iceshrimp-161sh/packages/client/src/scripts/theme-editor.ts
ThatOneCalculator 2aab2de38d refactor: 🎨 rome
2023-01-12 20:40:33 -08:00

101 lines
2.4 KiB
TypeScript

import { v4 as uuid } from "uuid";
import { themeProps, Theme } from "./theme";
export type Default = null;
export type Color = string;
export type FuncName = "alpha" | "darken" | "lighten";
export type Func = { type: "func"; name: FuncName; arg: number; value: string };
export type RefProp = { type: "refProp"; key: string };
export type RefConst = { type: "refConst"; key: string };
export type Css = { type: "css"; value: string };
export type ThemeValue = Color | Func | RefProp | RefConst | Css | Default;
export type ThemeViewModel = [string, ThemeValue][];
export const fromThemeString = (str?: string): ThemeValue => {
if (!str) return null;
if (str.startsWith(":")) {
const parts = str.slice(1).split("<");
const name = parts[0] as FuncName;
const arg = parseFloat(parts[1]);
const value = parts[2].startsWith("@") ? parts[2].slice(1) : "";
return { type: "func", name, arg, value };
} else if (str.startsWith("@")) {
return {
type: "refProp",
key: str.slice(1),
};
} else if (str.startsWith("$")) {
return {
type: "refConst",
key: str.slice(1),
};
} else if (str.startsWith('"')) {
return {
type: "css",
value: str.substr(1).trim(),
};
} else {
return str;
}
};
export const toThemeString = (
value: Color | Func | RefProp | RefConst | Css,
) => {
if (typeof value === "string") return value;
switch (value.type) {
case "func":
return `:${value.name}<${value.arg}<@${value.value}`;
case "refProp":
return `@${value.key}`;
case "refConst":
return `$${value.key}`;
case "css":
return `" ${value.value}`;
}
};
export const convertToMisskeyTheme = (
vm: ThemeViewModel,
name: string,
desc: string,
author: string,
base: "dark" | "light",
): Theme => {
const props = {} as { [key: string]: string };
for (const [key, value] of vm) {
if (value === null) continue;
props[key] = toThemeString(value);
}
return {
id: uuid(),
name,
desc,
author,
props,
base,
};
};
export const convertToViewModel = (theme: Theme): ThemeViewModel => {
const vm: ThemeViewModel = [];
// プロパティの登録
vm.push(
...themeProps.map(
(key) => [key, fromThemeString(theme.props[key])] as [string, ThemeValue],
),
);
// 定数の登録
const consts = Object.keys(theme.props)
.filter((k) => k.startsWith("$"))
.map((k) => [k, fromThemeString(theme.props[k])] as [string, ThemeValue]);
vm.push(...consts);
return vm;
};