2018-09-26 13:19:35 +02:00
|
|
|
import * as tinycolor from 'tinycolor2';
|
2018-09-26 18:32:04 +02:00
|
|
|
|
2018-10-02 09:04:31 +02:00
|
|
|
export type Theme = {
|
|
|
|
id: string;
|
|
|
|
name: string;
|
|
|
|
author: string;
|
|
|
|
desc?: string;
|
|
|
|
base?: 'dark' | 'light';
|
|
|
|
vars: { [key: string]: string };
|
|
|
|
props: { [key: string]: string };
|
2018-09-26 18:32:04 +02:00
|
|
|
};
|
|
|
|
|
2019-03-18 05:29:58 +01:00
|
|
|
export const lightTheme: Theme = require('../themes/light.json5');
|
|
|
|
export const darkTheme: Theme = require('../themes/dark.json5');
|
|
|
|
export const lavenderTheme: Theme = require('../themes/lavender.json5');
|
|
|
|
export const futureTheme: Theme = require('../themes/future.json5');
|
|
|
|
export const halloweenTheme: Theme = require('../themes/halloween.json5');
|
|
|
|
export const cafeTheme: Theme = require('../themes/cafe.json5');
|
|
|
|
export const japaneseSushiSetTheme: Theme = require('../themes/japanese-sushi-set.json5');
|
|
|
|
export const gruvboxDarkTheme: Theme = require('../themes/gruvbox-dark.json5');
|
|
|
|
export const monokaiTheme: Theme = require('../themes/monokai.json5');
|
|
|
|
export const colorfulTheme: Theme = require('../themes/colorful.json5');
|
|
|
|
export const rainyTheme: Theme = require('../themes/rainy.json5');
|
|
|
|
export const mauveTheme: Theme = require('../themes/mauve.json5');
|
|
|
|
export const grayTheme: Theme = require('../themes/gray.json5');
|
|
|
|
export const tweetDeckTheme: Theme = require('../themes/tweet-deck.json5');
|
2018-10-02 09:04:31 +02:00
|
|
|
|
|
|
|
export const builtinThemes = [
|
|
|
|
lightTheme,
|
|
|
|
darkTheme,
|
2019-03-18 05:29:58 +01:00
|
|
|
lavenderTheme,
|
|
|
|
futureTheme,
|
2018-12-29 22:40:48 +01:00
|
|
|
halloweenTheme,
|
|
|
|
cafeTheme,
|
|
|
|
japaneseSushiSetTheme,
|
2018-12-30 01:21:23 +01:00
|
|
|
gruvboxDarkTheme,
|
2018-12-30 04:45:31 +01:00
|
|
|
monokaiTheme,
|
|
|
|
colorfulTheme,
|
2019-01-08 10:00:05 +01:00
|
|
|
rainyTheme,
|
2018-12-30 04:45:31 +01:00
|
|
|
mauveTheme,
|
2019-01-08 10:00:05 +01:00
|
|
|
grayTheme,
|
2019-02-06 18:36:02 +01:00
|
|
|
tweetDeckTheme,
|
2018-10-02 09:04:31 +02:00
|
|
|
];
|
|
|
|
|
2019-03-18 05:29:58 +01:00
|
|
|
export function applyTheme(themes: Theme, persisted = true) {
|
|
|
|
document.documentElement.classList.add('changing-themes');
|
2019-03-03 00:43:51 +01:00
|
|
|
|
|
|
|
setTimeout(() => {
|
2019-03-18 05:29:58 +01:00
|
|
|
document.documentElement.classList.remove('changing-themes');
|
2019-03-05 12:45:19 +01:00
|
|
|
}, 1000);
|
2019-03-03 00:43:51 +01:00
|
|
|
|
2018-10-02 09:04:31 +02:00
|
|
|
// Deep copy
|
2019-03-18 05:29:58 +01:00
|
|
|
const _themes = JSON.parse(JSON.stringify(themes));
|
2018-10-02 09:04:31 +02:00
|
|
|
|
2019-03-18 05:29:58 +01:00
|
|
|
if (_themes.base) {
|
|
|
|
const base = [lightTheme, darkTheme].find(x => x.id == _themes.base);
|
|
|
|
_themes.vars = Object.assign({}, base.vars, _themes.vars);
|
|
|
|
_themes.props = Object.assign({}, base.props, _themes.props);
|
2018-09-26 18:32:04 +02:00
|
|
|
}
|
2018-09-26 13:19:35 +02:00
|
|
|
|
2019-03-18 05:29:58 +01:00
|
|
|
const props = compile(_themes);
|
2018-09-26 11:59:37 +02:00
|
|
|
|
2018-12-11 12:36:55 +01:00
|
|
|
for (const [k, v] of Object.entries(props)) {
|
2018-09-26 11:59:37 +02:00
|
|
|
document.documentElement.style.setProperty(`--${k}`, v.toString());
|
2018-12-11 12:36:55 +01:00
|
|
|
}
|
2018-09-26 12:14:11 +02:00
|
|
|
|
2018-09-28 17:01:11 +02:00
|
|
|
if (persisted) {
|
2019-03-18 05:29:58 +01:00
|
|
|
localStorage.setItem('themes', JSON.stringify(props));
|
2018-09-28 17:01:11 +02:00
|
|
|
}
|
2018-09-26 11:59:37 +02:00
|
|
|
}
|
|
|
|
|
2019-03-18 05:29:58 +01:00
|
|
|
function compile(themes: Theme): { [key: string]: string } {
|
2018-09-26 13:19:35 +02:00
|
|
|
function getColor(code: string): tinycolor.Instance {
|
2018-09-26 11:59:37 +02:00
|
|
|
// ref
|
|
|
|
if (code[0] == '@') {
|
2019-03-18 05:29:58 +01:00
|
|
|
return getColor(themes.props[code.substr(1)]);
|
2018-09-26 11:59:37 +02:00
|
|
|
}
|
2018-09-27 12:14:35 +02:00
|
|
|
if (code[0] == '$') {
|
2019-03-18 05:29:58 +01:00
|
|
|
return getColor(themes.vars[code.substr(1)]);
|
2018-09-27 12:14:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// func
|
|
|
|
if (code[0] == ':') {
|
|
|
|
const parts = code.split('<');
|
|
|
|
const func = parts.shift().substr(1);
|
2018-09-27 15:25:10 +02:00
|
|
|
const arg = parseFloat(parts.shift());
|
2018-09-27 12:14:35 +02:00
|
|
|
const color = getColor(parts.join('<'));
|
|
|
|
|
|
|
|
switch (func) {
|
|
|
|
case 'darken': return color.darken(arg);
|
|
|
|
case 'lighten': return color.lighten(arg);
|
2018-09-27 15:25:10 +02:00
|
|
|
case 'alpha': return color.setAlpha(arg);
|
2018-09-27 12:14:35 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-26 11:59:37 +02:00
|
|
|
|
2018-09-26 13:19:35 +02:00
|
|
|
return tinycolor(code);
|
2018-09-26 11:59:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const props = {};
|
|
|
|
|
2019-03-18 05:29:58 +01:00
|
|
|
for (const [k, v] of Object.entries(themes.props)) {
|
2018-12-11 12:36:55 +01:00
|
|
|
props[k] = genValue(getColor(v));
|
|
|
|
}
|
2018-09-26 11:59:37 +02:00
|
|
|
|
2018-09-26 13:19:35 +02:00
|
|
|
const primary = getColor(props['primary']);
|
|
|
|
|
|
|
|
for (let i = 1; i < 10; i++) {
|
|
|
|
const color = primary.clone().setAlpha(i / 10);
|
|
|
|
props['primaryAlpha0' + i] = genValue(color);
|
|
|
|
}
|
|
|
|
|
2018-12-30 06:00:57 +01:00
|
|
|
for (let i = 5; i < 100; i += 5) {
|
2018-09-26 13:19:35 +02:00
|
|
|
const color = primary.clone().lighten(i);
|
|
|
|
props['primaryLighten' + i] = genValue(color);
|
|
|
|
}
|
|
|
|
|
2018-12-30 06:00:57 +01:00
|
|
|
for (let i = 5; i < 100; i += 5) {
|
2018-09-26 13:19:35 +02:00
|
|
|
const color = primary.clone().darken(i);
|
|
|
|
props['primaryDarken' + i] = genValue(color);
|
|
|
|
}
|
|
|
|
|
2018-09-26 11:59:37 +02:00
|
|
|
return props;
|
|
|
|
}
|
|
|
|
|
2018-09-26 13:19:35 +02:00
|
|
|
function genValue(c: tinycolor.Instance): string {
|
|
|
|
return c.toRgbString();
|
2018-09-26 11:59:37 +02:00
|
|
|
}
|