aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FrontEnd/.eslintrc.cjs2
-rw-r--r--FrontEnd/package.json2
-rw-r--r--FrontEnd/pnpm-lock.yaml107
-rw-r--r--FrontEnd/tools/palette.ts271
-rw-r--r--FrontEnd/tools/tsconfig.json21
5 files changed, 396 insertions, 7 deletions
diff --git a/FrontEnd/.eslintrc.cjs b/FrontEnd/.eslintrc.cjs
index a9cd8e03..6fcccd3e 100644
--- a/FrontEnd/.eslintrc.cjs
+++ b/FrontEnd/.eslintrc.cjs
@@ -13,7 +13,7 @@ module.exports = {
plugins: ["@typescript-eslint", "prettier", "react", "react-hooks"],
parser: "@typescript-eslint/parser",
parserOptions: {
- project: true,
+ project: ["./tsconfig.json", "tools/tsconfig.json"],
tsconfigRootDir: __dirname
},
settings: {
diff --git a/FrontEnd/package.json b/FrontEnd/package.json
index 7f438f0e..850543ee 100644
--- a/FrontEnd/package.json
+++ b/FrontEnd/package.json
@@ -43,7 +43,6 @@
"devDependencies": {
"@parcel/packager-raw-url": "2.9.3",
"@parcel/transformer-webmanifest": "2.9.3",
- "@tsconfig/vite-react": "^2.0.0",
"@types/color": "^3.0.3",
"@types/lodash": "^4.14.195",
"@types/marked": "^5.0.0",
@@ -65,6 +64,7 @@
"parcel": "latest",
"prettier": "^3.0.0",
"process": "^0.11.10",
+ "ts-node": "latest",
"typescript": "^5.1.6"
}
} \ No newline at end of file
diff --git a/FrontEnd/pnpm-lock.yaml b/FrontEnd/pnpm-lock.yaml
index d4a2962c..0ee3d598 100644
--- a/FrontEnd/pnpm-lock.yaml
+++ b/FrontEnd/pnpm-lock.yaml
@@ -88,9 +88,6 @@ devDependencies:
'@parcel/transformer-webmanifest':
specifier: 2.9.3
version: 2.9.3(@parcel/core@2.9.3)
- '@tsconfig/vite-react':
- specifier: ^2.0.0
- version: 2.0.0
'@types/color':
specifier: ^3.0.3
version: 3.0.3
@@ -154,6 +151,9 @@ devDependencies:
process:
specifier: ^0.11.10
version: 0.11.10
+ ts-node:
+ specifier: latest
+ version: 10.9.1(@types/node@20.4.1)(typescript@5.1.6)
typescript:
specifier: ^5.1.6
version: 5.1.6
@@ -201,6 +201,13 @@ packages:
regenerator-runtime: 0.13.11
dev: false
+ /@cspotcode/source-map-support@0.8.1:
+ resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.9
+ dev: true
+
/@eslint-community/eslint-utils@4.4.0(eslint@8.44.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -266,6 +273,22 @@ packages:
react: 18.2.0
dev: false
+ /@jridgewell/resolve-uri@3.1.1:
+ resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==}
+ engines: {node: '>=6.0.0'}
+ dev: true
+
+ /@jridgewell/sourcemap-codec@1.4.15:
+ resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+ dev: true
+
+ /@jridgewell/trace-mapping@0.3.9:
+ resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.1
+ '@jridgewell/sourcemap-codec': 1.4.15
+ dev: true
+
/@lezer/common@0.15.12:
resolution: {integrity: sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==}
dev: true
@@ -1357,8 +1380,20 @@ packages:
engines: {node: '>=10.13.0'}
dev: true
- /@tsconfig/vite-react@2.0.0:
- resolution: {integrity: sha512-erT+k9yzjRYnqRn6Fmvz+Y8+AtE+/YE954frGGwwit2ifsoWzRzYaOTlGj9/z0xJyYiaKNnNiFhid312QdC4rw==}
+ /@tsconfig/node10@1.0.9:
+ resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
+ dev: true
+
+ /@tsconfig/node12@1.0.11:
+ resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
+ dev: true
+
+ /@tsconfig/node14@1.0.3:
+ resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
+ dev: true
+
+ /@tsconfig/node16@1.0.4:
+ resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
dev: true
/@types/color-convert@2.0.0:
@@ -1597,6 +1632,11 @@ packages:
acorn: 8.10.0
dev: true
+ /acorn-walk@8.2.0:
+ resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
/acorn@8.10.0:
resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
engines: {node: '>=0.4.0'}
@@ -1631,6 +1671,10 @@ packages:
color-convert: 2.0.1
dev: true
+ /arg@4.1.3:
+ resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
+ dev: true
+
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
@@ -1886,6 +1930,10 @@ packages:
path-type: 4.0.0
dev: true
+ /create-require@1.1.1:
+ resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
+ dev: true
+
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@@ -1967,6 +2015,11 @@ packages:
hasBin: true
dev: true
+ /diff@4.0.2:
+ resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
+ engines: {node: '>=0.3.1'}
+ dev: true
+
/dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
@@ -2989,6 +3042,10 @@ packages:
yallist: 4.0.0
dev: true
+ /make-error@1.3.6:
+ resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
+ dev: true
+
/marked@5.1.1:
resolution: {integrity: sha512-bTmmGdEINWmOMDjnPWDxGPQ4qkDLeYorpYbEtFOXzOruTwUE671q4Guiuchn4N8h/v6NGd7916kXsm3Iz4iUSg==}
engines: {node: '>= 18'}
@@ -3789,6 +3846,37 @@ packages:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
dev: false
+ /ts-node@10.9.1(@types/node@20.4.1)(typescript@5.1.6):
+ resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
+ hasBin: true
+ peerDependencies:
+ '@swc/core': '>=1.2.50'
+ '@swc/wasm': '>=1.2.50'
+ '@types/node': '*'
+ typescript: '>=2.7'
+ peerDependenciesMeta:
+ '@swc/core':
+ optional: true
+ '@swc/wasm':
+ optional: true
+ dependencies:
+ '@cspotcode/source-map-support': 0.8.1
+ '@tsconfig/node10': 1.0.9
+ '@tsconfig/node12': 1.0.11
+ '@tsconfig/node14': 1.0.3
+ '@tsconfig/node16': 1.0.4
+ '@types/node': 20.4.1
+ acorn: 8.10.0
+ acorn-walk: 8.2.0
+ arg: 4.1.3
+ create-require: 1.1.1
+ diff: 4.0.2
+ make-error: 1.3.6
+ typescript: 5.1.6
+ v8-compile-cache-lib: 3.0.1
+ yn: 3.1.1
+ dev: true
+
/tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
@@ -3875,6 +3963,10 @@ packages:
engines: {node: '>= 4'}
dev: true
+ /v8-compile-cache-lib@3.0.1:
+ resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
+ dev: true
+
/void-elements@3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
@@ -3962,6 +4054,11 @@ packages:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: true
+ /yn@3.1.1:
+ resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
+ engines: {node: '>=6'}
+ dev: true
+
/yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
diff --git a/FrontEnd/tools/palette.ts b/FrontEnd/tools/palette.ts
new file mode 100644
index 00000000..7b047ce1
--- /dev/null
+++ b/FrontEnd/tools/palette.ts
@@ -0,0 +1,271 @@
+#!/usr/bin/env ts-node
+
+/**
+ * Color variable name scheme:
+ * has variant: --[prefix]-[name]-[variant]-color: [color];
+ * no variant: --[prefix]-[name]-color: [color];
+ * Variant scheme:
+ * [variant-prefix][level]
+ * eg. --cru-primary-color: [color]; --cru-primary-l1-color: [color];
+ */
+
+class HslColor {
+ constructor(
+ public h: number,
+ public s: number,
+ public l: number,
+ ) {}
+
+ lighter(level: number): HslColor {
+ return new HslColor(this.h, this.s, this.l + level * 10);
+ }
+
+ darker(level: number): HslColor {
+ return new HslColor(this.h, this.s, this.l - level * 10);
+ }
+
+ toString(): string {
+ return `hsl(${this.h} ${this.s}% ${this.l}%)`;
+ }
+}
+
+class CssVarColor {
+ constructor(
+ public name: string,
+ public cssVar: string,
+ ) {}
+
+ toString(): string {
+ return `var(--${this.cssVar})`;
+ }
+}
+
+class VariantColor {
+ constructor(
+ public color: HslColor,
+ public variant?: string | null,
+ ) {}
+
+ toCssString(prefix: string, name: string): string {
+ const variantPart = this.variant == null ? "" : `-${this.variant}`;
+ return `--${prefix}-${name}${variantPart}-color: ${this.color.toString()};`;
+ }
+}
+
+type LightnessVariantType = "lighter" | "darker";
+
+interface LightnessVariant {
+ prefix: string;
+ type: LightnessVariantType;
+}
+
+function generateLightnessVariantColors(
+ baseColor: HslColor,
+ lightnessVariant: LightnessVariant,
+ levels: number,
+): VariantColor[] {
+ const result: VariantColor[] = [];
+
+ for (let i = 1; i <= levels; i++) {
+ const color =
+ lightnessVariant.type === "lighter"
+ ? baseColor.lighter(i)
+ : baseColor.darker(i);
+ const colorVariant = `${lightnessVariant.prefix}${i}`;
+ result.push(new VariantColor(color, colorVariant));
+ }
+
+ return result;
+}
+
+type ColorMode = "light" | "dark";
+
+const themeVariantPrefixes = ["l", "d", "f", "b"] as const;
+
+type LightnessVariants = {
+ prefix: (typeof themeVariantPrefixes)[number];
+ type: LightnessVariantType;
+}[];
+
+function generateThemeColorLightnessVariants(
+ mode: ColorMode,
+): LightnessVariants {
+ return [
+ {
+ prefix: "l",
+ type: "lighter",
+ },
+ {
+ prefix: "d",
+ type: "darker",
+ },
+ {
+ prefix: "f",
+ type: mode === "light" ? "lighter" : "darker",
+ },
+ {
+ prefix: "b",
+ type: mode === "light" ? "darker" : "lighter",
+ },
+ ];
+}
+
+class ColorGroup {
+ constructor(
+ public name: string,
+ public baseColor: HslColor,
+ ) {}
+
+ generateVariantColors(
+ lightnessVariants: LightnessVariant[],
+ levels = 3,
+ ): VariantColor[] {
+ const result: VariantColor[] = [new VariantColor(this.baseColor)];
+
+ for (const lightnessVariant of lightnessVariants) {
+ result.push(
+ ...generateLightnessVariantColors(
+ this.baseColor,
+ lightnessVariant,
+ levels,
+ ),
+ );
+ }
+
+ return result;
+ }
+}
+
+class ThemeColorGroup extends ColorGroup {
+ constructor(name: string, baseColor: HslColor) {
+ super(name, baseColor);
+ }
+
+ generateColors(mode: ColorMode): VariantColor[] {
+ return super.generateVariantColors(
+ generateThemeColorLightnessVariants(mode),
+ );
+ }
+
+ generateCss(prefix: string, mode: ColorMode): string {
+ return this.generateColors(mode)
+ .map((c) => c.toCssString(prefix, this.name))
+ .join("\n");
+ }
+}
+
+class VarColorGroup {
+ constructor(
+ public name: string,
+ public varName: string,
+ ) {}
+
+ generateCss(
+ prefix: string,
+ variantPrefixes = themeVariantPrefixes,
+ levels = 3,
+ ): string {
+ const vs: string[] = [];
+ for (const v of variantPrefixes) {
+ for (let l = 1; l <= levels; l++) {
+ vs.push(`${v}${l}`);
+ }
+ }
+ let result = vs
+ .map(
+ (v) =>
+ `--${prefix}-${this.name}-${v}-color: var(--${prefix}-${this.varName}-${v}-color);`,
+ )
+ .join("\n");
+ result = `--${prefix}-${this.name}-color: var(--${prefix}-${this.varName}-color);\n${result}`;
+ return result;
+ }
+}
+
+const themeColorNames = [
+ "primary",
+ "secondary",
+ "tertiary",
+ "danger",
+ "success",
+] as const;
+
+type ThemeColorNames = (typeof themeColorNames)[number];
+
+type ThemeColors = {
+ [key in ThemeColorNames]: HslColor;
+};
+
+// Config region begin
+const prefix = "cru";
+
+const themeColors: ThemeColors = {
+ primary: new HslColor(210, 100, 50),
+ secondary: new HslColor(40, 100, 50),
+ tertiary: new HslColor(160, 100, 50),
+ danger: new HslColor(0, 100, 50),
+ success: new HslColor(120, 100, 50),
+};
+
+// Config region end
+
+let output = "";
+
+function indentText(
+ text: string,
+ level: number,
+ indentWidth = 2,
+ appendNewlines = 1,
+): string {
+ const lines = text.split("\n");
+ const indent = " ".repeat(level * indentWidth);
+ return (
+ lines
+ .map((line) => (line.length === 0 ? "" : `${indent}${line}`))
+ .join("\n") + "\n".repeat(appendNewlines)
+ );
+}
+
+function print(text: string, indent = 0, appendNewlines = 1) {
+ output += indentText(text, indent, 2, appendNewlines);
+}
+
+function generateThemeColorCss(mode: ColorMode): string {
+ let output = "";
+ for (const name of themeColorNames) {
+ const colorGroup = new ThemeColorGroup(name, themeColors[name]);
+ output += colorGroup.generateCss(prefix, mode);
+ }
+ return output;
+}
+
+function generateThemeColorAliasCss(): string {
+ let result = "";
+ for (const name of themeColorNames) {
+ const varColorGroup = new VarColorGroup("theme", name);
+ result += `.${prefix}-${name} {\n${indentText(
+ varColorGroup.generateCss(prefix),
+ 1,
+ )}\n}\n`;
+ }
+ return result;
+}
+
+function main() {
+ print("/* Generated by palette.ts */\n");
+
+ print(":root {");
+ print(generateThemeColorCss("light"), 1);
+ print("}\n");
+
+ print("@media (prefers-color-scheme: dark) {");
+ print(":root {", 1);
+ print(generateThemeColorCss("dark"), 2);
+ print("}", 1);
+ print("}\n");
+
+ print(generateThemeColorAliasCss());
+}
+
+main();
+process.stdout.write(output);
diff --git a/FrontEnd/tools/tsconfig.json b/FrontEnd/tools/tsconfig.json
new file mode 100644
index 00000000..8c9b3c47
--- /dev/null
+++ b/FrontEnd/tools/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ // This is an alias to @tsconfig/node16: https://github.com/tsconfig/bases
+ "extends": "ts-node/node16/tsconfig.json",
+ // Most ts-node options can be specified here using their programmatic names.
+ "ts-node": {
+ // It is faster to skip typechecking.
+ // Remove if you want ts-node to do typechecking.
+ "transpileOnly": true,
+ "compilerOptions": {
+ // compilerOptions specified here will override those declared below,
+ // but *only* in ts-node. Useful if you want ts-node and tsc to use
+ // different options with a single tsconfig.json.
+ }
+ },
+ "compilerOptions": {
+ // typescript options here
+ },
+ "include": [
+ "**/*"
+ ]
+} \ No newline at end of file