mirror of
https://github.com/ente-io/ente.git
synced 2025-06-08 01:44:40 +00:00
798 lines
27 KiB
TypeScript
798 lines
27 KiB
TypeScript
import type { AppName } from "@/base/app";
|
|
import type { Theme } from "@mui/material";
|
|
import { createTheme } from "@mui/material";
|
|
import type { Components } from "@mui/material/styles/components";
|
|
import type { TypographyOptions } from "@mui/material/styles/createTypography";
|
|
|
|
const getTheme = (appName: AppName): Theme => {
|
|
const colors = getColors(appName);
|
|
const cs = getColorSchemes(colors);
|
|
// Cast app should always be shown in dark.
|
|
const colorSchemes =
|
|
appName == "cast" ? { ...cs, light: cs.dark } : { ...cs };
|
|
return createTheme({
|
|
cssVariables: {
|
|
colorSchemeSelector: "class",
|
|
},
|
|
colorSchemes,
|
|
typography,
|
|
components,
|
|
shape: {
|
|
// Increase the default border radius multiplier from 4 to 8.
|
|
borderRadius: 8,
|
|
},
|
|
transitions: {
|
|
// Increase the default transition out duration from 195 to 300.
|
|
duration: { leavingScreen: 300 },
|
|
},
|
|
});
|
|
};
|
|
|
|
/**
|
|
* [Note: Colors]
|
|
*
|
|
* The word "color" in MUI stands for different things. In particular, the color
|
|
* prop for (e.g.) a Button is not the same as the color passed in the sx prop.
|
|
*
|
|
* There are three layers (only the first is necessary, rest are semantic):
|
|
*
|
|
* 1. Consider some color, say a shade of red. This will be represented by its
|
|
* exact CSS color value, say "#ee0000".
|
|
*
|
|
* 2. These can be groups of color values that have roughly the same hue, but
|
|
* different levels of saturation. Such hue groups are arranged together into
|
|
* a "Colors" exported by "@/mui/material":
|
|
*
|
|
* export interface Color {
|
|
* 50: string;
|
|
* 100: string;
|
|
* ...
|
|
* 800: string;
|
|
* 900: string;
|
|
* A100: string;
|
|
* ...
|
|
* A700: string;
|
|
* }
|
|
*
|
|
* 3. Finally, there are "PaletteColors" (the naming of props, and
|
|
* documentation within MUI (as of v6), omits the palette qualifier).
|
|
*
|
|
* export interface PaletteColor {
|
|
* light: string;
|
|
* main: string;
|
|
* dark: string;
|
|
* contrastText: string;
|
|
* }
|
|
*
|
|
* The PaletteColors are what we use in the MUI component props (e.g. Button).
|
|
* The PaletteColors are defined by providing color values for the four "tokens"
|
|
* that make them up, either directly ("#aa000") or via Colors ("red[500]").
|
|
*
|
|
* Within the sx prop we need to specify a color value, which can come from the
|
|
* palette. The "palette", as defined by the palette property we provide when
|
|
* creating the theme, can consist of arbitrary (and nestable) key value pairs.
|
|
*
|
|
* Within sx prop, the "color" and "backgroundColor" props can refer to paths
|
|
* inside this palette object. That is,
|
|
*
|
|
* sx={{ color: "foo.bar" }}
|
|
*
|
|
* resolves to theme.vars.palette.foo.bar.
|
|
*
|
|
* [Note: Color names]
|
|
*
|
|
* When defining color names, there is some attempt at trying to use MUI v6,
|
|
* which uses MD (Material Design) v2, nomenclature when feasible (just to keep
|
|
* the number of concepts low), but as such, our color names should not be
|
|
* thought of as following Material Design, and should be treated as arbitrary
|
|
* tokens reflecting our own design system.
|
|
*
|
|
* Some callouts:
|
|
*
|
|
* - Our "primary" and "secondary" are neutral grays instead of the two-tone
|
|
* primary and secondary in MD. Our "accent" is corresponds to the MD primary.
|
|
*
|
|
* - Our "critical" is similar to and the alternative for the MD error (which is
|
|
* not used).
|
|
*
|
|
* - Two of the other default MD PaletteColors - warning, success - are used
|
|
* rarely, while info is not used at all.
|
|
*
|
|
* [Note: Theme and palette custom variables]
|
|
*
|
|
* Custom variables can be added to both the top level theme object, and to the
|
|
* palette object within the theme. One would imagine that within the palette
|
|
* there would only be colors that follow PaletteColor, but that's not something
|
|
* MUI itself follows.
|
|
*
|
|
* So there is no particular reason to place custom color related variables in
|
|
* theme vs in the palette. As a convention:
|
|
*
|
|
* - Custom colors (even if they're not PaletteColors) go within the palette.
|
|
*
|
|
* - Non-color tokens that depend on the color scheme (e.g. box shadows) also go
|
|
* within the palette so that they can be made color scheme specific.
|
|
*
|
|
* - All other custom variables remain within the top level theme.
|
|
*/
|
|
const getColors = (appName: AppName) => ({
|
|
..._colors,
|
|
...{
|
|
accent: appName == "auth" ? _colors.accentAuth : _colors.accentPhotos,
|
|
},
|
|
});
|
|
|
|
/**
|
|
* The color values.
|
|
*
|
|
* Use this arbitrarily shaped object to define the palette. This avoid
|
|
* duplication across color schemes, and also helps see if there are any
|
|
* reusable colors.
|
|
*/
|
|
const _colors = {
|
|
accentPhotos: {
|
|
dark: "#00b33c",
|
|
main: "#1db954",
|
|
light: "#01de4d",
|
|
},
|
|
accentAuth: {
|
|
dark: "#8e0fcb",
|
|
main: "#9610d6",
|
|
light: "#8e2de2",
|
|
},
|
|
fixed: {
|
|
white: "#fff",
|
|
black: "#000",
|
|
success: "#1db954",
|
|
golden: "#ffc107",
|
|
danger: {
|
|
dark: "#f53434",
|
|
main: "#ea3f3f",
|
|
light: "#ff6565",
|
|
},
|
|
switchOn: "#2eca45",
|
|
},
|
|
light: {
|
|
// Keep these solid.
|
|
background: {
|
|
default: "#fff",
|
|
paper: "#fff",
|
|
paper2: "#fbfbfb",
|
|
searchInput: "#f3f3f3",
|
|
},
|
|
backdrop: {
|
|
base: "rgba(255 255 255 / 0.92)",
|
|
muted: "rgba(255 255 255 / 0.75)",
|
|
faint: "rgba(255 255 255 / 0.30)",
|
|
},
|
|
text: {
|
|
base: "#000",
|
|
muted: "rgba(0 0 0 / 0.60)",
|
|
faint: "rgba(0 0 0 / 0.50)",
|
|
},
|
|
fill: {
|
|
base: "#000",
|
|
muted: "rgba(0 0 0 / 0.12)",
|
|
faint: "rgba(0 0 0 / 0.04)",
|
|
faintHover: "rgba(0 0 0 / 0.08)",
|
|
fainter: "rgba(0 0 0 / 0.02)",
|
|
},
|
|
// MUI (as of v6.4) doesn't like it if we specify a non-solid color for
|
|
// primary.main or secondary.main, or don't specify it using the #nnnnnn
|
|
// notation; it seems to mess with the derivation of the color channels.
|
|
secondary: {
|
|
main: "#f5f5f5",
|
|
hover: "#e9e9e9",
|
|
},
|
|
stroke: {
|
|
base: "#000",
|
|
muted: "rgba(0 0 0 / 0.24)",
|
|
faint: "rgba(0 0 0 / 0.12)",
|
|
fainter: "rgba(0 0 0 / 0.06)",
|
|
},
|
|
boxShadow: {
|
|
paper: "0px 0px 10px rgba(0 0 0 / 0.25)",
|
|
menu: "0px 0px 6px rgba(0 0 0 / 0.16), 0px 3px 6px rgba(0 0 0 / 0.12)",
|
|
button: "0px 4px 4px rgba(0 0 0 / 0.25)",
|
|
},
|
|
},
|
|
dark: {
|
|
background: {
|
|
default: "#000",
|
|
paper: "#1b1b1b",
|
|
paper2: "#252525",
|
|
searchInput: "#1b1b1b",
|
|
},
|
|
backdrop: {
|
|
base: "rgba(0 0 0 / 0.90)",
|
|
muted: "rgba(0 0 0 / 0.65)",
|
|
faint: "rgba(0 0 0 / 0.20)",
|
|
},
|
|
text: {
|
|
base: "#fff",
|
|
muted: "rgba(255 255 255 / 0.70)",
|
|
faint: "rgba(255 255 255 / 0.50)",
|
|
},
|
|
fill: {
|
|
base: "#fff",
|
|
muted: "rgba(255 255 255 / 0.16)",
|
|
faint: "rgba(255 255 255 / 0.12)",
|
|
faintHover: "rgba(255 255 255 / 0.16)",
|
|
fainter: "rgba(255 255 255 / 0.05)",
|
|
},
|
|
secondary: {
|
|
main: "#2b2b2b",
|
|
hover: "#373737",
|
|
},
|
|
stroke: {
|
|
base: "#fff",
|
|
muted: "rgba(255 255 255 / 0.24)",
|
|
faint: "rgba(255 255 255 / 0.16)",
|
|
fainter: "rgba(255 255 255 / 0.12)",
|
|
},
|
|
boxShadow: {
|
|
paper: "0px 2px 12px rgba(0 0 0 / 0.75)",
|
|
menu: "0px 0px 6px rgba(0 0 0 / 0.50), 0px 3px 6px rgba(0 0 0 / 0.25)",
|
|
button: "0px 4px 4px rgba(0 0 0 / 0.75)",
|
|
},
|
|
},
|
|
};
|
|
|
|
const getColorSchemes = (colors: ReturnType<typeof getColors>) => ({
|
|
light: {
|
|
palette: {
|
|
background: {
|
|
...colors.light.background,
|
|
elevatedPaper: colors.light.background.paper2,
|
|
},
|
|
backdrop: colors.light.backdrop,
|
|
primary: {
|
|
main: colors.fixed.black,
|
|
contrastText: colors.fixed.white,
|
|
},
|
|
secondary: {
|
|
main: colors.light.secondary.main,
|
|
dark: colors.light.secondary.hover,
|
|
contrastText: colors.light.text.base,
|
|
},
|
|
success: { main: colors.fixed.success },
|
|
warning: { main: colors.fixed.golden },
|
|
accent: {
|
|
main: colors.accent.main,
|
|
dark: colors.accent.dark,
|
|
light: colors.accent.light,
|
|
contrastText: colors.fixed.white,
|
|
},
|
|
critical: {
|
|
main: colors.fixed.danger.main,
|
|
dark: colors.fixed.danger.dark,
|
|
light: colors.fixed.danger.light,
|
|
contrastText: colors.fixed.white,
|
|
},
|
|
text: {
|
|
// Alias the tokens used by MUI to the ones that we use. This way,
|
|
// we don't need to change the default ("primary"), or update the
|
|
// MUI internal styling that refers to these tokens.
|
|
//
|
|
// Our own code should not use these.
|
|
primary: colors.light.text.base,
|
|
secondary: colors.light.text.muted,
|
|
disabled: colors.light.text.faint,
|
|
// Our color tokens.
|
|
base: colors.light.text.base,
|
|
muted: colors.light.text.muted,
|
|
faint: colors.light.text.faint,
|
|
},
|
|
fill: colors.light.fill,
|
|
stroke: colors.light.stroke,
|
|
divider: colors.light.stroke.faint,
|
|
fixed: colors.fixed,
|
|
boxShadow: colors.light.boxShadow,
|
|
// Override some MUI defaults for styling action elements like
|
|
// buttons and menu items.
|
|
//
|
|
// Nb: There are more where these came from, currently those don't
|
|
// affect us, but in the future they might.
|
|
//
|
|
// https://github.com/mui/material-ui/blob/v6.4.0/packages/mui-material/src/styles/createPalette.js#L68
|
|
action: {
|
|
// The color of an active action like an icon button.
|
|
active: colors.light.stroke.base,
|
|
// The color of an hovered action.
|
|
hover: colors.light.fill.faintHover,
|
|
// For an icon button, the hover background color is derived
|
|
// from the active color above and this opacity. Use a value
|
|
// that results in the same result as faintHover.
|
|
hoverOpacity: 0.08,
|
|
// The color of a disabled action.
|
|
disabled: colors.light.text.faint,
|
|
// The background color of a disabled action.
|
|
disabledBackground: colors.light.fill.faint,
|
|
},
|
|
// Override some internal MUI defaults that impact the components
|
|
// which we use.
|
|
//
|
|
// https://github.com/mui/material-ui/blob/v6.4.0/packages/mui-material/src/styles/createThemeWithVars.js#L271
|
|
FilledInput: {
|
|
bg: colors.light.fill.faint,
|
|
hoverBg: colors.light.fill.faintHover,
|
|
// While we don't specifically have disabled inputs, TextInputs
|
|
// do get disabled when the form is submitting, and this value
|
|
// comes into play then.
|
|
disabledBg: colors.light.fill.fainter,
|
|
},
|
|
},
|
|
},
|
|
// -- See the light mode section for comments
|
|
dark: {
|
|
palette: {
|
|
background: {
|
|
...colors.dark.background,
|
|
elevatedPaper: colors.dark.background.paper,
|
|
},
|
|
backdrop: colors.dark.backdrop,
|
|
primary: {
|
|
main: colors.fixed.white,
|
|
contrastText: colors.fixed.black,
|
|
},
|
|
secondary: {
|
|
main: colors.dark.secondary.main,
|
|
dark: colors.dark.secondary.hover,
|
|
contrastText: colors.dark.text.base,
|
|
},
|
|
success: { main: colors.fixed.success },
|
|
warning: { main: colors.fixed.golden },
|
|
accent: {
|
|
main: colors.accent.main,
|
|
dark: colors.accent.dark,
|
|
light: colors.accent.light,
|
|
contrastText: colors.fixed.white,
|
|
},
|
|
critical: {
|
|
main: colors.fixed.danger.main,
|
|
dark: colors.fixed.danger.dark,
|
|
light: colors.fixed.danger.light,
|
|
contrastText: colors.fixed.white,
|
|
},
|
|
text: {
|
|
primary: colors.dark.text.base,
|
|
secondary: colors.dark.text.muted,
|
|
disabled: colors.dark.text.faint,
|
|
base: colors.dark.text.base,
|
|
muted: colors.dark.text.muted,
|
|
faint: colors.dark.text.faint,
|
|
},
|
|
fill: colors.dark.fill,
|
|
stroke: colors.dark.stroke,
|
|
divider: colors.dark.stroke.faint,
|
|
fixed: colors.fixed,
|
|
boxShadow: colors.dark.boxShadow,
|
|
// -- See the light mode section for comments
|
|
action: {
|
|
active: colors.dark.stroke.base,
|
|
hover: colors.dark.fill.faintHover,
|
|
hoverOpacity: 0.16,
|
|
disabled: colors.dark.text.faint,
|
|
disabledBackground: colors.dark.fill.faint,
|
|
},
|
|
FilledInput: {
|
|
bg: colors.dark.fill.faint,
|
|
hoverBg: colors.dark.fill.faintHover,
|
|
disabledBg: colors.dark.fill.fainter,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
/**
|
|
* [Note: Font weights]
|
|
*
|
|
* We only use three font weights:
|
|
*
|
|
* - 500 (sx "regular")
|
|
* - 600 (sx "medium")
|
|
* - 700 (sx "bold", CSS "bold")
|
|
*
|
|
* While the sx prop allows us to use keywords "regular", "medium" and "bold",
|
|
* which we do elsewhere in the code, within this file those keywords cannot be
|
|
* used in all contexts because they instead map to the CSS keywords. To avoid
|
|
* any confusion, within this file we only use the numeric values.
|
|
*
|
|
* ---
|
|
*
|
|
* MUI (as of v6) uses the following font weights by default:
|
|
*
|
|
* - fontWeightLight 300
|
|
* - fontWeightRegular 400
|
|
* - fontWeightMedium 500
|
|
* - fontWeightBold 700
|
|
*
|
|
* The browser default (CSS keyword "normal"), is also 400.
|
|
*
|
|
* However for Inter, the font that we use, 400 is too light, and to improve
|
|
* legibility we change fontWeightRegular to 500.
|
|
*
|
|
* Correspondingly, we shift fontWeightMedium to 600. fontWeightBold then ends
|
|
* up mapping back to 700, which also nicely coincides with the CSS keyword
|
|
* "bold".
|
|
*
|
|
* MUI uses fontWeightLight only as the default font weight for the h1 and h2
|
|
* variants, but we override their font weight in our theme. Thus we don't need
|
|
* to bother with the light variant (though for consistency of specifying every
|
|
* value, we alias it the same weight as regular, 500).
|
|
*/
|
|
const typography: TypographyOptions = {
|
|
fontFamily: "Inter Variable, sans-serif",
|
|
fontWeightLight: 500,
|
|
fontWeightRegular: 500 /* CSS baseline reset sets this as the default */,
|
|
fontWeightMedium: 600,
|
|
fontWeightBold: 700,
|
|
h1: {
|
|
fontSize: "48px",
|
|
lineHeight: "58px",
|
|
fontWeight: 600 /* Medium */,
|
|
},
|
|
h2: {
|
|
fontSize: "32px",
|
|
lineHeight: "39px",
|
|
fontWeight: 500 /* Reset to regular to override MUI's default theme */,
|
|
},
|
|
h3: {
|
|
fontSize: "24px",
|
|
lineHeight: "29px",
|
|
fontWeight: 600 /* Medium */,
|
|
},
|
|
h4: {
|
|
fontSize: "22px",
|
|
lineHeight: "27px",
|
|
fontWeight: 500 /* Reset to regular to override MUI's default theme */,
|
|
},
|
|
h5: {
|
|
fontSize: "20px",
|
|
lineHeight: "25px",
|
|
fontWeight: 600 /* Medium */,
|
|
},
|
|
// h6 is the default variant used by MUI's DialogTitle.
|
|
h6: {
|
|
// The font size and line height below is the same as large.
|
|
fontSize: "18px",
|
|
lineHeight: "22px",
|
|
fontWeight: 600 /* Medium */,
|
|
},
|
|
body: {
|
|
fontSize: "16px",
|
|
lineHeight: "20px",
|
|
},
|
|
small: {
|
|
fontSize: "14px",
|
|
lineHeight: "17px",
|
|
},
|
|
mini: {
|
|
fontSize: "12px",
|
|
lineHeight: "15px",
|
|
},
|
|
tiny: {
|
|
fontSize: "10px",
|
|
lineHeight: "12px",
|
|
},
|
|
};
|
|
|
|
/**
|
|
* > [!NOTE]
|
|
* >
|
|
* > The theme isn't tree-shakeable, prefer creating new components for heavy
|
|
* > customization.
|
|
* >
|
|
* > https://mui.com/material-ui/customization/theme-components/
|
|
*/
|
|
const components: Components = {
|
|
MuiCssBaseline: {
|
|
styleOverrides: {
|
|
body: {
|
|
// MUI has different letter spacing for each variant, but those
|
|
// are values arrived at for the default Material font, and
|
|
// don't work for the font that we're using.
|
|
//
|
|
// So we reset the letter spacing for _all_ variants to a
|
|
// reasonable value that works for our font.
|
|
letterSpacing: "-0.011em",
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiTypography: {
|
|
defaultProps: {
|
|
// MUI has body1 as the default variant for Typography, but our
|
|
// variant scheme is different, instead of body1/2, we have
|
|
// large/body/small etc. So reset the default to our equivalent of
|
|
// body1, which is "body".
|
|
variant: "body",
|
|
// Map all our custom variants to <p>.
|
|
variantMapping: {
|
|
body: "p",
|
|
small: "p",
|
|
mini: "p",
|
|
tiny: "p",
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiModal: {
|
|
styleOverrides: {
|
|
root: {
|
|
// A workaround to prevent stuck modals from blocking clicks.
|
|
// https://github.com/mui/material-ui/issues/32286#issuecomment-1287951109
|
|
'&:has(> div[style*="opacity: 0"])': {
|
|
pointerEvents: "none",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiDrawer: {
|
|
styleOverrides: {
|
|
root: {
|
|
".MuiBackdrop-root": {
|
|
backgroundColor: "var(--mui-palette-backdrop-muted)",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiDialog: {
|
|
defaultProps: {
|
|
// [Note: Overzealous Chrome? Complicated ARIA?]
|
|
//
|
|
// This is required to prevent console errors about aria-hiding a
|
|
// focused button when the dialog is closed.
|
|
//
|
|
// https://github.com/mui/material-ui/issues/43106#issuecomment-2314809028
|
|
closeAfterTransition: false,
|
|
},
|
|
styleOverrides: {
|
|
root: {
|
|
".MuiBackdrop-root": {
|
|
backgroundColor: "var(--mui-palette-backdrop-muted)",
|
|
},
|
|
// Reset the MUI default paddings to 16px everywhere.
|
|
//
|
|
// This is not a great choice either, usually most dialogs, for
|
|
// one reason or the other, will need to customize this padding
|
|
// anyway. But not resetting it to 16px leaves it at the MUI
|
|
// defaults, which just doesn't work well with our designs.
|
|
"& .MuiDialogTitle-root": {
|
|
// MUI default is '16px 24px'.
|
|
padding: "16px",
|
|
},
|
|
"& .MuiDialogContent-root": {
|
|
// MUI default is '20px 24px'.
|
|
padding: "16px",
|
|
// If the contents of the dialog's contents exceed the
|
|
// available height, show a scrollbar just for the contents
|
|
// instead of the entire dialog.
|
|
overflowY: "auto",
|
|
},
|
|
"& .MuiDialogActions-root": {
|
|
// MUI default is way off for us since they cluster the
|
|
// buttons to the right, while our designs usually want the
|
|
// buttons to align with the heading / content.
|
|
padding: "16px",
|
|
},
|
|
".MuiDialogTitle-root + .MuiDialogContent-root": {
|
|
// MUI resets this to 0 when the content doesn't use
|
|
// dividers (none of ours do). I feel that is a better
|
|
// default, since unlike margins, padding doesn't collapse,
|
|
// but changing this now would break existing layouts.
|
|
paddingTop: "16px",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiPaper: {
|
|
styleOverrides: {
|
|
root: {
|
|
// MUI applies a semi-transparent background image for elevation
|
|
// in dark mode. Remove it to match background for our designs.
|
|
backgroundImage: "none",
|
|
// Use our paper shadow.
|
|
boxShadow: "var(--mui-palette-boxShadow-paper)",
|
|
},
|
|
},
|
|
},
|
|
|
|
// The default link "color" prop is "primary", which maps to "fill.base"
|
|
// (and equivalently, to "text.base"). In our current designs, the <Link>
|
|
// MUI component is only used in places where the surrounding text uses
|
|
// "text.muted", so this default already provides it a highlight compared to
|
|
// the text it in embedded in.
|
|
//
|
|
// We additionally disable the underline, and add a hover indication by
|
|
// switching its color to the main accent.
|
|
MuiLink: {
|
|
defaultProps: {
|
|
underline: "none",
|
|
},
|
|
styleOverrides: {
|
|
root: {
|
|
"&:hover": {
|
|
color: "var(--mui-palette-accent-main)",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiButton: {
|
|
defaultProps: {
|
|
// Change the default button variant from "text" to "contained".
|
|
variant: "contained",
|
|
// Disable shadows.
|
|
disableElevation: true,
|
|
},
|
|
styleOverrides: {
|
|
// We don't use the size prop for the MUI button, or rather it
|
|
// cannot be used, since we have fixed the paddings and font sizes
|
|
// unconditionally here (which is all that the size prop changes).
|
|
root: {
|
|
padding: "12px 16px",
|
|
borderRadius: "4px",
|
|
textTransform: "none",
|
|
// Body, but medium.
|
|
fontSize: typography.body?.fontSize,
|
|
lineHeight: typography.body?.lineHeight,
|
|
fontWeight: 600,
|
|
},
|
|
startIcon: {
|
|
marginRight: "12px",
|
|
"&& >svg": {
|
|
fontSize: "20px",
|
|
},
|
|
},
|
|
endIcon: {
|
|
marginLeft: "12px",
|
|
"&& >svg": {
|
|
fontSize: "20px",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiInputBase: {
|
|
styleOverrides: {
|
|
formControl: {
|
|
// Give a symmetric border to the input field, by default the
|
|
// border radius is only applied to the top for the "filled"
|
|
// variant of input used inside TextFields.
|
|
borderRadius: "8px",
|
|
// Clip the bottom border so that there is no gap between the
|
|
// filled area and the (full width) border.
|
|
overflow: "hidden",
|
|
// Hide the bottom border that always appears for the "filled"
|
|
// variant of input used inside TextFields.
|
|
"::before": {
|
|
borderBottom: "none !important",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiTextField: {
|
|
defaultProps: {
|
|
// The MUI default variant is "outlined", override it to use the
|
|
// "filled" one by default.
|
|
variant: "filled",
|
|
// Reduce the vertical margins that MUI adds to the TextField.
|
|
//
|
|
// Note that this causes things to be too tight when the helper text
|
|
// is shown, so this is not recommended for new code that we write.
|
|
margin: "dense",
|
|
},
|
|
styleOverrides: {
|
|
root: {
|
|
"& .MuiInputAdornment-root": {
|
|
marginRight: "8px",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiCheckbox: {
|
|
defaultProps: {
|
|
// Disable the ripple effect for all checkboxes.
|
|
disableRipple: true,
|
|
},
|
|
styleOverrides: {
|
|
// Since we've disabled the ripple, add other affordances to it (a
|
|
// background and outline) to clearly indicate whenever it gains
|
|
// keyboard focus.
|
|
root: {
|
|
"&.Mui-focusVisible": {
|
|
backgroundColor: "var(--mui-palette-fill-faint)",
|
|
outline: "1px solid var(--mui-palette-stroke-faint)",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiSvgIcon: {
|
|
styleOverrides: {
|
|
root: {
|
|
variants: [
|
|
{
|
|
props: { color: "primary" },
|
|
style: { color: "var(--mui-palette-stroke-base)" },
|
|
},
|
|
{
|
|
props: { color: "secondary" },
|
|
style: { color: "var(--mui-palette-stroke-muted)" },
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiIconButton: {
|
|
styleOverrides: {
|
|
root: {
|
|
padding: "12px",
|
|
variants: [
|
|
{
|
|
props: { color: "primary" },
|
|
style: { color: "var(--mui-palette-stroke-base)" },
|
|
},
|
|
{
|
|
props: { color: "secondary" },
|
|
style: { color: "var(--mui-palette-stroke-muted)" },
|
|
},
|
|
{
|
|
props: { color: "disabled" },
|
|
style: { color: "var(--mui-palette-stroke-faint)" },
|
|
},
|
|
],
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiMenu: {
|
|
styleOverrides: {
|
|
root: {
|
|
".MuiMenu-paper": {
|
|
boxShadow: "var(--mui-palette-boxShadow-menu)",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
MuiSnackbar: {
|
|
styleOverrides: {
|
|
root: {
|
|
// Set a default border radius for all snackbar's (e.g.
|
|
// notification popups).
|
|
borderRadius: "8px",
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
// Exports ---
|
|
|
|
/**
|
|
* The MUI {@link Theme} to use for the photos app.
|
|
*
|
|
* This is also the "default" theme, in that it is used for the accounts app
|
|
* which serves both photos and auth.
|
|
*/
|
|
export const photosTheme = getTheme("photos");
|
|
|
|
/**
|
|
* The MUI {@link Theme} to use for the auth app.
|
|
*/
|
|
export const authTheme = getTheme("auth");
|
|
|
|
/**
|
|
* The MUI {@link Theme} to use for the cast app.
|
|
*
|
|
* This is the same as the dark theme for the photos app.
|
|
*/
|
|
export const castTheme = getTheme("cast");
|