Merge branch 'master' of https://github.com/spotify/backstage into remove_plugin_wip

This commit is contained in:
Jose Balanza Martinez
2020-04-16 12:32:53 -05:00
55 changed files with 859 additions and 1057 deletions
+1
View File
@@ -30,6 +30,7 @@
"scripts": {
"start": "backstage-cli app:serve",
"bundle": "backstage-cli app:build",
"clean": "backstage-cli clean",
"test": "backstage-cli test",
"test:e2e": "start-server-and-test start http://localhost:3000 cy:dev",
"test:e2e:ci": "start-server-and-test start http://localhost:3000 cy:run",
+7 -9
View File
@@ -20,7 +20,7 @@ import {
Theme,
ThemeProvider,
} from '@material-ui/core';
import { BackstageThemeLight, BackstageThemeDark } from '@backstage/theme';
import { lightTheme, darkTheme } from '@backstage/theme';
import { createApp } from '@backstage/core';
import React, { FC } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
@@ -53,30 +53,28 @@ app.registerApis(apis);
app.registerPlugin(...Object.values(plugins));
const AppComponent = app.build();
type T = typeof BackstageThemeLight | typeof BackstageThemeDark;
const App: FC<{}> = () => {
useStyles();
const [theme, toggleTheme] = useThemeType(
localStorage.getItem('theme') || 'auto',
);
let backstageTheme: T = BackstageThemeLight;
let backstageTheme = lightTheme;
switch (theme) {
case 'light':
backstageTheme = BackstageThemeLight;
backstageTheme = lightTheme;
break;
case 'dark':
backstageTheme = BackstageThemeDark;
backstageTheme = darkTheme;
break;
default:
if (!window.matchMedia) {
backstageTheme = BackstageThemeLight;
backstageTheme = lightTheme;
break;
}
backstageTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? BackstageThemeDark
: BackstageThemeLight;
? darkTheme
: lightTheme;
break;
}
+2 -1
View File
@@ -19,7 +19,8 @@ const path = require('path');
// Figure out whether we're running inside the backstage repo or as an installed dependency
const isLocal = require('fs').existsSync(path.resolve(__dirname, '../src'));
if (!isLocal) {
if (!isLocal || process.env.BACKSTAGE_E2E_CLI_TEST) {
// src-relative imports are a pain to get to work with plain tsc compilation, as the
// transpiled code will maintain the imports as they are in the source. Which means an
// import for `helpers/paths` will start like that in the output, which won't work in NodeJS.
+1
View File
@@ -22,6 +22,7 @@
"build": "backstage-cli build-cache -- tsc",
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"clean": "backstage-cli clean",
"start": "nodemon ."
},
"devDependencies": {
@@ -30,7 +30,7 @@ export async function withCache(
buildFunc: () => Promise<void>,
): Promise<void> {
const key = await Cache.readInputKey(options.inputs);
if (!key) {
if (!key || process.env.BACKSTAGE_E2E_CLI_TEST) {
print('input directory is dirty, skipping cache');
await fs.remove(options.output);
await buildFunc();
+33
View File
@@ -0,0 +1,33 @@
/*
* 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 fs from 'fs-extra';
import { resolve as resolvePath, relative as relativePath } from 'path';
import { getDefaultCacheOptions } from 'commands/build-cache/options';
import { paths } from 'helpers/paths';
export default async function clean() {
const cacheOptions = getDefaultCacheOptions();
const packagePath = getPackagePath(cacheOptions.cacheDir);
await fs.remove(cacheOptions.output);
await fs.remove(packagePath);
}
function getPackagePath(cacheDir: string) {
const relativePackagePath = relativePath(paths.targetRoot, paths.targetDir);
const packagePath = resolvePath(cacheDir, relativePackagePath);
return packagePath;
}
@@ -86,6 +86,34 @@ export async function moveApp(
});
}
async function addPackageResolutions(rootDir: string, appDir: string) {
process.chdir(appDir);
const packageFileContent = await fs.readFile('package.json', 'utf-8');
const packageFileJson = JSON.parse(packageFileContent);
if (packageFileJson.resolutions) {
throw new Error('package.json already contains resolutions');
}
packageFileJson.resolutions = {};
const packages = ['cli', 'core', 'test-utils', 'test-utils-core', 'theme'];
for (const pkg of packages) {
await Task.forItem('adding', `${pkg} link to package.json`, async () => {
const pkgPath = require('path').join(rootDir, 'packages', pkg);
packageFileJson.resolutions[`@backstage/${pkg}`] = `file:${pkgPath}`;
const newContents = `${JSON.stringify(packageFileJson, null, 2)}\n`;
await fs.writeFile('package.json', newContents, 'utf-8').catch(error => {
throw new Error(
`Failed to add resolutions to package.json: ${error.message}`,
);
});
});
}
}
export default async () => {
const questions: Question[] = [
{
@@ -126,6 +154,15 @@ export default async () => {
Task.section('Moving to final location');
await moveApp(tempDir, appDir, answers.name);
// e2e testing needs special treatment
if (process.env.BACKSTAGE_E2E_CLI_TEST) {
Task.section('Linking packages locally for e2e tests');
const rootDir = process.env.CI
? resolvePath(process.env.GITHUB_WORKSPACE!)
: resolvePath(__dirname, '..', '..', '..');
await addPackageResolutions(rootDir, appDir);
}
Task.section('Building the app');
await buildApp(appDir);
@@ -134,6 +171,7 @@ export default async () => {
chalk.green(`🥇 Successfully created ${chalk.cyan(answers.name)}`),
);
Task.log();
Task.exit();
} catch (error) {
Task.error(error.message);
@@ -143,5 +181,6 @@ export default async () => {
Task.section('Cleanup');
await cleanUp(tempDir);
Task.error('🔥 Failed to create app!');
Task.exit(1);
}
};
@@ -268,6 +268,7 @@ export default async () => {
)}`,
);
Task.log();
Task.exit();
} catch (error) {
Task.error(error.message);
@@ -277,5 +278,6 @@ export default async () => {
Task.section('Cleanup');
await cleanUp(tempDir);
Task.error('🔥 Failed to create plugin!');
Task.exit(1);
}
};
@@ -46,6 +46,7 @@ export default {
json(),
typescript({
include: `${paths.resolveTarget('src')}/**/*.{js,jsx,ts,tsx}`,
clean: true,
}),
],
} as RollupWatchOptions;
@@ -23,6 +23,7 @@ import { startCompiler } from './compiler';
import { startChild } from './child';
import { waitForExit, run } from 'helpers/run';
import { paths } from 'helpers/paths';
import { Command } from 'commander';
const PACKAGE_BLACKLIST = [
// We never want to watch for changes in the cli, but all packages will depend on it.
@@ -88,8 +89,14 @@ export async function watchDeps(options: Options = {}) {
* and instead start up watch mode for that package. Starting watch mode means running the first
* available yarn script out of "build:watch", "watch", or "build" --watch.
*/
export default async (_command: any, args: string[]) => {
await watchDeps();
export default async (cmd: Command, args: string[]) => {
const options: Options = {};
if (cmd.build) {
options.build = true;
}
await watchDeps(options);
if (args?.length) {
await waitForExit(startChild(args));
+1 -1
View File
@@ -53,7 +53,7 @@ export function findRootPath(topPath: string): string {
try {
const contents = fs.readFileSync(packagePath, 'utf8');
const data = JSON.parse(contents);
if (data.name === 'root') {
if (data.name === 'root' || data.name.includes('backstage-e2e')) {
return path;
}
} catch (error) {
+4
View File
@@ -37,6 +37,10 @@ export class Task {
process.stdout.write(`\n ${title}\n`);
}
static exit(code: number = 0) {
process.exit(code);
}
static async forItem(
task: string,
item: string,
+6
View File
@@ -77,6 +77,7 @@ const main = (argv: string[]) => {
program
.command('watch-deps')
.option('--build', 'Build all dependencies on startup')
.description('Watch all dependencies while running another command')
.action(actionHandler(() => require('commands/watch-deps')));
@@ -97,6 +98,11 @@ const main = (argv: string[]) => {
)
.action(actionHandler(() => require('commands/build-cache')));
program
.command('clean')
.description('Delete cache directories')
.action(actionHandler(() => require('commands/clean/clean')));
program.on('command:*', () => {
console.log();
console.log(
@@ -13,7 +13,8 @@
"test:all": "yarn build && lerna run test -- --coverage",
"lint": "lerna run lint --since origin/master --",
"lint:all": "lerna run lint --",
"create-plugin": "backstage-cli create-plugin"
"create-plugin": "backstage-cli create-plugin",
"clean": "lerna run clean"
},
"workspaces": {
"packages": [
@@ -5,6 +5,7 @@
"dependencies": {
"@material-ui/core": "^4.9.1",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "4.0.0-alpha.45",
"@backstage/cli": "^{{version}}",
"@backstage/core": "^{{version}}",
"@backstage/theme": "^{{version}}",
@@ -17,7 +18,8 @@
"plugin-welcome": "0.0.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-router-dom": "^5.1.2"
"react-router-dom": "^5.1.2",
"react-use": "^13.24.0"
},
"scripts": {
"start": "backstage-cli app:serve",
@@ -1,6 +1,6 @@
import { CssBaseline, makeStyles, ThemeProvider } from '@material-ui/core';
import { createApp } from '@backstage/core';
import { BackstageTheme } from '@backstage/theme';
import { lightTheme } from '@backstage/theme';
import React, { FC } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import * as plugins from './plugins';
@@ -31,7 +31,7 @@ const App: FC<{}> = () => {
useStyles();
return (
<CssBaseline>
<ThemeProvider theme={BackstageTheme}>
<ThemeProvider theme={lightTheme}>
<Router>
<AppComponent />
</Router>
@@ -2,12 +2,12 @@ import React from 'react';
import { render } from '@testing-library/react';
import WelcomePage from './WelcomePage';
import { ThemeProvider } from '@material-ui/core';
import { BackstageTheme } from '@backstage/theme';
import { lightTheme } from '@backstage/theme';
describe('WelcomePage', () => {
it('should render', () => {
const rendered = render(
<ThemeProvider theme={BackstageTheme}>
<ThemeProvider theme={lightTheme}>
<WelcomePage />
</ThemeProvider>,
);
@@ -8,7 +8,8 @@
"scripts": {
"build": "backstage-cli plugin:build",
"lint": "backstage-cli lint",
"test": "backstage-cli test"
"test": "backstage-cli test",
"clean": "backstage-cli clean"
},
"devDependencies": {
"@backstage/cli": "^{{version}}",
@@ -19,13 +19,13 @@ import { render } from '@testing-library/react';
import mockFetch from 'jest-fetch-mock';
import ExampleComponent from './ExampleComponent';
import { ThemeProvider } from '@material-ui/core';
import { BackstageTheme } from '@backstage/theme';
import { lightTheme } from '@backstage/theme';
describe('ExampleComponent', () => {
it('should render', () => {
mockFetch.mockResponse(() => new Promise(() => {}));
const rendered = render(
<ThemeProvider theme={BackstageTheme}>
<ThemeProvider theme={lightTheme}>
<ExampleComponent />
</ThemeProvider>,
);
+3 -2
View File
@@ -21,7 +21,8 @@
"scripts": {
"build": "backstage-cli plugin:build",
"lint": "backstage-cli lint",
"test": "backstage-cli test"
"test": "backstage-cli test",
"clean": "backstage-cli clean"
},
"dependencies": {
"@material-ui/core": "^4.9.1",
@@ -42,9 +43,9 @@
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.4",
"@backstage/test-utils": "0.1.1-alpha.4",
"@backstage/test-utils-core": "^0.1.1-alpha.4",
"@backstage/theme": "^0.1.1-alpha.4",
"@storybook/addon-storysource": "^5.3.18",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
@@ -19,7 +19,7 @@ import { BackstageTheme } from '@backstage/theme';
import { Circle } from 'rc-progress';
import React, { FC } from 'react';
const useStyles = makeStyles<typeof BackstageTheme>(theme => ({
const useStyles = makeStyles<BackstageTheme>(theme => ({
root: {
position: 'relative',
lineHeight: 0,
@@ -19,7 +19,7 @@ import { BackstageTheme } from '@backstage/theme';
import classNames from 'classnames';
import React, { FC } from 'react';
const useStyles = makeStyles<typeof BackstageTheme>(theme => ({
const useStyles = makeStyles<BackstageTheme>(theme => ({
status: {
width: 12,
height: 12,
@@ -14,9 +14,9 @@
* limitations under the License.
*/
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Typography, withStyles } from '@material-ui/core';
import React, { FC } from 'react';
import { Typography, withStyles, makeStyles } from '@material-ui/core';
import { BackstageTheme } from '@backstage/theme';
import ErrorOutline from '@material-ui/icons/ErrorOutline';
const errorOutlineStyles = theme => ({
@@ -27,7 +27,7 @@ const errorOutlineStyles = theme => ({
});
const ErrorOutlineStyled = withStyles(errorOutlineStyles)(ErrorOutline);
const styles = theme => ({
const useStyles = makeStyles<BackstageTheme>(theme => ({
message: {
display: 'flex',
flexDirection: 'column',
@@ -47,34 +47,35 @@ const styles = theme => ({
messageText: {
color: theme.palette.warningText,
},
});
}));
/**
* WarningPanel. Show a user friendly error message to a user similar to ErrorPanel except that the warning panel
* only shows the warning message to the user
*/
class WarningPanel extends Component {
static propTypes = {
message: PropTypes.node.isRequired,
};
render() {
const { classes, title, message, children } = this.props;
return (
<div className={classes.message}>
<div className={classes.header}>
<ErrorOutlineStyled />
<Typography className={classes.headerText} variant="subtitle1">
{title}
</Typography>
</div>
{message && (
<Typography className={classes.messageText}>{message}</Typography>
)}
{children}
type Props = {
message?: React.ReactNode;
title?: string;
};
const WarningPanel: FC<Props> = props => {
const classes = useStyles(props);
const { title, message, children } = props;
return (
<div className={classes.message}>
<div className={classes.header}>
<ErrorOutlineStyled />
<Typography className={classes.headerText} variant="subtitle1">
{title}
</Typography>
</div>
);
}
}
{message && (
<Typography className={classes.messageText}>{message}</Typography>
)}
{children}
</div>
);
};
export default withStyles(styles)(WarningPanel);
export default WarningPanel;
+1 -1
View File
@@ -23,7 +23,7 @@ import { Theme } from 'layout/Page/Page';
// import { Link } from 'shared/components';
import Waves from './Waves';
const useStyles = makeStyles<typeof BackstageTheme>(theme => ({
const useStyles = makeStyles<BackstageTheme>(theme => ({
header: {
gridArea: 'pageHeader',
padding: theme.spacing(3),
+1 -1
View File
@@ -20,7 +20,7 @@ import React, { FC, useRef, useState } from 'react';
import { sidebarConfig, SidebarContext } from './config';
import { BackstageTheme } from '@backstage/theme';
const useStyles = makeStyles<typeof BackstageTheme>(theme => ({
const useStyles = makeStyles<BackstageTheme>(theme => ({
root: {
zIndex: 1000,
position: 'relative',
@@ -15,19 +15,37 @@
*/
import React, { useState } from 'react';
import { TabbedCard, CardTab } from '.';
import { Grid } from '@material-ui/core';
const cardContentStyle = { height: 200, width: 500 };
export default {
title: 'Tabbed Card',
component: TabbedCard,
decorators: [
storyFn => (
<Grid container spacing={4}>
<Grid item>{storyFn()}</Grid>
</Grid>
),
],
};
export const Default = () => {
return (
<TabbedCard title="Default Example Header">
<CardTab label="Option 1">some content 1</CardTab>
<CardTab label="Option 2">some content 2</CardTab>
<CardTab label="Option 3">some content 3</CardTab>
<CardTab label="Option 4">some content 4</CardTab>
<CardTab label="Option 1">
<div style={cardContentStyle}>Some content</div>
</CardTab>
<CardTab label="Option 2">
<div style={cardContentStyle}>Some content 2</div>
</CardTab>
<CardTab label="Option 3">
<div style={cardContentStyle}>Some content 3</div>
</CardTab>
<CardTab label="Option 4">
<div style={cardContentStyle}>Some content 4</div>
</CardTab>
</TabbedCard>
);
};
@@ -37,10 +55,18 @@ const linkInfo = { title: 'Go to XYZ Location', link: '#' };
export const WithFooterLink = () => {
return (
<TabbedCard title="Footer Link Example Header" deepLink={linkInfo}>
<CardTab label="Option 1">some content 1</CardTab>
<CardTab label="Option 2">some content 2</CardTab>
<CardTab label="Option 3">some content 3</CardTab>
<CardTab label="Option 4">some content 4</CardTab>
<CardTab label="Option 1">
<div style={cardContentStyle}>Some content</div>
</CardTab>
<CardTab label="Option 2">
<div style={cardContentStyle}>Some content 2</div>
</CardTab>
<CardTab label="Option 3">
<div style={cardContentStyle}>Some content 3</div>
</CardTab>
<CardTab label="Option 4">
<div style={cardContentStyle}>Some content 4</div>
</CardTab>
</TabbedCard>
);
};
@@ -60,16 +86,16 @@ export const WithControlledTabValue = () => {
title="Controlled Value Example"
>
<CardTab value="one" label="Option 1">
some content 1
<div style={cardContentStyle}>Some content</div>
</CardTab>
<CardTab value="two" label="Option 2">
some content 2
<div style={cardContentStyle}>Some content 2</div>
</CardTab>
<CardTab value="three" label="Option 3">
some content 3
<div style={cardContentStyle}>Some content 3</div>
</CardTab>
<CardTab value="four" label="Option 4">
some content 4
<div style={cardContentStyle}>Some content 4</div>
</CardTab>
</TabbedCard>
</>
+2 -2
View File
@@ -1,10 +1,10 @@
import React from 'react';
import { addDecorator } from '@storybook/react';
import { BackstageTheme } from '@backstage/theme';
import { lightTheme } from '@backstage/theme';
import { CssBaseline, ThemeProvider } from '@material-ui/core';
addDecorator(story => (
<ThemeProvider theme={BackstageTheme}>
<ThemeProvider theme={lightTheme}>
<CssBaseline>{story()}</CssBaseline>
</ThemeProvider>
));
+1 -1
View File
@@ -13,7 +13,7 @@ module.exports = {
webpackFinal: async config => {
config.resolve.alias = {
...config.resolve.alias,
'@backstage/theme': path.resolve(__dirname, '../../theme/src'),
'@backstage/theme': path.resolve(__dirname, '../../theme'),
};
config.resolve.modules.push(path.resolve(__dirname, '../../core/src'));
config.module.rules.push(
+4
View File
@@ -1,3 +1,7 @@
# storybook
This package provides a storybook build for Backstage. See [storybook.backstage.io](http://storybook.backstage.io)
## Why is this not part of `@backstage/core`?
This separate storybook package exists because of dependency conflicts with `@backstage/cli`. It uses nohoist to avoid the conflicts, and since you can only use that in private packages it has to be separated out of `@backstage/core`.
+7 -3
View File
@@ -4,14 +4,18 @@
"description": "Storybook build for core package",
"private": true,
"scripts": {
"start": "start-storybook -p 6006",
"build-storybook": "build-storybook --output-dir dist"
"start": "backstage-cli watch-deps --build -- start-storybook -p 6006",
"build-storybook": "backstage-cli watch-deps --build -- build-storybook --output-dir dist"
},
"workspaces": {
"nohoist": [
"@storybook/**"
"@storybook/react/**",
"@storybook/addons/**"
]
},
"dependencies": {
"@backstage/theme": "0.1.1-alpha.4"
},
"devDependencies": {
"@storybook/addon-actions": "^5.3.17",
"@storybook/addon-links": "^5.3.17",
+2 -1
View File
@@ -21,7 +21,8 @@
"scripts": {
"build": "backstage-cli plugin:build",
"lint": "backstage-cli lint",
"test": "backstage-cli test"
"test": "backstage-cli test",
"clean": "backstage-cli clean"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.4",
@@ -18,7 +18,7 @@ import React, { ComponentType, ReactNode, FunctionComponent } from 'react';
import { ThemeProvider } from '@material-ui/core';
import { MemoryRouter } from 'react-router';
import { Route } from 'react-router-dom';
import { BackstageTheme } from '@backstage/theme';
import { lightTheme } from '@backstage/theme';
export function wrapInTestApp(
Component: ComponentType | ReactNode,
@@ -42,12 +42,10 @@ export function wrapInThemedTestApp(
component: ReactNode,
initialRouterEntries: string[] = ['/'],
) {
const themed = (
<ThemeProvider theme={BackstageTheme}>{component}</ThemeProvider>
);
const themed = <ThemeProvider theme={lightTheme}>{component}</ThemeProvider>;
return wrapInTestApp(themed, initialRouterEntries);
}
export const wrapInTheme = (component: ReactNode, theme = BackstageTheme) => (
export const wrapInTheme = (component: ReactNode, theme = lightTheme) => (
<ThemeProvider theme={theme}>{component}</ThemeProvider>
);
+2 -1
View File
@@ -20,7 +20,8 @@
"types": "dist/index.d.ts",
"scripts": {
"build": "backstage-cli plugin:build",
"lint": "backstage-cli lint"
"lint": "backstage-cli lint",
"clean": "backstage-cli clean"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.4",
-260
View File
@@ -1,260 +0,0 @@
/*
* 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';
import { BackstageMuiTheme, BackstageMuiThemeOptions } from './types';
const COLORS = {
PAGE_BACKGROUND: '#F8F8F8',
DEFAULT_PAGE_THEME_COLOR: '#7C3699',
DEFAULT_PAGE_THEME_LIGHT_COLOR: '#ECDBF2',
SIDEBAR_BACKGROUND_COLOR: '#171717',
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: BackstageMuiThemeOptions = {
props: {
MuiGrid: {
spacing: 2,
},
MuiSwitch: {
color: 'primary',
},
},
palette: {
background: {
default: COLORS.PAGE_BACKGROUND,
// @ts-ignore
informational: '#60a3cb',
},
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,
},
},
// @ts-ignore
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,
sidebar: COLORS.SIDEBAR_BACKGROUND_COLOR,
},
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: BackstageMuiTheme,
): Partial<BackstageMuiTheme> => {
return {
overrides: {
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: undefined,
},
},
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) as BackstageMuiTheme;
// 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 BackstageTheme: BackstageMuiTheme = {
...extendedTheme,
...createOverrides(extendedTheme),
};
// Temporary workaround for files incorrectly importing the theme directly
export const V1 = BackstageTheme;
export default BackstageTheme;
-273
View File
@@ -1,273 +0,0 @@
/*
* 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';
import { BackstageMuiTheme, BackstageMuiThemeOptions } from './types';
const COLORS = {
PAGE_BACKGROUND: '#282828',
DEFAULT_PAGE_THEME_COLOR: '#7C3699',
DEFAULT_PAGE_THEME_LIGHT_COLOR: '#ECDBF2',
SIDEBAR_BACKGROUND_COLOR: '#424242',
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: BackstageMuiThemeOptions = {
props: {
MuiGrid: {
spacing: 2,
},
MuiSwitch: {
color: 'primary',
},
},
palette: {
background: {
default: COLORS.PAGE_BACKGROUND,
// @ts-ignore
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,
},
},
// @ts-ignore
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,
sidebar: COLORS.SIDEBAR_BACKGROUND_COLOR,
},
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: BackstageMuiTheme): BackstageMuiTheme => {
return {
overrides: {
// @ts-ignore
MuiCSSBaseline: {
'@global': {
body: {
backgroundColor: theme.palette.background.default,
// @ts-ignore
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: undefined,
},
},
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) as BackstageMuiTheme;
// 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;
-274
View File
@@ -1,274 +0,0 @@
/*
* 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';
import { BackstageMuiTheme, BackstageMuiThemeOptions } from './types';
const COLORS = {
PAGE_BACKGROUND: '#F8F8F8',
DEFAULT_PAGE_THEME_COLOR: '#7C3699',
DEFAULT_PAGE_THEME_LIGHT_COLOR: '#ECDBF2',
SIDEBAR_BACKGROUND_COLOR: '#171717',
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: BackstageMuiThemeOptions = {
props: {
MuiGrid: {
spacing: 2,
},
MuiSwitch: {
color: 'primary',
},
},
palette: {
background: {
default: COLORS.PAGE_BACKGROUND,
// @ts-ignore
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,
},
},
// @ts-ignore
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,
sidebar: COLORS.SIDEBAR_BACKGROUND_COLOR,
},
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: BackstageMuiTheme,
): Partial<BackstageMuiTheme> => {
return {
overrides: {
// @ts-ignore
MuiCSSBaseline: {
'@global': {
body: {
backgroundColor: theme.palette.background.default,
// @ts-ignore
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: undefined,
},
},
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) as BackstageMuiTheme;
// 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;
+197
View File
@@ -0,0 +1,197 @@
/*
* 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 { Overrides } from '@material-ui/core/styles/overrides';
import {
BackstageTheme,
BackstageThemeOptions,
BackstagePaletteOptions,
} from './types';
export function createThemeOptions(
palette: BackstagePaletteOptions,
): BackstageThemeOptions {
return {
palette,
props: {
MuiGrid: {
spacing: 2,
},
MuiSwitch: {
color: 'primary',
},
},
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,
},
},
};
}
export function createThemeOverrides(theme: BackstageTheme): Overrides {
return {
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: theme.palette.background.paper,
},
},
},
// 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: undefined,
},
},
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',
},
},
};
}
// Creates a Backstage MUI theme using a palette.
// The theme is created with the common Backstage options and component styles.
export function createTheme(palette: BackstagePaletteOptions): BackstageTheme {
const themeOptions = createThemeOptions(palette);
const baseTheme = createMuiTheme(themeOptions) as BackstageTheme;
const overrides = createThemeOverrides(baseTheme);
const theme = { ...baseTheme, overrides };
return theme;
}
+4 -3
View File
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { default as BackstageThemeLight } from './BackstageThemeLight';
export { default as BackstageThemeDark } from './BackstageThemeDark';
export { default as BackstageTheme } from './BackstageTheme';
export * from './themes';
export * from './baseTheme';
export * from './types';
+96
View File
@@ -0,0 +1,96 @@
/*
* 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 { createTheme } from 'baseTheme';
import { blue, yellow } from '@material-ui/core/colors';
export const lightTheme = createTheme({
type: 'light',
background: {
default: '#F8F8F8',
},
status: {
ok: '#1db855',
warning: '#f49b20',
error: '#CA001B',
running: '#BEBEBE',
pending: '#5BC0DE',
background: '#FEFEFE',
},
bursts: {
fontColor: '#FEFEFE',
slackChannelText: '#ddd',
backgroundColor: {
default: '#7C3699',
},
},
primary: {
main: blue[500],
},
border: '#E6E6E6',
textVerySubtle: '#DDD',
textSubtle: '#6E6E6E',
highlight: '#FFFBCC',
errorBackground: '#FFEBEE',
warningBackground: '#F59B23',
infoBackground: '#ebf5ff',
errorText: '#CA001B',
infoText: '#004e8a',
warningText: '#FEFEFE',
linkHover: '#2196F3',
link: '#0A6EBE',
gold: yellow.A700,
sidebar: '#171717',
});
export const darkTheme = createTheme({
type: 'dark',
background: {
default: '#282828',
},
status: {
ok: '#1db855',
warning: '#f49b20',
error: '#CA001B',
running: '#BEBEBE',
pending: '#5BC0DE',
background: '#FEFEFE',
},
bursts: {
fontColor: '#FEFEFE',
slackChannelText: '#ddd',
backgroundColor: {
default: '#7C3699',
},
},
primary: {
main: blue[500],
},
border: '#E6E6E6',
textVerySubtle: '#DDD',
textSubtle: '#6E6E6E',
highlight: '#FFFBCC',
errorBackground: '#FFEBEE',
warningBackground: '#F59B23',
infoBackground: '#ebf5ff',
errorText: '#CA001B',
infoText: '#004e8a',
warningText: '#FEFEFE',
linkHover: '#2196F3',
link: '#0A6EBE',
gold: yellow.A700,
sidebar: '#424242',
});
+12 -5
View File
@@ -15,8 +15,12 @@
*/
import { Theme, ThemeOptions } from '@material-ui/core';
import {
PaletteOptions,
Palette,
} from '@material-ui/core/styles/createPalette';
export type BackstageMuiPalette = Theme['palette'] & {
type PaletteAdditions = {
status: {
ok: string;
warning: string;
@@ -48,10 +52,13 @@ export type BackstageMuiPalette = Theme['palette'] & {
};
};
export interface BackstageMuiTheme extends Theme {
palette: BackstageMuiPalette;
export type BackstagePalette = Palette & PaletteAdditions;
export type BackstagePaletteOptions = PaletteOptions & PaletteAdditions;
export interface BackstageTheme extends Theme {
palette: BackstagePalette;
}
export interface BackstageMuiThemeOptions extends ThemeOptions {
palette: Partial<BackstageMuiPalette>;
export interface BackstageThemeOptions extends ThemeOptions {
palette: BackstagePaletteOptions;
}