Implemented dark mode
This commit is contained in:
@@ -19,6 +19,17 @@ import { render } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
describe('App', () => {
|
||||
beforeAll(() => {
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
value: jest.fn(() => {
|
||||
return {
|
||||
matches: true,
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
};
|
||||
}),
|
||||
});
|
||||
});
|
||||
it('should render', () => {
|
||||
const rendered = render(<App />);
|
||||
expect(rendered.baseElement).toBeInTheDocument();
|
||||
|
||||
+40
-10
@@ -15,13 +15,18 @@
|
||||
*/
|
||||
|
||||
import { CssBaseline, makeStyles, ThemeProvider } from '@material-ui/core';
|
||||
import { BackstageTheme, createApp } from '@backstage/core';
|
||||
import {
|
||||
BackstageThemeLight,
|
||||
BackstageThemeDark,
|
||||
createApp,
|
||||
} from '@backstage/core';
|
||||
import React, { FC } from 'react';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import Root from './components/Root';
|
||||
import ErrorDisplay from './components/ErrorDisplay';
|
||||
import * as plugins from './plugins';
|
||||
import apis, { errorDialogForwarder } from './apis';
|
||||
import { ThemeContextType, ThemeContext, useThemeType } from './ThemeContext';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
'@global': {
|
||||
@@ -48,17 +53,42 @@ const AppComponent = app.build();
|
||||
|
||||
const App: FC<{}> = () => {
|
||||
useStyles();
|
||||
const [theme, toggleTheme] = useThemeType(
|
||||
localStorage.getItem('theme') || 'auto',
|
||||
);
|
||||
|
||||
let backstageTheme = BackstageThemeLight;
|
||||
switch (theme) {
|
||||
case 'light':
|
||||
backstageTheme = BackstageThemeLight;
|
||||
break;
|
||||
case 'dark':
|
||||
backstageTheme = BackstageThemeDark;
|
||||
break;
|
||||
default:
|
||||
backstageTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? BackstageThemeDark
|
||||
: BackstageThemeLight;
|
||||
break;
|
||||
}
|
||||
|
||||
const themeContext: ThemeContextType = {
|
||||
theme,
|
||||
toggleTheme,
|
||||
};
|
||||
return (
|
||||
<CssBaseline>
|
||||
<ThemeProvider theme={BackstageTheme}>
|
||||
<ErrorDisplay forwarder={errorDialogForwarder} />
|
||||
<Router>
|
||||
<Root>
|
||||
<AppComponent />
|
||||
</Root>
|
||||
</Router>
|
||||
<ThemeContext.Provider value={themeContext}>
|
||||
<ThemeProvider theme={backstageTheme}>
|
||||
<CssBaseline>
|
||||
<ErrorDisplay forwarder={errorDialogForwarder} />
|
||||
<Router>
|
||||
<Root>
|
||||
<AppComponent />
|
||||
</Root>
|
||||
</Router>
|
||||
</CssBaseline>
|
||||
</ThemeProvider>
|
||||
</CssBaseline>
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
export type ThemeContextType = {
|
||||
theme: string;
|
||||
toggleTheme: () => void;
|
||||
};
|
||||
export const ThemeContext = React.createContext<ThemeContextType>({
|
||||
theme: 'light',
|
||||
toggleTheme: () => {},
|
||||
});
|
||||
|
||||
export function useThemeType(themeId: string): [string, () => void] {
|
||||
const [theme, setTheme] = useState(themeId);
|
||||
useEffect(() => {
|
||||
const mql = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const darkListener = (event: MediaQueryListEvent) => {
|
||||
if (localStorage.getItem('theme') === 'auto') {
|
||||
if (event.matches) {
|
||||
setTheme('dark');
|
||||
} else {
|
||||
setTheme('light');
|
||||
}
|
||||
setTheme('auto');
|
||||
}
|
||||
};
|
||||
mql.addEventListener('change', darkListener);
|
||||
return () => {
|
||||
mql.removeEventListener('change', darkListener);
|
||||
};
|
||||
});
|
||||
function toggleTheme() {
|
||||
if (theme === 'light') {
|
||||
setTheme('dark');
|
||||
localStorage.setItem('theme', 'dark');
|
||||
} else if (theme === 'dark') {
|
||||
setTheme('auto');
|
||||
localStorage.setItem('theme', 'auto');
|
||||
setTheme('auto');
|
||||
} else {
|
||||
setTheme('light');
|
||||
localStorage.setItem('theme', 'light');
|
||||
}
|
||||
}
|
||||
return [theme, toggleTheme];
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
SidebarDivider,
|
||||
SidebarSpace,
|
||||
} from '@backstage/core';
|
||||
import ToggleThemeSidebarItem from './ToggleThemeSidebarItem';
|
||||
|
||||
const useSidebarLogoStyles = makeStyles({
|
||||
root: {
|
||||
@@ -81,6 +82,7 @@ const Root: FC<{}> = ({ children }) => (
|
||||
<SidebarItem icon={AccountCircle} to="/login" text="Login" />
|
||||
<SidebarDivider />
|
||||
<SidebarSpace />
|
||||
<ToggleThemeSidebarItem />
|
||||
</Sidebar>
|
||||
{children}
|
||||
</SidebarPage>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import { SidebarItem } from '@backstage/core';
|
||||
import { ThemeContext } from '../../ThemeContext';
|
||||
import WbSunnyIcon from '@material-ui/icons/WbSunny';
|
||||
import Brightness2Icon from '@material-ui/icons/Brightness2';
|
||||
import ToggleOnIcon from '@material-ui/icons/ToggleOn';
|
||||
const ToggleThemeSidebarItem: FC<{}> = () => {
|
||||
return (
|
||||
<ThemeContext.Consumer>
|
||||
{themeContext => {
|
||||
let text = 'Auto';
|
||||
let icon = ToggleOnIcon;
|
||||
switch (themeContext.theme) {
|
||||
case 'dark':
|
||||
text = 'Dark mode';
|
||||
icon = Brightness2Icon;
|
||||
break;
|
||||
case 'light':
|
||||
text = 'Light mode';
|
||||
icon = WbSunnyIcon;
|
||||
break;
|
||||
default:
|
||||
text = 'Auto';
|
||||
icon = ToggleOnIcon;
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarItem
|
||||
text={text}
|
||||
onClick={themeContext.toggleTheme}
|
||||
icon={icon}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</ThemeContext.Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
export default ToggleThemeSidebarItem;
|
||||
@@ -24,8 +24,10 @@ export { default as HeaderLabel } from './layout/HeaderLabel';
|
||||
export { default as InfoCard } from './layout/InfoCard';
|
||||
export { default as ErrorBoundary } from './layout/ErrorBoundary';
|
||||
export * from './layout/Sidebar';
|
||||
export { default as BackstageThemeLight } from './theme/BackstageThemeLight';
|
||||
export { default as BackstageTheme } from './theme/BackstageTheme';
|
||||
export { COLORS } from './theme/BackstageTheme';
|
||||
export { default as BackstageThemeDark } from './theme/BackstageThemeDark';
|
||||
export { default as HorizontalScrollGrid } from './components/HorizontalScrollGrid';
|
||||
export { default as ProgressCard } from './components/ProgressCard';
|
||||
export { default as CircleProgress } from './components/CircleProgress';
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createMuiTheme } from '@material-ui/core';
|
||||
import { darken, lighten } from '@material-ui/core/styles/colorManipulator';
|
||||
import { blue, yellow } from '@material-ui/core/colors';
|
||||
|
||||
export const COLORS = {
|
||||
PAGE_BACKGROUND: '#282828',
|
||||
EFAULT_PAGE_THEME_COLOR: '#232323',
|
||||
DEFAULT_PAGE_THEME_COLOR: '#7C3699',
|
||||
DEFAULT_PAGE_THEME_LIGHT_COLOR: '#ECDBF2',
|
||||
ERROR_BACKGROUND_COLOR: '#FFEBEE',
|
||||
ERROR_TEXT_COLOR: '#CA001B',
|
||||
INFO_TEXT_COLOR: '#004e8a',
|
||||
LINK_TEXT: '#0A6EBE',
|
||||
LINK_TEXT_HOVER: '#2196F3',
|
||||
NAMED: {
|
||||
WHITE: '#FEFEFE',
|
||||
},
|
||||
STATUS: {
|
||||
OK: '#1db855',
|
||||
WARNING: '#f49b20',
|
||||
ERROR: '#CA001B',
|
||||
},
|
||||
};
|
||||
|
||||
const extendedThemeConfig = {
|
||||
props: {
|
||||
MuiGrid: {
|
||||
spacing: 2,
|
||||
},
|
||||
MuiSwitch: {
|
||||
color: 'primary',
|
||||
},
|
||||
},
|
||||
palette: {
|
||||
background: {
|
||||
default: COLORS.PAGE_BACKGROUND,
|
||||
informational: '#60a3cb',
|
||||
},
|
||||
color: {
|
||||
default: '#fff',
|
||||
},
|
||||
type: 'dark',
|
||||
status: {
|
||||
ok: COLORS.STATUS.OK,
|
||||
warning: COLORS.STATUS.WARNING,
|
||||
error: COLORS.STATUS.ERROR,
|
||||
running: '#BEBEBE',
|
||||
pending: '#5BC0DE',
|
||||
background: COLORS.NAMED.WHITE,
|
||||
},
|
||||
bursts: {
|
||||
fontColor: COLORS.NAMED.WHITE,
|
||||
slackChannelText: '#ddd',
|
||||
backgroundColor: {
|
||||
default: COLORS.DEFAULT_PAGE_THEME_COLOR,
|
||||
},
|
||||
},
|
||||
primary: {
|
||||
main: blue[500],
|
||||
},
|
||||
border: '#E6E6E6',
|
||||
textVerySubtle: '#DDD',
|
||||
textSubtle: '#6E6E6E',
|
||||
highlight: '#FFFBCC',
|
||||
errorBackground: COLORS.ERROR_BACKGROUND_COLOR,
|
||||
warningBackground: '#F59B23',
|
||||
infoBackground: '#ebf5ff',
|
||||
errorText: COLORS.ERROR_TEXT_COLOR,
|
||||
infoText: COLORS.INFO_TEXT_COLOR,
|
||||
warningText: COLORS.NAMED.WHITE,
|
||||
linkHover: COLORS.LINK_TEXT_HOVER,
|
||||
link: COLORS.LINK_TEXT,
|
||||
gold: yellow.A700,
|
||||
},
|
||||
navigation: {
|
||||
width: 220,
|
||||
background: '#333333',
|
||||
},
|
||||
typography: {
|
||||
fontFamily: '"Helvetica Neue", Helvetica, Roboto, Arial, sans-serif',
|
||||
h5: {
|
||||
fontWeight: 700,
|
||||
},
|
||||
h4: {
|
||||
fontWeight: 700,
|
||||
fontSize: 28,
|
||||
marginBottom: 6,
|
||||
},
|
||||
h3: {
|
||||
fontSize: 32,
|
||||
fontWeight: 700,
|
||||
marginBottom: 6,
|
||||
},
|
||||
h2: {
|
||||
fontSize: 40,
|
||||
fontWeight: 700,
|
||||
marginBottom: 8,
|
||||
},
|
||||
h1: {
|
||||
fontSize: 54,
|
||||
fontWeight: 700,
|
||||
marginBottom: 10,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const createOverrides = theme => {
|
||||
return {
|
||||
overrides: {
|
||||
MuiCSSBaseline: {
|
||||
'@global': {
|
||||
body: {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
color: theme.palette.color.default,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableRow: {
|
||||
// Alternating row backgrounds
|
||||
root: {
|
||||
'&:nth-of-type(odd)': {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
},
|
||||
},
|
||||
// Use pointer for hoverable rows
|
||||
hover: {
|
||||
'&:hover': {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
},
|
||||
// Alternating head backgrounds
|
||||
head: {
|
||||
'&:nth-of-type(odd)': {
|
||||
backgroundColor: COLORS.NAMED.WHITE,
|
||||
},
|
||||
},
|
||||
},
|
||||
// Tables are more dense than default mui tables
|
||||
MuiTableCell: {
|
||||
root: {
|
||||
wordBreak: 'break-word',
|
||||
overflow: 'hidden',
|
||||
verticalAlign: 'middle',
|
||||
lineHeight: '1',
|
||||
margin: 0,
|
||||
padding: '8px',
|
||||
borderBottom: 0,
|
||||
},
|
||||
head: {
|
||||
wordBreak: 'break-word',
|
||||
overflow: 'hidden',
|
||||
color: 'rgb(179, 179, 179)',
|
||||
fontWeight: 'normal',
|
||||
lineHeight: '1',
|
||||
},
|
||||
},
|
||||
MuiTabs: {
|
||||
// Tabs are smaller than default mui tab rows
|
||||
root: {
|
||||
minHeight: 24,
|
||||
},
|
||||
},
|
||||
MuiTab: {
|
||||
// Tabs are smaller and have a hover background
|
||||
root: {
|
||||
color: theme.palette.link,
|
||||
minHeight: 24,
|
||||
textTransform: 'initial',
|
||||
'&:hover': {
|
||||
color: darken(theme.palette.link, 0.3),
|
||||
background: lighten(theme.palette.link, 0.95),
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
minWidth: 120,
|
||||
fontSize: theme.typography.pxToRem(14),
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
textColorPrimary: {
|
||||
color: theme.palette.link,
|
||||
},
|
||||
},
|
||||
MuiTableSortLabel: {
|
||||
// No color change on hover, just rely on the arrow showing up instead.
|
||||
root: {
|
||||
color: 'inherit',
|
||||
'&:hover': {
|
||||
color: 'inherit',
|
||||
},
|
||||
'&:focus': {
|
||||
color: 'inherit',
|
||||
},
|
||||
},
|
||||
// Bold font for highlighting selected column
|
||||
active: {
|
||||
fontWeight: 'bold',
|
||||
color: 'inherit',
|
||||
},
|
||||
},
|
||||
MuiListItemText: {
|
||||
dense: {
|
||||
// Default dense list items to adding ellipsis for really long str...
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
},
|
||||
},
|
||||
MuiButton: {
|
||||
text: {
|
||||
// Text buttons have less padding by default, but we want to keep the original padding
|
||||
padding: null,
|
||||
},
|
||||
},
|
||||
MuiChip: {
|
||||
root: {
|
||||
// By default there's no margin, but it's usually wanted, so we add some trailing margin
|
||||
marginRight: theme.spacing(1),
|
||||
marginBottom: theme.spacing(1),
|
||||
},
|
||||
},
|
||||
MuiCardHeader: {
|
||||
root: {
|
||||
// Reduce padding between header and content
|
||||
paddingBottom: 0,
|
||||
},
|
||||
},
|
||||
MuiCardActions: {
|
||||
root: {
|
||||
// We default to putting the card actions at the end
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const extendedTheme = createMuiTheme(extendedThemeConfig);
|
||||
|
||||
// V1 theming
|
||||
// https://material-ui-next.com/customization/themes/
|
||||
// For CSS it is advised to use JSS, see https://material-ui-next.com/customization/css-in-js/
|
||||
const BackstageThemeDark = {
|
||||
...extendedTheme,
|
||||
...createOverrides(extendedTheme),
|
||||
};
|
||||
|
||||
// Temporary workaround for files incorrectly importing the theme directly
|
||||
export const V1 = BackstageThemeDark;
|
||||
export default BackstageThemeDark;
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createMuiTheme } from '@material-ui/core';
|
||||
import { darken, lighten } from '@material-ui/core/styles/colorManipulator';
|
||||
import { blue, yellow } from '@material-ui/core/colors';
|
||||
|
||||
export const COLORS = {
|
||||
PAGE_BACKGROUND: '#F8F8F8',
|
||||
DEFAULT_PAGE_THEME_COLOR: '#7C3699',
|
||||
DEFAULT_PAGE_THEME_LIGHT_COLOR: '#ECDBF2',
|
||||
ERROR_BACKGROUND_COLOR: '#FFEBEE',
|
||||
ERROR_TEXT_COLOR: '#CA001B',
|
||||
INFO_TEXT_COLOR: '#004e8a',
|
||||
LINK_TEXT: '#0A6EBE',
|
||||
LINK_TEXT_HOVER: '#2196F3',
|
||||
NAMED: {
|
||||
WHITE: '#FEFEFE',
|
||||
},
|
||||
STATUS: {
|
||||
OK: '#1db855',
|
||||
WARNING: '#f49b20',
|
||||
ERROR: '#CA001B',
|
||||
},
|
||||
};
|
||||
|
||||
const extendedThemeConfig = {
|
||||
props: {
|
||||
MuiGrid: {
|
||||
spacing: 2,
|
||||
},
|
||||
MuiSwitch: {
|
||||
color: 'primary',
|
||||
},
|
||||
},
|
||||
palette: {
|
||||
background: {
|
||||
default: COLORS.PAGE_BACKGROUND,
|
||||
informational: '#60a3cb',
|
||||
},
|
||||
color: {
|
||||
default: '#000',
|
||||
},
|
||||
status: {
|
||||
ok: COLORS.STATUS.OK,
|
||||
warning: COLORS.STATUS.WARNING,
|
||||
error: COLORS.STATUS.ERROR,
|
||||
running: '#BEBEBE',
|
||||
pending: '#5BC0DE',
|
||||
background: COLORS.NAMED.WHITE,
|
||||
},
|
||||
bursts: {
|
||||
fontColor: COLORS.NAMED.WHITE,
|
||||
slackChannelText: '#ddd',
|
||||
backgroundColor: {
|
||||
default: COLORS.DEFAULT_PAGE_THEME_COLOR,
|
||||
},
|
||||
},
|
||||
primary: {
|
||||
main: blue[500],
|
||||
},
|
||||
border: '#E6E6E6',
|
||||
textVerySubtle: '#DDD',
|
||||
textSubtle: '#6E6E6E',
|
||||
highlight: '#FFFBCC',
|
||||
errorBackground: COLORS.ERROR_BACKGROUND_COLOR,
|
||||
warningBackground: '#F59B23',
|
||||
infoBackground: '#ebf5ff',
|
||||
errorText: COLORS.ERROR_TEXT_COLOR,
|
||||
infoText: COLORS.INFO_TEXT_COLOR,
|
||||
warningText: COLORS.NAMED.WHITE,
|
||||
linkHover: COLORS.LINK_TEXT_HOVER,
|
||||
link: COLORS.LINK_TEXT,
|
||||
gold: yellow.A700,
|
||||
},
|
||||
navigation: {
|
||||
width: 220,
|
||||
background: '#333333',
|
||||
},
|
||||
typography: {
|
||||
fontFamily: '"Helvetica Neue", Helvetica, Roboto, Arial, sans-serif',
|
||||
h5: {
|
||||
fontWeight: 700,
|
||||
},
|
||||
h4: {
|
||||
fontWeight: 700,
|
||||
fontSize: 28,
|
||||
marginBottom: 6,
|
||||
},
|
||||
h3: {
|
||||
fontSize: 32,
|
||||
fontWeight: 700,
|
||||
marginBottom: 6,
|
||||
},
|
||||
h2: {
|
||||
fontSize: 40,
|
||||
fontWeight: 700,
|
||||
marginBottom: 8,
|
||||
},
|
||||
h1: {
|
||||
fontSize: 54,
|
||||
fontWeight: 700,
|
||||
marginBottom: 10,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const createOverrides = theme => {
|
||||
return {
|
||||
overrides: {
|
||||
MuiCSSBaseline: {
|
||||
'@global': {
|
||||
body: {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
color: theme.palette.color.default,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTableRow: {
|
||||
// Alternating row backgrounds
|
||||
root: {
|
||||
'&:nth-of-type(odd)': {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
},
|
||||
},
|
||||
// Use pointer for hoverable rows
|
||||
hover: {
|
||||
'&:hover': {
|
||||
cursor: 'pointer',
|
||||
},
|
||||
},
|
||||
// Alternating head backgrounds
|
||||
head: {
|
||||
'&:nth-of-type(odd)': {
|
||||
backgroundColor: COLORS.NAMED.WHITE,
|
||||
},
|
||||
},
|
||||
},
|
||||
// Tables are more dense than default mui tables
|
||||
MuiTableCell: {
|
||||
root: {
|
||||
wordBreak: 'break-word',
|
||||
overflow: 'hidden',
|
||||
verticalAlign: 'middle',
|
||||
lineHeight: '1',
|
||||
margin: 0,
|
||||
padding: '8px',
|
||||
borderBottom: 0,
|
||||
},
|
||||
head: {
|
||||
wordBreak: 'break-word',
|
||||
overflow: 'hidden',
|
||||
color: 'rgb(179, 179, 179)',
|
||||
fontWeight: 'normal',
|
||||
lineHeight: '1',
|
||||
},
|
||||
},
|
||||
MuiTabs: {
|
||||
// Tabs are smaller than default mui tab rows
|
||||
root: {
|
||||
minHeight: 24,
|
||||
},
|
||||
},
|
||||
MuiTab: {
|
||||
// Tabs are smaller and have a hover background
|
||||
root: {
|
||||
color: theme.palette.link,
|
||||
minHeight: 24,
|
||||
textTransform: 'initial',
|
||||
'&:hover': {
|
||||
color: darken(theme.palette.link, 0.3),
|
||||
background: lighten(theme.palette.link, 0.95),
|
||||
},
|
||||
[theme.breakpoints.up('md')]: {
|
||||
minWidth: 120,
|
||||
fontSize: theme.typography.pxToRem(14),
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
textColorPrimary: {
|
||||
color: theme.palette.link,
|
||||
},
|
||||
},
|
||||
MuiTableSortLabel: {
|
||||
// No color change on hover, just rely on the arrow showing up instead.
|
||||
root: {
|
||||
color: 'inherit',
|
||||
'&:hover': {
|
||||
color: 'inherit',
|
||||
},
|
||||
'&:focus': {
|
||||
color: 'inherit',
|
||||
},
|
||||
},
|
||||
// Bold font for highlighting selected column
|
||||
active: {
|
||||
fontWeight: 'bold',
|
||||
color: 'inherit',
|
||||
},
|
||||
},
|
||||
MuiListItemText: {
|
||||
dense: {
|
||||
// Default dense list items to adding ellipsis for really long str...
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
},
|
||||
},
|
||||
MuiButton: {
|
||||
text: {
|
||||
// Text buttons have less padding by default, but we want to keep the original padding
|
||||
padding: null,
|
||||
},
|
||||
},
|
||||
MuiChip: {
|
||||
root: {
|
||||
// By default there's no margin, but it's usually wanted, so we add some trailing margin
|
||||
marginRight: theme.spacing(1),
|
||||
marginBottom: theme.spacing(1),
|
||||
},
|
||||
},
|
||||
MuiCardHeader: {
|
||||
root: {
|
||||
// Reduce padding between header and content
|
||||
paddingBottom: 0,
|
||||
},
|
||||
},
|
||||
MuiCardActions: {
|
||||
root: {
|
||||
// We default to putting the card actions at the end
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const extendedTheme = createMuiTheme(extendedThemeConfig);
|
||||
|
||||
// V1 theming
|
||||
// https://material-ui-next.com/customization/themes/
|
||||
// For CSS it is advised to use JSS, see https://material-ui-next.com/customization/css-in-js/
|
||||
const BackstageThemeLight = {
|
||||
...extendedTheme,
|
||||
...createOverrides(extendedTheme),
|
||||
};
|
||||
|
||||
// Temporary workaround for files incorrectly importing the theme directly
|
||||
export const V1 = BackstageThemeLight;
|
||||
export default BackstageThemeLight;
|
||||
Reference in New Issue
Block a user