2018-07-17 23:34:28 +00:00
|
|
|
// @flow
|
|
|
|
import { render, THROW_ON_ERROR } from '../common/render';
|
|
|
|
import { getThemes } from './index';
|
2018-07-18 00:48:10 +00:00
|
|
|
import type { Theme } from './index';
|
2018-07-17 23:34:28 +00:00
|
|
|
|
|
|
|
type ThemeBlock = {
|
|
|
|
background?: {
|
|
|
|
default: string,
|
|
|
|
success?: string,
|
|
|
|
notice?: string,
|
|
|
|
warning?: string,
|
|
|
|
danger?: string,
|
|
|
|
surprise?: string,
|
2018-12-12 17:36:11 +00:00
|
|
|
info?: string,
|
2018-07-17 23:34:28 +00:00
|
|
|
},
|
|
|
|
foreground?: {
|
|
|
|
default: string,
|
|
|
|
success?: string,
|
|
|
|
notice?: string,
|
|
|
|
warning?: string,
|
|
|
|
danger?: string,
|
|
|
|
surprise?: string,
|
2018-12-12 17:36:11 +00:00
|
|
|
info?: string,
|
2018-07-17 23:34:28 +00:00
|
|
|
},
|
|
|
|
highlight?: {
|
|
|
|
default: string,
|
|
|
|
xxs?: string,
|
|
|
|
xs?: string,
|
|
|
|
sm?: string,
|
|
|
|
md?: string,
|
|
|
|
lg?: string,
|
2018-12-12 17:36:11 +00:00
|
|
|
xl?: string,
|
|
|
|
},
|
2018-07-17 23:34:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
type ThemeInner = {
|
|
|
|
...ThemeBlock,
|
2018-07-17 23:39:15 +00:00
|
|
|
rawCss?: string,
|
2018-07-17 23:34:28 +00:00
|
|
|
styles: ?{
|
2019-08-09 16:15:29 +00:00
|
|
|
dialog?: ThemeBlock,
|
|
|
|
dialogFooter?: ThemeBlock,
|
|
|
|
dialogHeader?: ThemeBlock,
|
2018-07-17 23:34:28 +00:00
|
|
|
dropdown?: ThemeBlock,
|
2019-08-09 16:15:29 +00:00
|
|
|
editor?: ThemeBlock,
|
|
|
|
link?: ThemeBlock,
|
|
|
|
overlay?: ThemeBlock,
|
|
|
|
pane?: ThemeBlock,
|
|
|
|
paneHeader?: ThemeBlock,
|
2018-07-17 23:34:28 +00:00
|
|
|
sidebar?: ThemeBlock,
|
|
|
|
sidebarHeader?: ThemeBlock,
|
|
|
|
sidebarList?: ThemeBlock,
|
2019-08-09 16:15:29 +00:00
|
|
|
tooltip?: ThemeBlock,
|
2018-07-17 23:34:28 +00:00
|
|
|
transparentOverlay?: ThemeBlock,
|
2018-12-12 17:36:11 +00:00
|
|
|
},
|
2018-07-17 23:34:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export type PluginTheme = {
|
|
|
|
name: string,
|
|
|
|
displayName: string,
|
2018-12-12 17:36:11 +00:00
|
|
|
theme: ThemeInner,
|
2018-07-17 23:34:28 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export async function generateThemeCSS(theme: PluginTheme): Promise<string> {
|
|
|
|
const renderedTheme: ThemeInner = await render(
|
|
|
|
theme.theme,
|
|
|
|
theme.theme,
|
|
|
|
null,
|
|
|
|
THROW_ON_ERROR,
|
2018-12-12 17:36:11 +00:00
|
|
|
theme.name,
|
2018-07-17 23:34:28 +00:00
|
|
|
);
|
|
|
|
const n = theme.name;
|
|
|
|
|
|
|
|
let css = '';
|
|
|
|
css += wrapStyles(n, '', getThemeBlockCSS(renderedTheme));
|
|
|
|
|
|
|
|
if (renderedTheme.styles) {
|
|
|
|
const styles = renderedTheme.styles;
|
|
|
|
|
|
|
|
// Dropdown Menus
|
2018-10-17 16:42:33 +00:00
|
|
|
css += wrapStyles(n, '.theme--dropdown__menu', getThemeBlockCSS(styles.dialog));
|
|
|
|
css += wrapStyles(n, '.theme--dropdown__menu', getThemeBlockCSS(styles.dropdown));
|
2018-07-17 23:34:28 +00:00
|
|
|
|
|
|
|
// Tooltips
|
|
|
|
css += wrapStyles(n, '.theme--tooltip', getThemeBlockCSS(styles.dialog));
|
|
|
|
css += wrapStyles(n, '.theme--tooltip', getThemeBlockCSS(styles.tooltip));
|
|
|
|
|
|
|
|
// Overlay
|
|
|
|
css += wrapStyles(
|
|
|
|
n,
|
|
|
|
'.theme--transparent-overlay',
|
2018-12-12 17:36:11 +00:00
|
|
|
getThemeBlockCSS(styles.transparentOverlay),
|
2018-07-17 23:34:28 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
// Dialogs
|
|
|
|
css += wrapStyles(n, '.theme--dialog', getThemeBlockCSS(styles.dialog));
|
2018-10-17 16:42:33 +00:00
|
|
|
css += wrapStyles(n, '.theme--dialog__header', getThemeBlockCSS(styles.dialogHeader));
|
|
|
|
css += wrapStyles(n, '.theme--dialog__footer', getThemeBlockCSS(styles.dialogFooter));
|
2018-07-17 23:34:28 +00:00
|
|
|
|
|
|
|
// Panes
|
|
|
|
css += wrapStyles(n, '.theme--pane', getThemeBlockCSS(styles.pane));
|
2018-10-17 16:42:33 +00:00
|
|
|
css += wrapStyles(n, '.theme--pane__header', getThemeBlockCSS(styles.paneHeader));
|
2018-07-17 23:34:28 +00:00
|
|
|
|
|
|
|
// Sidebar Styles
|
|
|
|
css += wrapStyles(n, '.theme--sidebar', getThemeBlockCSS(styles.sidebar));
|
2018-10-17 16:42:33 +00:00
|
|
|
css += wrapStyles(n, '.theme--sidebar__list', getThemeBlockCSS(styles.sidebarList));
|
|
|
|
css += wrapStyles(n, '.theme--sidebar__header', getThemeBlockCSS(styles.sidebarHeader));
|
2018-07-17 23:34:28 +00:00
|
|
|
|
|
|
|
// Link
|
|
|
|
css += wrapStyles(n, '.theme--link', getThemeBlockCSS(styles.link));
|
|
|
|
|
2019-08-09 16:15:29 +00:00
|
|
|
// Code Editors
|
|
|
|
css += wrapStyles(n, '.theme--editor', getThemeBlockCSS(styles.editor));
|
|
|
|
|
2018-07-17 23:34:28 +00:00
|
|
|
// HACK: Dialog styles for CodeMirror dialogs too
|
|
|
|
css += wrapStyles(n, '.CodeMirror-info', getThemeBlockCSS(styles.dialog));
|
|
|
|
}
|
|
|
|
|
2018-07-18 00:48:10 +00:00
|
|
|
return css;
|
2018-07-17 23:34:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function getThemeBlockCSS(block?: ThemeBlock): string {
|
|
|
|
if (!block) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
const indent = '\t';
|
|
|
|
|
|
|
|
let css = '';
|
|
|
|
|
|
|
|
const addVar = (variable?: string, value?: string) => {
|
|
|
|
if (variable && value) {
|
|
|
|
css += `${indent}--${variable}: ${value};\n`;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const addComment = comment => {
|
|
|
|
css += `${indent}/* ${comment} */\n`;
|
|
|
|
};
|
|
|
|
|
|
|
|
const addNewLine = () => {
|
|
|
|
css += `\n`;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (block.background) {
|
|
|
|
const { background } = block;
|
|
|
|
addComment('Background');
|
|
|
|
addVar('color-bg', background.default);
|
|
|
|
addVar('color-success', background.success);
|
|
|
|
addVar('color-notice', background.notice);
|
|
|
|
addVar('color-warning', background.warning);
|
|
|
|
addVar('color-danger', background.danger);
|
|
|
|
addVar('color-surprise', background.surprise);
|
|
|
|
addVar('color-info', background.info);
|
|
|
|
addNewLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (block.foreground) {
|
|
|
|
const { foreground } = block;
|
|
|
|
addComment('Foreground');
|
|
|
|
addVar('color-font', foreground.default);
|
|
|
|
addVar('color-font-success', foreground.success);
|
|
|
|
addVar('color-font-notice', foreground.notice);
|
|
|
|
addVar('color-font-warning', foreground.warning);
|
|
|
|
addVar('color-font-danger', foreground.danger);
|
|
|
|
addVar('color-font-surprise', foreground.surprise);
|
|
|
|
addVar('color-font-info', foreground.info);
|
|
|
|
addNewLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (block.highlight) {
|
|
|
|
const { highlight } = block;
|
|
|
|
addComment('Highlight');
|
|
|
|
addVar('hl', highlight.default);
|
|
|
|
addVar('hl-xxs', highlight.xxs);
|
|
|
|
addVar('hl-xs', highlight.xs);
|
|
|
|
addVar('hl-sm', highlight.sm);
|
|
|
|
addVar('hl-md', highlight.md);
|
|
|
|
addVar('hl-lg', highlight.lg);
|
|
|
|
addVar('hl-xl', highlight.xl);
|
|
|
|
addNewLine();
|
|
|
|
}
|
|
|
|
|
|
|
|
return css.replace(/\s+$/, '');
|
|
|
|
}
|
|
|
|
|
|
|
|
function wrapStyles(theme: string, selector: string, styles: string) {
|
|
|
|
if (!styles) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
return [
|
|
|
|
`[theme="${theme}"] ${selector}, `,
|
|
|
|
`[subtheme="${theme}"] ${selector ? selector + '--sub' : ''} {`,
|
|
|
|
styles,
|
|
|
|
'}',
|
|
|
|
'',
|
2018-12-12 17:36:11 +00:00
|
|
|
'',
|
2018-07-17 23:34:28 +00:00
|
|
|
].join('\n');
|
|
|
|
}
|
|
|
|
|
2018-07-18 00:48:10 +00:00
|
|
|
export async function setTheme(themeName: string) {
|
2018-07-17 23:34:28 +00:00
|
|
|
if (!document) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const head = document.head;
|
2018-07-18 00:48:10 +00:00
|
|
|
const body = document.body;
|
2018-07-17 23:34:28 +00:00
|
|
|
|
2018-07-18 00:48:10 +00:00
|
|
|
if (!head || !body) {
|
2018-07-17 23:34:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-18 00:48:10 +00:00
|
|
|
body.setAttribute('theme', themeName);
|
|
|
|
const themes: Array<Theme> = await getThemes();
|
2018-07-17 23:34:28 +00:00
|
|
|
|
|
|
|
for (const theme of themes) {
|
2018-07-18 00:48:10 +00:00
|
|
|
let themeCSS = (await generateThemeCSS(theme.theme)) + '\n';
|
|
|
|
const { name } = theme.theme;
|
|
|
|
const { rawCss } = theme.theme.theme;
|
|
|
|
|
|
|
|
let s = document.querySelector(`style[data-theme-name="${name}"]`);
|
2018-07-17 23:34:28 +00:00
|
|
|
|
|
|
|
if (!s) {
|
|
|
|
s = document.createElement('style');
|
2018-07-18 00:48:10 +00:00
|
|
|
s.setAttribute('data-theme-name', name);
|
2018-07-17 23:34:28 +00:00
|
|
|
head.appendChild(s);
|
|
|
|
}
|
|
|
|
|
2018-07-18 00:48:10 +00:00
|
|
|
if (typeof rawCss === 'string' && name === themeName) {
|
|
|
|
themeCSS += '\n\n' + rawCss;
|
|
|
|
}
|
|
|
|
|
2018-07-17 23:34:28 +00:00
|
|
|
s.innerHTML = themeCSS;
|
|
|
|
}
|
|
|
|
}
|
2018-10-17 17:26:19 +00:00
|
|
|
|
|
|
|
export async function setFont(settings: Object) {
|
|
|
|
if (!document) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const html = document.querySelector('html');
|
|
|
|
|
|
|
|
if (!html) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-17 18:20:46 +00:00
|
|
|
html.style.setProperty('--font-default', settings.fontInterface);
|
|
|
|
html.style.setProperty('--font-monospace', settings.fontMonospace);
|
|
|
|
html.style.setProperty('--font-ligatures', settings.fontVariantLigatures ? 'normal' : 'none');
|
2018-10-17 17:26:19 +00:00
|
|
|
html.style.setProperty('font-size', `${settings.fontSize}px`);
|
|
|
|
}
|