From 810185b8df1fd191cd4a5e7eb92e1986000880b1 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 14 Jul 2023 00:30:17 +0800 Subject: ... --- FrontEnd/.eslintrc.cjs | 2 +- FrontEnd/package.json | 2 +- FrontEnd/pnpm-lock.yaml | 107 ++++++++++++++++- FrontEnd/tools/palette.ts | 271 +++++++++++++++++++++++++++++++++++++++++++ FrontEnd/tools/tsconfig.json | 21 ++++ 5 files changed, 396 insertions(+), 7 deletions(-) create mode 100644 FrontEnd/tools/palette.ts create mode 100644 FrontEnd/tools/tsconfig.json 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 -- cgit v1.2.3 From c833176b638eeb1cdc8b30d4aef632a25ede3777 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 14 Jul 2023 23:01:33 +0800 Subject: ... --- FrontEnd/.eslintrc.cjs | 24 -- FrontEnd/.eslintrc.js | 24 ++ FrontEnd/package.json | 5 +- FrontEnd/pnpm-lock.yaml | 9 +- FrontEnd/src/common.ts | 10 + FrontEnd/src/index.css | 3 +- FrontEnd/src/index.tsx | 7 +- FrontEnd/src/palette.ts | 167 --------- FrontEnd/src/views/common/alert/alert.css | 2 +- FrontEnd/src/views/common/button/Button.css | 10 +- FrontEnd/src/views/common/button/Button.tsx | 5 +- FrontEnd/src/views/common/button/FlatButton.tsx | 5 +- FrontEnd/src/views/common/button/IconButton.tsx | 4 +- FrontEnd/src/views/common/button/LoadingButton.tsx | 5 +- FrontEnd/src/views/common/index.css | 216 +---------- FrontEnd/src/views/common/theme.css | 244 +++++++++++++ FrontEnd/tools/palette.ts | 271 -------------- FrontEnd/tools/theme-generator.ts | 403 +++++++++++++++++++++ FrontEnd/tools/tsconfig.json | 4 +- 19 files changed, 711 insertions(+), 707 deletions(-) delete mode 100644 FrontEnd/.eslintrc.cjs create mode 100644 FrontEnd/.eslintrc.js delete mode 100644 FrontEnd/src/palette.ts create mode 100644 FrontEnd/src/views/common/theme.css delete mode 100644 FrontEnd/tools/palette.ts create mode 100644 FrontEnd/tools/theme-generator.ts diff --git a/FrontEnd/.eslintrc.cjs b/FrontEnd/.eslintrc.cjs deleted file mode 100644 index 6fcccd3e..00000000 --- a/FrontEnd/.eslintrc.cjs +++ /dev/null @@ -1,24 +0,0 @@ -module.exports = { - root: true, - extends: [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:react-hooks/recommended", - "plugin:react/jsx-runtime", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - "prettier", - ], - plugins: ["@typescript-eslint", "prettier", "react", "react-hooks"], - parser: "@typescript-eslint/parser", - parserOptions: { - project: ["./tsconfig.json", "tools/tsconfig.json"], - tsconfigRootDir: __dirname - }, - settings: { - react: { - version: "detect", - }, - }, -}; diff --git a/FrontEnd/.eslintrc.js b/FrontEnd/.eslintrc.js new file mode 100644 index 00000000..6fcccd3e --- /dev/null +++ b/FrontEnd/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + root: true, + extends: [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:react/jsx-runtime", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "prettier", + ], + plugins: ["@typescript-eslint", "prettier", "react", "react-hooks"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: ["./tsconfig.json", "tools/tsconfig.json"], + tsconfigRootDir: __dirname + }, + settings: { + react: { + version: "detect", + }, + }, +}; diff --git a/FrontEnd/package.json b/FrontEnd/package.json index 850543ee..268e9636 100644 --- a/FrontEnd/package.json +++ b/FrontEnd/package.json @@ -1,8 +1,6 @@ { "name": "timeline", "version": "0.4.0", - "private": true, - "type": "module", "source": "index.html", "scripts": { "start": "parcel --port 5678", @@ -43,6 +41,7 @@ "devDependencies": { "@parcel/packager-raw-url": "2.9.3", "@parcel/transformer-webmanifest": "2.9.3", + "@tsconfig/node20": "^1.0.2", "@types/color": "^3.0.3", "@types/lodash": "^4.14.195", "@types/marked": "^5.0.0", @@ -64,7 +63,7 @@ "parcel": "latest", "prettier": "^3.0.0", "process": "^0.11.10", - "ts-node": "latest", + "ts-node": "^10.9.1", "typescript": "^5.1.6" } } \ No newline at end of file diff --git a/FrontEnd/pnpm-lock.yaml b/FrontEnd/pnpm-lock.yaml index 0ee3d598..e57ef2f4 100644 --- a/FrontEnd/pnpm-lock.yaml +++ b/FrontEnd/pnpm-lock.yaml @@ -88,6 +88,9 @@ devDependencies: '@parcel/transformer-webmanifest': specifier: 2.9.3 version: 2.9.3(@parcel/core@2.9.3) + '@tsconfig/node20': + specifier: ^1.0.2 + version: 1.0.2 '@types/color': specifier: ^3.0.3 version: 3.0.3 @@ -152,7 +155,7 @@ devDependencies: specifier: ^0.11.10 version: 0.11.10 ts-node: - specifier: latest + specifier: ^10.9.1 version: 10.9.1(@types/node@20.4.1)(typescript@5.1.6) typescript: specifier: ^5.1.6 @@ -1396,6 +1399,10 @@ packages: resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} dev: true + /@tsconfig/node20@1.0.2: + resolution: {integrity: sha512-pw0MmECiSTbBfIlT0x3iQLuJ8s3i2mwYoGxJ3vzqTNMdc4nO2VeqfCOQ/doGFa8iyPlqmBd98/5pBctWz7uN2A==} + dev: true + /@types/color-convert@2.0.0: resolution: {integrity: sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==} dependencies: diff --git a/FrontEnd/src/common.ts b/FrontEnd/src/common.ts index 965f9933..6dcd2a9e 100644 --- a/FrontEnd/src/common.ts +++ b/FrontEnd/src/common.ts @@ -8,3 +8,13 @@ export const highlightTimelineUsername = "crupest"; export type { I18nText } from "./i18n"; export { c, convertI18nText } from "./i18n"; export { default as useC } from "./utilities/hooks/use-c"; + +export const themeColors = [ + "primary", + "secondary", + "tertiary", + "danger", + "success", +] as const; + +export type ThemeColor = (typeof themeColors)[number]; diff --git a/FrontEnd/src/index.css b/FrontEnd/src/index.css index 419ccb8c..2faecfae 100644 --- a/FrontEnd/src/index.css +++ b/FrontEnd/src/index.css @@ -75,6 +75,7 @@ i { .markdown-container { white-space: initial; } + .markdown-container img { max-height: 200px; max-width: 100%; @@ -82,4 +83,4 @@ i { a { text-decoration: none; -} +} \ No newline at end of file diff --git a/FrontEnd/src/index.tsx b/FrontEnd/src/index.tsx index ba61d357..64d39cd5 100644 --- a/FrontEnd/src/index.tsx +++ b/FrontEnd/src/index.tsx @@ -1,14 +1,9 @@ -import "regenerator-runtime"; -import "core-js/modules/es.promise"; -import "core-js/modules/es.array.iterator"; - import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import "./index.css"; import "./i18n"; -import "./palette"; import App from "./App"; @@ -18,5 +13,5 @@ const root = createRoot(container!); root.render( - + , ); diff --git a/FrontEnd/src/palette.ts b/FrontEnd/src/palette.ts deleted file mode 100644 index d06f9b19..00000000 --- a/FrontEnd/src/palette.ts +++ /dev/null @@ -1,167 +0,0 @@ -import Color from "color"; -import { BehaviorSubject, Observable } from "rxjs"; - -import refreshAnimation from "./utilities/refreshAnimation"; - -function lightenBy(color: Color, ratio: number): Color { - const lightness = color.lightness(); - return color.lightness(lightness + (100 - lightness) * ratio); -} - -function darkenBy(color: Color, ratio: number): Color { - const lightness = color.lightness(); - return color.lightness(lightness - lightness * ratio); -} - -export interface PaletteColor { - color: string; - l1: string; - l2: string; - l3: string; - d1: string; - d2: string; - d3: string; - f1: string; - f2: string; - f3: string; - r1: string; - r2: string; - r3: string; - t: string; - t1: string; - t2: string; - t3: string; - [key: string]: string; -} - -const paletteColorList = [ - "primary", - "primary-enhance", - "secondary", - "danger", - "success", -] as const; - -export type PaletteColorType = (typeof paletteColorList)[number]; - -export type Palette = Record; - -export function generatePaletteColor(color: string): PaletteColor { - const c = Color(color); - const light = c.lightness() > 60; - const l1 = lightenBy(c, 0.1).rgb().toString(); - const l2 = lightenBy(c, 0.2).rgb().toString(); - const l3 = lightenBy(c, 0.3).rgb().toString(); - const d1 = darkenBy(c, 0.1).rgb().toString(); - const d2 = darkenBy(c, 0.2).rgb().toString(); - const d3 = darkenBy(c, 0.3).rgb().toString(); - const f1 = light ? l1 : d1; - const f2 = light ? l2 : d2; - const f3 = light ? l3 : d3; - const r1 = light ? d1 : l1; - const r2 = light ? d2 : l2; - const r3 = light ? d3 : l3; - const _t = light ? Color("black") : Color("white"); - const t = _t.rgb().toString(); - const _b = light ? lightenBy : darkenBy; - const t1 = _b(_t, 0.1).rgb().toString(); - const t2 = _b(_t, 0.2).rgb().toString(); - const t3 = _b(_t, 0.3).rgb().toString(); - - return { - color: c.rgb().toString(), - l1, - l2, - l3, - d1, - d2, - d3, - f1, - f2, - f3, - r1, - r2, - r3, - t, - t1, - t2, - t3, - }; -} - -export function generatePalette(options: { - primary: string; - primaryEnhance?: string; - secondary?: string; -}): Palette { - const { primary, primaryEnhance, secondary } = options; - const p = Color(primary); - const pe = - primaryEnhance == null - ? lightenBy(p, 0.3).saturate(0.3) - : Color(primaryEnhance); - const s = secondary == null ? Color("gray") : Color(secondary); - - return { - primary: generatePaletteColor(p.toString()), - "primary-enhance": generatePaletteColor(pe.toString()), - secondary: generatePaletteColor(s.toString()), - danger: generatePaletteColor("red"), - success: generatePaletteColor("green"), - }; -} - -export function generatePaletteCSS(palette: Palette): string { - const colors: [string, string][] = []; - for (const colorType of paletteColorList) { - const paletteColor = palette[colorType]; - for (const variant in paletteColor) { - let key = `--cru-${colorType}`; - if (variant !== "color") key += `-${variant}`; - key += "-color"; - colors.push([key, paletteColor[variant]]); - } - } - - return `:root {${colors - .map(([key, color]) => `${key} : ${color};`) - .join("")}}`; -} - -const paletteSubject: BehaviorSubject = - new BehaviorSubject( - generatePalette({ primary: "rgb(0, 123, 255)" }) - ); - -export const palette$: Observable = - paletteSubject.asObservable(); - -palette$.subscribe((palette) => { - const styleTagId = "timeline-palette-css"; - if (palette != null) { - let styleTag = document.getElementById(styleTagId); - if (styleTag == null) { - styleTag = document.createElement("style"); - styleTag.id = styleTagId; - document.head.append(styleTag); - } - styleTag.innerHTML = generatePaletteCSS(palette); - } else { - const styleTag = document.getElementById(styleTagId); - if (styleTag != null) { - styleTag.parentElement?.removeChild(styleTag); - } - } - - refreshAnimation(); -}); - -export function setPalette(palette: Palette): () => void { - const old = paletteSubject.value; - - paletteSubject.next(palette); - - return () => { - paletteSubject.next(old); - }; -} diff --git a/FrontEnd/src/views/common/alert/alert.css b/FrontEnd/src/views/common/alert/alert.css index fc15e3cb..83e1af28 100644 --- a/FrontEnd/src/views/common/alert/alert.css +++ b/FrontEnd/src/views/common/alert/alert.css @@ -7,7 +7,7 @@ border-radius: 5px; border: var(--cru-theme-color) 1px solid; color: var(--cru-theme-t-color); - background-color: var(--cru-theme-r1-color); + background-color: var(--cru-theme-b1-color); display: flex; overflow: hidden; diff --git a/FrontEnd/src/views/common/button/Button.css b/FrontEnd/src/views/common/button/Button.css index c34176f6..406d70d2 100644 --- a/FrontEnd/src/views/common/button/Button.css +++ b/FrontEnd/src/views/common/button/Button.css @@ -1,5 +1,5 @@ .cru-button:not(.outline) { - color: var(--cru-theme-t-color); + color: var(--cru-text-color); cursor: pointer; padding: 0.2em 0.5em; border-radius: 0.2em; @@ -17,7 +17,7 @@ } .cru-button:not(.outline):disabled { - background-color: var(--cru-disable-color); + background-color: var(--cru-disabled-color); cursor: auto; } @@ -44,8 +44,8 @@ } .cru-button.outline:disabled { - color: var(--cru-disable-color); - border-color: var(--cru-disable-color); + color: var(--cru-disabled-color); + border-color: var(--cru-disabled-color); background-color: white; cursor: auto; -} +} \ No newline at end of file diff --git a/FrontEnd/src/views/common/button/Button.tsx b/FrontEnd/src/views/common/button/Button.tsx index be605328..53f41bc1 100644 --- a/FrontEnd/src/views/common/button/Button.tsx +++ b/FrontEnd/src/views/common/button/Button.tsx @@ -1,13 +1,12 @@ import { ComponentPropsWithoutRef, Ref } from "react"; import classNames from "classnames"; -import { I18nText, useC } from "@/common"; -import { PaletteColorType } from "@/palette"; +import { I18nText, useC, ThemeColor } from "@/common"; import "./Button.css"; interface ButtonProps extends ComponentPropsWithoutRef<"button"> { - color?: PaletteColorType; + color?: ThemeColor; text?: I18nText; outline?: boolean; buttonRef?: Ref | null; diff --git a/FrontEnd/src/views/common/button/FlatButton.tsx b/FrontEnd/src/views/common/button/FlatButton.tsx index 49912b68..a5354670 100644 --- a/FrontEnd/src/views/common/button/FlatButton.tsx +++ b/FrontEnd/src/views/common/button/FlatButton.tsx @@ -1,13 +1,12 @@ import { ComponentPropsWithoutRef, Ref } from "react"; import classNames from "classnames"; -import { I18nText, useC } from "@/common"; -import { PaletteColorType } from "@/palette"; +import { I18nText, useC, ThemeColor } from "@/common"; import "./FlatButton.css"; interface FlatButtonProps extends ComponentPropsWithoutRef<"button"> { - color?: PaletteColorType; + color?: ThemeColor; text?: I18nText; buttonRef?: Ref | null; } diff --git a/FrontEnd/src/views/common/button/IconButton.tsx b/FrontEnd/src/views/common/button/IconButton.tsx index 652a8b09..0ff9541a 100644 --- a/FrontEnd/src/views/common/button/IconButton.tsx +++ b/FrontEnd/src/views/common/button/IconButton.tsx @@ -1,13 +1,13 @@ import { ComponentPropsWithoutRef } from "react"; import classNames from "classnames"; -import { PaletteColorType } from "@/palette"; +import { ThemeColor } from "@/common"; import "./IconButton.css"; interface IconButtonProps extends ComponentPropsWithoutRef<"i"> { icon: string; - color?: PaletteColorType; + color?: ThemeColor; large?: boolean; } diff --git a/FrontEnd/src/views/common/button/LoadingButton.tsx b/FrontEnd/src/views/common/button/LoadingButton.tsx index fceaec27..c4cafc0c 100644 --- a/FrontEnd/src/views/common/button/LoadingButton.tsx +++ b/FrontEnd/src/views/common/button/LoadingButton.tsx @@ -2,13 +2,12 @@ import * as React from "react"; import classNames from "classnames"; import { useTranslation } from "react-i18next"; -import { convertI18nText, I18nText } from "@/common"; -import { PaletteColorType } from "@/palette"; +import { convertI18nText, I18nText, ThemeColor } from "@/common"; import Spinner from "../Spinner"; interface LoadingButtonProps extends React.ComponentPropsWithoutRef<"button"> { - color?: PaletteColorType; + color?: ThemeColor; text?: I18nText; loading?: boolean; } diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css index 111a3ec0..06f2556b 100644 --- a/FrontEnd/src/views/common/index.css +++ b/FrontEnd/src/views/common/index.css @@ -1,218 +1,4 @@ -:root { - --cru-background-color: #f8f9fa; - --cru-background-1-color: #e9ecef; - --cru-background-2-color: #dee2e6; - - --cru-disable-color: #ced4da; - - /* - --cru-primary-color: rgb(0, 123, 255); - --cru-primary-l1-color: rgb(26, 136, 255); - --cru-primary-l2-color: rgb(51, 149, 255); - --cru-primary-l3-color: rgb(77, 163, 255); - --cru-primary-d1-color: rgb(0, 111, 230); - --cru-primary-d2-color: rgb(0, 98, 204); - --cru-primary-d3-color: rgb(0, 86, 179); - --cru-primary-f1-color: rgb(0, 111, 230); - --cru-primary-f2-color: rgb(0, 98, 204); - --cru-primary-f3-color: rgb(0, 86, 179); - --cru-primary-r1-color: rgb(26, 136, 255); - --cru-primary-r2-color: rgb(51, 149, 255); - --cru-primary-r3-color: rgb(77, 163, 255); - --cru-primary-t-color: rgb(255, 255, 255); - --cru-primary-t1-color: rgb(230, 230, 230); - --cru-primary-t2-color: rgb(204, 204, 204); - --cru-primary-t3-color: rgb(179, 179, 179); - --cru-primary-enhance-color: rgb(77, 163, 255); - --cru-primary-enhance-l1-color: rgb(94, 172, 255); - --cru-primary-enhance-l2-color: rgb(112, 181, 255); - --cru-primary-enhance-l3-color: rgb(130, 190, 255); - --cru-primary-enhance-d1-color: rgb(43, 145, 255); - --cru-primary-enhance-d2-color: rgb(10, 128, 255); - --cru-primary-enhance-d3-color: rgb(0, 112, 232); - --cru-primary-enhance-f1-color: rgb(94, 172, 255); - --cru-primary-enhance-f2-color: rgb(112, 181, 255); - --cru-primary-enhance-f3-color: rgb(130, 190, 255); - --cru-primary-enhance-r1-color: rgb(43, 145, 255); - --cru-primary-enhance-r2-color: rgb(10, 128, 255); - --cru-primary-enhance-r3-color: rgb(0, 112, 232); - --cru-primary-enhance-t-color: rgb(0, 0, 0); - --cru-primary-enhance-t1-color: rgb(26, 26, 26); - --cru-primary-enhance-t2-color: rgb(51, 51, 51); - --cru-primary-enhance-t3-color: rgb(77, 77, 77); - --cru-secondary-color: rgb(128, 128, 128); - --cru-secondary-l1-color: rgb(141, 141, 141); - --cru-secondary-l2-color: rgb(153, 153, 153); - --cru-secondary-l3-color: rgb(166, 166, 166); - --cru-secondary-d1-color: rgb(115, 115, 115); - --cru-secondary-d2-color: rgb(102, 102, 102); - --cru-secondary-d3-color: rgb(90, 90, 90); - --cru-secondary-f1-color: rgb(115, 115, 115); - --cru-secondary-f2-color: rgb(102, 102, 102); - --cru-secondary-f3-color: rgb(90, 90, 90); - --cru-secondary-r1-color: rgb(141, 141, 141); - --cru-secondary-r2-color: rgb(153, 153, 153); - --cru-secondary-r3-color: rgb(166, 166, 166); - --cru-secondary-t-color: rgb(255, 255, 255); - --cru-secondary-t1-color: rgb(230, 230, 230); - --cru-secondary-t2-color: rgb(204, 204, 204); - --cru-secondary-t3-color: rgb(179, 179, 179); - --cru-danger-color: rgb(255, 0, 0); - --cru-danger-l1-color: rgb(255, 26, 26); - --cru-danger-l2-color: rgb(255, 51, 51); - --cru-danger-l3-color: rgb(255, 77, 77); - --cru-danger-d1-color: rgb(230, 0, 0); - --cru-danger-d2-color: rgb(204, 0, 0); - --cru-danger-d3-color: rgb(179, 0, 0); - --cru-danger-f1-color: rgb(230, 0, 0); - --cru-danger-f2-color: rgb(204, 0, 0); - --cru-danger-f3-color: rgb(179, 0, 0); - --cru-danger-r1-color: rgb(255, 26, 26); - --cru-danger-r2-color: rgb(255, 51, 51); - --cru-danger-r3-color: rgb(255, 77, 77); - --cru-danger-t-color: rgb(255, 255, 255); - --cru-danger-t1-color: rgb(230, 230, 230); - --cru-danger-t2-color: rgb(204, 204, 204); - --cru-danger-t3-color: rgb(179, 179, 179); - --cru-success-color: rgb(0, 128, 0); - --cru-success-l1-color: rgb(0, 166, 0); - --cru-success-l2-color: rgb(0, 204, 0); - --cru-success-l3-color: rgb(0, 243, 0); - --cru-success-d1-color: rgb(0, 115, 0); - --cru-success-d2-color: rgb(0, 102, 0); - --cru-success-d3-color: rgb(0, 90, 0); - --cru-success-f1-color: rgb(0, 115, 0); - --cru-success-f2-color: rgb(0, 102, 0); - --cru-success-f3-color: rgb(0, 90, 0); - --cru-success-r1-color: rgb(0, 166, 0); - --cru-success-r2-color: rgb(0, 204, 0); - --cru-success-r3-color: rgb(0, 243, 0); - --cru-success-t-color: rgb(255, 255, 255); - --cru-success-t1-color: rgb(230, 230, 230); - --cru-success-t2-color: rgb(204, 204, 204); - --cru-success-t3-color: rgb(179, 179, 179); - */ -} - -.cru-primary { - --cru-theme-color: var(--cru-primary-color); - --cru-theme-l1-color: var(--cru-primary-l1-color); - --cru-theme-l2-color: var(--cru-primary-l2-color); - --cru-theme-l3-color: var(--cru-primary-l3-color); - --cru-theme-d1-color: var(--cru-primary-d1-color); - --cru-theme-d2-color: var(--cru-primary-d2-color); - --cru-theme-d3-color: var(--cru-primary-d3-color); - --cru-theme-f1-color: var(--cru-primary-f1-color); - --cru-theme-f2-color: var(--cru-primary-f2-color); - --cru-theme-f3-color: var(--cru-primary-f3-color); - --cru-theme-r1-color: var(--cru-primary-r1-color); - --cru-theme-r2-color: var(--cru-primary-r2-color); - --cru-theme-r3-color: var(--cru-primary-r3-color); - --cru-theme-t-color: var(--cru-primary-t-color); - --cru-theme-t1-color: var(--cru-primary-t1-color); - --cru-theme-t2-color: var(--cru-primary-t2-color); - --cru-theme-t3-color: var(--cru-primary-t3-color); -} - -.cru-primary-enhance { - --cru-theme-color: var(--cru-primary-enhance-color); - --cru-theme-l1-color: var(--cru-primary-enhance-l1-color); - --cru-theme-l2-color: var(--cru-primary-enhance-l2-color); - --cru-theme-l3-color: var(--cru-primary-enhance-l3-color); - --cru-theme-d1-color: var(--cru-primary-enhance-d1-color); - --cru-theme-d2-color: var(--cru-primary-enhance-d2-color); - --cru-theme-d3-color: var(--cru-primary-enhance-d3-color); - --cru-theme-f1-color: var(--cru-primary-enhance-f1-color); - --cru-theme-f2-color: var(--cru-primary-enhance-f2-color); - --cru-theme-f3-color: var(--cru-primary-enhance-f3-color); - --cru-theme-r1-color: var(--cru-primary-enhance-r1-color); - --cru-theme-r2-color: var(--cru-primary-enhance-r2-color); - --cru-theme-r3-color: var(--cru-primary-enhance-r3-color); - --cru-theme-t-color: var(--cru-primary-enhance-t-color); - --cru-theme-t1-color: var(--cru-primary-enhance-t1-color); - --cru-theme-t2-color: var(--cru-primary-enhance-t2-color); - --cru-theme-t3-color: var(--cru-primary-enhance-t3-color); -} - -.cru-secondary { - --cru-theme-color: var(--cru-secondary-color); - --cru-theme-l1-color: var(--cru-secondary-l1-color); - --cru-theme-l2-color: var(--cru-secondary-l2-color); - --cru-theme-l3-color: var(--cru-secondary-l3-color); - --cru-theme-d1-color: var(--cru-secondary-d1-color); - --cru-theme-d2-color: var(--cru-secondary-d2-color); - --cru-theme-d3-color: var(--cru-secondary-d3-color); - --cru-theme-f1-color: var(--cru-secondary-f1-color); - --cru-theme-f2-color: var(--cru-secondary-f2-color); - --cru-theme-f3-color: var(--cru-secondary-f3-color); - --cru-theme-r1-color: var(--cru-secondary-r1-color); - --cru-theme-r2-color: var(--cru-secondary-r2-color); - --cru-theme-r3-color: var(--cru-secondary-r3-color); - --cru-theme-t-color: var(--cru-secondary-t-color); - --cru-theme-t1-color: var(--cru-secondary-t1-color); - --cru-theme-t2-color: var(--cru-secondary-t2-color); - --cru-theme-t3-color: var(--cru-secondary-t3-color); -} - -.cru-success { - --cru-theme-color: var(--cru-success-color); - --cru-theme-l1-color: var(--cru-success-l1-color); - --cru-theme-l2-color: var(--cru-success-l2-color); - --cru-theme-l3-color: var(--cru-success-l3-color); - --cru-theme-d1-color: var(--cru-success-d1-color); - --cru-theme-d2-color: var(--cru-success-d2-color); - --cru-theme-d3-color: var(--cru-success-d3-color); - --cru-theme-f1-color: var(--cru-success-f1-color); - --cru-theme-f2-color: var(--cru-success-f2-color); - --cru-theme-f3-color: var(--cru-success-f3-color); - --cru-theme-r1-color: var(--cru-success-r1-color); - --cru-theme-r2-color: var(--cru-success-r2-color); - --cru-theme-r3-color: var(--cru-success-r3-color); - --cru-theme-t-color: var(--cru-success-t-color); - --cru-theme-t1-color: var(--cru-success-t1-color); - --cru-theme-t2-color: var(--cru-success-t2-color); - --cru-theme-t3-color: var(--cru-success-t3-color); -} - -.cru-danger { - --cru-theme-color: var(--cru-danger-color); - --cru-theme-l1-color: var(--cru-danger-l1-color); - --cru-theme-l2-color: var(--cru-danger-l2-color); - --cru-theme-l3-color: var(--cru-danger-l3-color); - --cru-theme-d1-color: var(--cru-danger-d1-color); - --cru-theme-d2-color: var(--cru-danger-d2-color); - --cru-theme-d3-color: var(--cru-danger-d3-color); - --cru-theme-f1-color: var(--cru-danger-f1-color); - --cru-theme-f2-color: var(--cru-danger-f2-color); - --cru-theme-f3-color: var(--cru-danger-f3-color); - --cru-theme-r1-color: var(--cru-danger-r1-color); - --cru-theme-r2-color: var(--cru-danger-r2-color); - --cru-theme-r3-color: var(--cru-danger-r3-color); - --cru-theme-t-color: var(--cru-danger-t-color); - --cru-theme-t1-color: var(--cru-danger-t1-color); - --cru-theme-t2-color: var(--cru-danger-t2-color); - --cru-theme-t3-color: var(--cru-danger-t3-color); -} - -.cru-color-primary { - color: var(--cru-primary-color); -} - -.cru-color-primary-enhance { - color: var(--cru-primary-enhance-color); -} - -.cru-color-secondary { - color: var(--cru-secondary-color); -} - -.cru-color-success { - color: var(--cru-success-color); -} - -.cru-color-danger { - color: var(--cru-danger-color); -} +@import "./theme.css"; .cru-text-center { text-align: center; diff --git a/FrontEnd/src/views/common/theme.css b/FrontEnd/src/views/common/theme.css new file mode 100644 index 00000000..816bd3d1 --- /dev/null +++ b/FrontEnd/src/views/common/theme.css @@ -0,0 +1,244 @@ +/* Generated by theme-generator.ts */ + +:root { + --cru-primary-color: hsl(210 100% 50%); + --cru-primary-l1-color: hsl(210 100% 60%); + --cru-primary-l2-color: hsl(210 100% 70%); + --cru-primary-l3-color: hsl(210 100% 80%); + --cru-primary-d1-color: hsl(210 100% 40%); + --cru-primary-d2-color: hsl(210 100% 30%); + --cru-primary-d3-color: hsl(210 100% 20%); + --cru-primary-f1-color: hsl(210 100% 60%); + --cru-primary-f2-color: hsl(210 100% 70%); + --cru-primary-f3-color: hsl(210 100% 80%); + --cru-primary-b1-color: hsl(210 100% 40%); + --cru-primary-b2-color: hsl(210 100% 30%); + --cru-primary-b3-color: hsl(210 100% 20%); + --cru-secondary-color: hsl(40 100% 50%); + --cru-secondary-l1-color: hsl(40 100% 60%); + --cru-secondary-l2-color: hsl(40 100% 70%); + --cru-secondary-l3-color: hsl(40 100% 80%); + --cru-secondary-d1-color: hsl(40 100% 40%); + --cru-secondary-d2-color: hsl(40 100% 30%); + --cru-secondary-d3-color: hsl(40 100% 20%); + --cru-secondary-f1-color: hsl(40 100% 60%); + --cru-secondary-f2-color: hsl(40 100% 70%); + --cru-secondary-f3-color: hsl(40 100% 80%); + --cru-secondary-b1-color: hsl(40 100% 40%); + --cru-secondary-b2-color: hsl(40 100% 30%); + --cru-secondary-b3-color: hsl(40 100% 20%); + --cru-tertiary-color: hsl(160 100% 50%); + --cru-tertiary-l1-color: hsl(160 100% 60%); + --cru-tertiary-l2-color: hsl(160 100% 70%); + --cru-tertiary-l3-color: hsl(160 100% 80%); + --cru-tertiary-d1-color: hsl(160 100% 40%); + --cru-tertiary-d2-color: hsl(160 100% 30%); + --cru-tertiary-d3-color: hsl(160 100% 20%); + --cru-tertiary-f1-color: hsl(160 100% 60%); + --cru-tertiary-f2-color: hsl(160 100% 70%); + --cru-tertiary-f3-color: hsl(160 100% 80%); + --cru-tertiary-b1-color: hsl(160 100% 40%); + --cru-tertiary-b2-color: hsl(160 100% 30%); + --cru-tertiary-b3-color: hsl(160 100% 20%); + --cru-danger-color: hsl(0 100% 50%); + --cru-danger-l1-color: hsl(0 100% 60%); + --cru-danger-l2-color: hsl(0 100% 70%); + --cru-danger-l3-color: hsl(0 100% 80%); + --cru-danger-d1-color: hsl(0 100% 40%); + --cru-danger-d2-color: hsl(0 100% 30%); + --cru-danger-d3-color: hsl(0 100% 20%); + --cru-danger-f1-color: hsl(0 100% 60%); + --cru-danger-f2-color: hsl(0 100% 70%); + --cru-danger-f3-color: hsl(0 100% 80%); + --cru-danger-b1-color: hsl(0 100% 40%); + --cru-danger-b2-color: hsl(0 100% 30%); + --cru-danger-b3-color: hsl(0 100% 20%); + --cru-success-color: hsl(120 100% 50%); + --cru-success-l1-color: hsl(120 100% 60%); + --cru-success-l2-color: hsl(120 100% 70%); + --cru-success-l3-color: hsl(120 100% 80%); + --cru-success-d1-color: hsl(120 100% 40%); + --cru-success-d2-color: hsl(120 100% 30%); + --cru-success-d3-color: hsl(120 100% 20%); + --cru-success-f1-color: hsl(120 100% 60%); + --cru-success-f2-color: hsl(120 100% 70%); + --cru-success-f3-color: hsl(120 100% 80%); + --cru-success-b1-color: hsl(120 100% 40%); + --cru-success-b2-color: hsl(120 100% 30%); + --cru-success-b3-color: hsl(120 100% 20%); + --cru-text-color: hsl(0 0% 0%); + --cru-text-1-color: hsl(0 0% 10%); + --cru-text-2-color: hsl(0 0% 20%); + --cru-text-3-color: hsl(0 0% 30%); + --cru-bg-color: hsl(0 0% 100%); + --cru-bg-1-color: hsl(0 0% 90%); + --cru-bg-2-color: hsl(0 0% 80%); + --cru-bg-3-color: hsl(0 0% 70%); + --cru-disabled-color: hsl(0 0% 75%); + --cru-disabled-1-color: hsl(0 0% 65%); + --cru-disabled-2-color: hsl(0 0% 55%); + --cru-disabled-3-color: hsl(0 0% 45%); +} + +@media (prefers-color-scheme: dark) { + :root { + --cru-primary-color: hsl(210 100% 50%); + --cru-primary-l1-color: hsl(210 100% 60%); + --cru-primary-l2-color: hsl(210 100% 70%); + --cru-primary-l3-color: hsl(210 100% 80%); + --cru-primary-d1-color: hsl(210 100% 40%); + --cru-primary-d2-color: hsl(210 100% 30%); + --cru-primary-d3-color: hsl(210 100% 20%); + --cru-primary-f1-color: hsl(210 100% 40%); + --cru-primary-f2-color: hsl(210 100% 30%); + --cru-primary-f3-color: hsl(210 100% 20%); + --cru-primary-b1-color: hsl(210 100% 60%); + --cru-primary-b2-color: hsl(210 100% 70%); + --cru-primary-b3-color: hsl(210 100% 80%); + --cru-secondary-color: hsl(40 100% 50%); + --cru-secondary-l1-color: hsl(40 100% 60%); + --cru-secondary-l2-color: hsl(40 100% 70%); + --cru-secondary-l3-color: hsl(40 100% 80%); + --cru-secondary-d1-color: hsl(40 100% 40%); + --cru-secondary-d2-color: hsl(40 100% 30%); + --cru-secondary-d3-color: hsl(40 100% 20%); + --cru-secondary-f1-color: hsl(40 100% 40%); + --cru-secondary-f2-color: hsl(40 100% 30%); + --cru-secondary-f3-color: hsl(40 100% 20%); + --cru-secondary-b1-color: hsl(40 100% 60%); + --cru-secondary-b2-color: hsl(40 100% 70%); + --cru-secondary-b3-color: hsl(40 100% 80%); + --cru-tertiary-color: hsl(160 100% 50%); + --cru-tertiary-l1-color: hsl(160 100% 60%); + --cru-tertiary-l2-color: hsl(160 100% 70%); + --cru-tertiary-l3-color: hsl(160 100% 80%); + --cru-tertiary-d1-color: hsl(160 100% 40%); + --cru-tertiary-d2-color: hsl(160 100% 30%); + --cru-tertiary-d3-color: hsl(160 100% 20%); + --cru-tertiary-f1-color: hsl(160 100% 40%); + --cru-tertiary-f2-color: hsl(160 100% 30%); + --cru-tertiary-f3-color: hsl(160 100% 20%); + --cru-tertiary-b1-color: hsl(160 100% 60%); + --cru-tertiary-b2-color: hsl(160 100% 70%); + --cru-tertiary-b3-color: hsl(160 100% 80%); + --cru-danger-color: hsl(0 100% 50%); + --cru-danger-l1-color: hsl(0 100% 60%); + --cru-danger-l2-color: hsl(0 100% 70%); + --cru-danger-l3-color: hsl(0 100% 80%); + --cru-danger-d1-color: hsl(0 100% 40%); + --cru-danger-d2-color: hsl(0 100% 30%); + --cru-danger-d3-color: hsl(0 100% 20%); + --cru-danger-f1-color: hsl(0 100% 40%); + --cru-danger-f2-color: hsl(0 100% 30%); + --cru-danger-f3-color: hsl(0 100% 20%); + --cru-danger-b1-color: hsl(0 100% 60%); + --cru-danger-b2-color: hsl(0 100% 70%); + --cru-danger-b3-color: hsl(0 100% 80%); + --cru-success-color: hsl(120 100% 50%); + --cru-success-l1-color: hsl(120 100% 60%); + --cru-success-l2-color: hsl(120 100% 70%); + --cru-success-l3-color: hsl(120 100% 80%); + --cru-success-d1-color: hsl(120 100% 40%); + --cru-success-d2-color: hsl(120 100% 30%); + --cru-success-d3-color: hsl(120 100% 20%); + --cru-success-f1-color: hsl(120 100% 40%); + --cru-success-f2-color: hsl(120 100% 30%); + --cru-success-f3-color: hsl(120 100% 20%); + --cru-success-b1-color: hsl(120 100% 60%); + --cru-success-b2-color: hsl(120 100% 70%); + --cru-success-b3-color: hsl(120 100% 80%); + --cru-text-color: hsl(0 0% 100%); + --cru-text-1-color: hsl(0 0% 90%); + --cru-text-2-color: hsl(0 0% 80%); + --cru-text-3-color: hsl(0 0% 70%); + --cru-bg-color: hsl(0 0% 0%); + --cru-bg-1-color: hsl(0 0% 10%); + --cru-bg-2-color: hsl(0 0% 20%); + --cru-bg-3-color: hsl(0 0% 30%); + --cru-disabled-color: hsl(0 0% 25%); + --cru-disabled-1-color: hsl(0 0% 35%); + --cru-disabled-2-color: hsl(0 0% 45%); + --cru-disabled-3-color: hsl(0 0% 55%); + } +} + +.cru-primary { + --cru-theme-color: var(--cru-primary-color); + --cru-theme-l1-color: var(--cru-primary-l1-color); + --cru-theme-l2-color: var(--cru-primary-l2-color); + --cru-theme-l3-color: var(--cru-primary-l3-color); + --cru-theme-d1-color: var(--cru-primary-d1-color); + --cru-theme-d2-color: var(--cru-primary-d2-color); + --cru-theme-d3-color: var(--cru-primary-d3-color); + --cru-theme-f1-color: var(--cru-primary-f1-color); + --cru-theme-f2-color: var(--cru-primary-f2-color); + --cru-theme-f3-color: var(--cru-primary-f3-color); + --cru-theme-b1-color: var(--cru-primary-b1-color); + --cru-theme-b2-color: var(--cru-primary-b2-color); + --cru-theme-b3-color: var(--cru-primary-b3-color); +} + +.cru-secondary { + --cru-theme-color: var(--cru-secondary-color); + --cru-theme-l1-color: var(--cru-secondary-l1-color); + --cru-theme-l2-color: var(--cru-secondary-l2-color); + --cru-theme-l3-color: var(--cru-secondary-l3-color); + --cru-theme-d1-color: var(--cru-secondary-d1-color); + --cru-theme-d2-color: var(--cru-secondary-d2-color); + --cru-theme-d3-color: var(--cru-secondary-d3-color); + --cru-theme-f1-color: var(--cru-secondary-f1-color); + --cru-theme-f2-color: var(--cru-secondary-f2-color); + --cru-theme-f3-color: var(--cru-secondary-f3-color); + --cru-theme-b1-color: var(--cru-secondary-b1-color); + --cru-theme-b2-color: var(--cru-secondary-b2-color); + --cru-theme-b3-color: var(--cru-secondary-b3-color); +} + +.cru-tertiary { + --cru-theme-color: var(--cru-tertiary-color); + --cru-theme-l1-color: var(--cru-tertiary-l1-color); + --cru-theme-l2-color: var(--cru-tertiary-l2-color); + --cru-theme-l3-color: var(--cru-tertiary-l3-color); + --cru-theme-d1-color: var(--cru-tertiary-d1-color); + --cru-theme-d2-color: var(--cru-tertiary-d2-color); + --cru-theme-d3-color: var(--cru-tertiary-d3-color); + --cru-theme-f1-color: var(--cru-tertiary-f1-color); + --cru-theme-f2-color: var(--cru-tertiary-f2-color); + --cru-theme-f3-color: var(--cru-tertiary-f3-color); + --cru-theme-b1-color: var(--cru-tertiary-b1-color); + --cru-theme-b2-color: var(--cru-tertiary-b2-color); + --cru-theme-b3-color: var(--cru-tertiary-b3-color); +} + +.cru-danger { + --cru-theme-color: var(--cru-danger-color); + --cru-theme-l1-color: var(--cru-danger-l1-color); + --cru-theme-l2-color: var(--cru-danger-l2-color); + --cru-theme-l3-color: var(--cru-danger-l3-color); + --cru-theme-d1-color: var(--cru-danger-d1-color); + --cru-theme-d2-color: var(--cru-danger-d2-color); + --cru-theme-d3-color: var(--cru-danger-d3-color); + --cru-theme-f1-color: var(--cru-danger-f1-color); + --cru-theme-f2-color: var(--cru-danger-f2-color); + --cru-theme-f3-color: var(--cru-danger-f3-color); + --cru-theme-b1-color: var(--cru-danger-b1-color); + --cru-theme-b2-color: var(--cru-danger-b2-color); + --cru-theme-b3-color: var(--cru-danger-b3-color); +} + +.cru-success { + --cru-theme-color: var(--cru-success-color); + --cru-theme-l1-color: var(--cru-success-l1-color); + --cru-theme-l2-color: var(--cru-success-l2-color); + --cru-theme-l3-color: var(--cru-success-l3-color); + --cru-theme-d1-color: var(--cru-success-d1-color); + --cru-theme-d2-color: var(--cru-success-d2-color); + --cru-theme-d3-color: var(--cru-success-d3-color); + --cru-theme-f1-color: var(--cru-success-f1-color); + --cru-theme-f2-color: var(--cru-success-f2-color); + --cru-theme-f3-color: var(--cru-success-f3-color); + --cru-theme-b1-color: var(--cru-success-b1-color); + --cru-theme-b2-color: var(--cru-success-b2-color); + --cru-theme-b3-color: var(--cru-success-b3-color); +} + diff --git a/FrontEnd/tools/palette.ts b/FrontEnd/tools/palette.ts deleted file mode 100644 index 7b047ce1..00000000 --- a/FrontEnd/tools/palette.ts +++ /dev/null @@ -1,271 +0,0 @@ -#!/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/theme-generator.ts b/FrontEnd/tools/theme-generator.ts new file mode 100644 index 00000000..27dd5d1d --- /dev/null +++ b/FrontEnd/tools/theme-generator.ts @@ -0,0 +1,403 @@ +#!/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]; + */ + +import { stdout } from "process"; + +interface CssSegment { + toCssString(): string; +} + +interface Color extends CssSegment { + readonly type: "hsl" | "css-var"; + toString(): string; +} + +class HslColor implements Color { + readonly type = "hsl"; + + 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); + } + + toCssString(): string { + return this.toString(); + } + + toString(): string { + return `hsl(${this.h} ${this.s}% ${this.l}%)`; + } + + static readonly white = new HslColor(0, 0, 100); + static readonly black = new HslColor(0, 0, 0); +} + +class ColorVariable implements CssSegment { + constructor( + public prefix: string, + public name: string, + public variant?: string | null, + ) {} + + toString(): string { + const variantPart = this.variant == null ? "" : `-${this.variant}`; + return `--${this.prefix}-${this.name}${variantPart}-color`; + } + + toCssString(): string { + return this.toString(); + } +} + +class CssVarColor implements Color { + readonly type = "css-var"; + + constructor(public colorVariable: ColorVariable) {} + + toCssString(): string { + return this.toString(); + } + + toString(): string { + return `var(${this.colorVariable.toString()})`; + } +} + +class ColorVariableDefinition implements CssSegment { + constructor( + public name: ColorVariable, + public color: Color, + ) {} + + toCssString(): string { + return `${this.name.toCssString()}: ${this.color.toCssString()};`; + } +} + +type LightnessVariantType = "lighter" | "darker"; + +interface LightnessVariantInfo { + prefix: string; + type: LightnessVariantType; + levels: number; +} + +abstract class ColorGroup implements CssSegment { + abstract getColorVariables(): ColorVariableDefinition[]; + toCssString(): string { + return this.getColorVariables() + .map((c) => c.toCssString()) + .join("\n"); + } +} + +class LightnessVariantColorGroup extends ColorGroup { + constructor( + public prefix: string, + public name: string, + public baseColor: HslColor, + public lightnessVariants: LightnessVariantInfo[], + ) { + super(); + } + + getColorVariables(): ColorVariableDefinition[] { + const result: ColorVariableDefinition[] = [ + new ColorVariableDefinition( + new ColorVariable(this.prefix, this.name), + this.baseColor, + ), + ]; + + for (const lightnessVariant of this.lightnessVariants) { + for (let i = 1; i <= lightnessVariant.levels; i++) { + const color = + lightnessVariant.type === "lighter" + ? this.baseColor.lighter(i) + : this.baseColor.darker(i); + const colorVariant = `${lightnessVariant.prefix}${i}`; + result.push( + new ColorVariableDefinition( + new ColorVariable(this.prefix, this.name, colorVariant), + color, + ), + ); + } + } + + return result; + } +} + +class VarAliasColorGroup extends ColorGroup { + constructor( + public prefix: string, + public newName: string, + public oldName: string, + public variants: string[], + ) { + super(); + } + + getColorVariables(): ColorVariableDefinition[] { + const result = [ + new ColorVariableDefinition( + new ColorVariable(this.prefix, this.newName), + new CssVarColor(new ColorVariable(this.prefix, this.oldName)), + ), + ]; + for (const variant of this.variants) { + result.push( + new ColorVariableDefinition( + new ColorVariable(this.prefix, this.newName, variant), + new CssVarColor( + new ColorVariable(this.prefix, this.oldName, variant), + ), + ), + ); + } + return result; + } +} + +class GrayscaleColorGroup extends ColorGroup { + _delegate: LightnessVariantColorGroup; + + constructor( + public prefix: string, + public name: string, + public baseColor: HslColor, + public type: LightnessVariantType, + public levels = 3, + ) { + super(); + + this._delegate = new LightnessVariantColorGroup( + prefix, + name, + this.baseColor, + [{ prefix: "", type: this.type, levels }], + ); + } + + getColorVariables(): ColorVariableDefinition[] { + return this._delegate.getColorVariables(); + } + + static white(prefix: string, name: string, levels = 3): GrayscaleColorGroup { + return new GrayscaleColorGroup( + prefix, + name, + HslColor.white, + "darker", + levels, + ); + } + + static black(prefix: string, name: string, levels = 3): GrayscaleColorGroup { + return new GrayscaleColorGroup( + prefix, + name, + HslColor.black, + "lighter", + levels, + ); + } +} + +class CompositeColorGroup extends ColorGroup { + constructor(public groups: ColorGroup[]) { + super(); + } + + getColorVariables(): ColorVariableDefinition[] { + return this.groups + .map((g) => g.getColorVariables()) + .reduce((prev, curr) => prev.concat(curr), []); + } +} + +type ThemeColors = { name: string; color: HslColor }[]; + +type ColorMode = "light" | "dark"; + +class Theme { + static getDefaultThemeColorLightnessVariants( + mode: ColorMode, + levels = 3, + ): LightnessVariantInfo[] { + return [ + { + prefix: "l", + type: "lighter", + levels, + }, + { + prefix: "d", + type: "darker", + levels, + }, + { + prefix: "f", + type: mode === "light" ? "lighter" : "darker", + levels, + }, + { + prefix: "b", + type: mode === "light" ? "darker" : "lighter", + levels, + }, + ]; + } + + static getThemeColorAllVariants(): string[] { + const lightnessVariantInfos = + Theme.getDefaultThemeColorLightnessVariants("light"); + const result: string[] = []; + for (const { prefix, levels } of lightnessVariantInfos) { + for (let i = 1; i <= levels; i++) { + result.push(`${prefix}${i}`); + } + } + return result; + } + + constructor( + public prefix: string, + public themeColors: ThemeColors, + public levels = 3, + ) {} + + getThemeColorDefinitions(mode: ColorMode): ColorGroup { + const groups: ColorGroup[] = []; + for (const { name, color } of this.themeColors) { + const colorGroup = new LightnessVariantColorGroup( + this.prefix, + name, + color, + Theme.getDefaultThemeColorLightnessVariants(mode, this.levels), + ); + groups.push(colorGroup); + } + return new CompositeColorGroup(groups); + } + + getAliasColorDefinitions(name: string): ColorGroup { + return new VarAliasColorGroup( + this.prefix, + "theme", + name, + Theme.getThemeColorAllVariants(), + ); + } + + getGrayscaleDefinitions(mode: ColorMode): ColorGroup { + const textGroup = + mode === "light" + ? GrayscaleColorGroup.black(this.prefix, "text", this.levels) + : GrayscaleColorGroup.white(this.prefix, "text", this.levels); + const bgGroup = + mode === "light" + ? GrayscaleColorGroup.white(this.prefix, "bg", this.levels) + : GrayscaleColorGroup.black(this.prefix, "bg", this.levels); + const disabledGroup = + mode == "light" + ? new GrayscaleColorGroup( + this.prefix, + "disabled", + new HslColor(0, 0, 75), + "darker", + this.levels, + ) + : new GrayscaleColorGroup( + this.prefix, + "disabled", + new HslColor(0, 0, 25), + "lighter", + this.levels, + ); + return new CompositeColorGroup([textGroup, bgGroup, disabledGroup]); + } + + generateCss(print: (text: string, indent: number) => void): void { + print(":root {", 0); + print(this.getThemeColorDefinitions("light").toCssString(), 1); + print(this.getGrayscaleDefinitions("light").toCssString(), 1); + print("}", 0); + + print("", 0); + + print("@media (prefers-color-scheme: dark) {", 0); + print(":root {", 1); + print(this.getThemeColorDefinitions("dark").toCssString(), 2); + print(this.getGrayscaleDefinitions("dark").toCssString(), 2); + print("}", 1); + print("}", 0); + + print("", 0); + + for (const { name } of this.themeColors) { + print(`.${this.prefix}-${name} {`, 0); + print(this.getAliasColorDefinitions(name).toCssString(), 1); + print("}", 0); + + print("", 0); + } + } +} + +(function main() { + const prefix = "cru"; + const themeColors: ThemeColors = [ + { name: "primary", color: new HslColor(210, 100, 50) }, + { name: "secondary", color: new HslColor(40, 100, 50) }, + { name: "tertiary", color: new HslColor(160, 100, 50) }, + { name: "danger", color: new HslColor(0, 100, 50) }, + { name: "success", color: new HslColor(120, 100, 50) }, + ]; + + const theme = new Theme(prefix, themeColors); + + 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); + } + + print("/* Generated by theme-generator.ts */\n"); + theme.generateCss(print); + + stdout.write(output); +})(); diff --git a/FrontEnd/tools/tsconfig.json b/FrontEnd/tools/tsconfig.json index 8c9b3c47..08f53190 100644 --- a/FrontEnd/tools/tsconfig.json +++ b/FrontEnd/tools/tsconfig.json @@ -1,6 +1,6 @@ { - // This is an alias to @tsconfig/node16: https://github.com/tsconfig/bases - "extends": "ts-node/node16/tsconfig.json", + // This is an alias to @tsconfig/node20: https://github.com/tsconfig/bases + "extends": "@tsconfig/node20/tsconfig.json", // Most ts-node options can be specified here using their programmatic names. "ts-node": { // It is faster to skip typechecking. -- cgit v1.2.3 From d808b68d959aa59347e1c4ce7084a7afcfa80522 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 14 Jul 2023 23:07:46 +0800 Subject: ... --- FrontEnd/src/views/common/button/Button.css | 2 +- FrontEnd/src/views/common/button/Button.tsx | 2 +- FrontEnd/src/views/common/button/FlatButton.css | 2 +- FrontEnd/src/views/common/button/FlatButton.tsx | 2 +- FrontEnd/src/views/common/button/IconButton.tsx | 2 +- FrontEnd/src/views/common/button/LoadingButton.tsx | 2 +- FrontEnd/src/views/common/common.ts | 12 ++++++++++++ 7 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 FrontEnd/src/views/common/common.ts diff --git a/FrontEnd/src/views/common/button/Button.css b/FrontEnd/src/views/common/button/Button.css index 406d70d2..e0b8e733 100644 --- a/FrontEnd/src/views/common/button/Button.css +++ b/FrontEnd/src/views/common/button/Button.css @@ -28,7 +28,7 @@ padding: 0.2em 0.5em; border-radius: 0.2em; transition: all 0.6s; - background-color: white; + background-color: var(--cru-background-color); } .cru-button.outline:hover { diff --git a/FrontEnd/src/views/common/button/Button.tsx b/FrontEnd/src/views/common/button/Button.tsx index 53f41bc1..e1015f71 100644 --- a/FrontEnd/src/views/common/button/Button.tsx +++ b/FrontEnd/src/views/common/button/Button.tsx @@ -1,7 +1,7 @@ import { ComponentPropsWithoutRef, Ref } from "react"; import classNames from "classnames"; -import { I18nText, useC, ThemeColor } from "@/common"; +import { I18nText, useC, ThemeColor } from "../common"; import "./Button.css"; diff --git a/FrontEnd/src/views/common/button/FlatButton.css b/FrontEnd/src/views/common/button/FlatButton.css index f0d33153..ea45e783 100644 --- a/FrontEnd/src/views/common/button/FlatButton.css +++ b/FrontEnd/src/views/common/button/FlatButton.css @@ -9,7 +9,7 @@ } .cru-flat-button.disabled { - color: var(--cru-theme-l1-color); + color: var(--cru-theme-f1-color); cursor: default; } diff --git a/FrontEnd/src/views/common/button/FlatButton.tsx b/FrontEnd/src/views/common/button/FlatButton.tsx index a5354670..7b268b6d 100644 --- a/FrontEnd/src/views/common/button/FlatButton.tsx +++ b/FrontEnd/src/views/common/button/FlatButton.tsx @@ -1,7 +1,7 @@ import { ComponentPropsWithoutRef, Ref } from "react"; import classNames from "classnames"; -import { I18nText, useC, ThemeColor } from "@/common"; +import { I18nText, useC, ThemeColor } from "../common"; import "./FlatButton.css"; diff --git a/FrontEnd/src/views/common/button/IconButton.tsx b/FrontEnd/src/views/common/button/IconButton.tsx index 0ff9541a..e5454574 100644 --- a/FrontEnd/src/views/common/button/IconButton.tsx +++ b/FrontEnd/src/views/common/button/IconButton.tsx @@ -1,7 +1,7 @@ import { ComponentPropsWithoutRef } from "react"; import classNames from "classnames"; -import { ThemeColor } from "@/common"; +import { ThemeColor } from "../common"; import "./IconButton.css"; diff --git a/FrontEnd/src/views/common/button/LoadingButton.tsx b/FrontEnd/src/views/common/button/LoadingButton.tsx index c4cafc0c..249f3e1d 100644 --- a/FrontEnd/src/views/common/button/LoadingButton.tsx +++ b/FrontEnd/src/views/common/button/LoadingButton.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import classNames from "classnames"; import { useTranslation } from "react-i18next"; -import { convertI18nText, I18nText, ThemeColor } from "@/common"; +import { I18nText, ThemeColor, convertI18nText } from "../common"; import Spinner from "../Spinner"; diff --git a/FrontEnd/src/views/common/common.ts b/FrontEnd/src/views/common/common.ts new file mode 100644 index 00000000..e3a5a2a2 --- /dev/null +++ b/FrontEnd/src/views/common/common.ts @@ -0,0 +1,12 @@ +export type { I18nText } from "@/common"; +export { c, convertI18nText, useC } from "@/common"; + +export const themeColors = [ + "primary", + "secondary", + "tertiary", + "danger", + "success", +] as const; + +export type ThemeColor = (typeof themeColors)[number]; -- cgit v1.2.3 From c456e1769d2f06860f3d08272dc72407f96a42b8 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 14 Jul 2023 23:21:54 +0800 Subject: ... --- FrontEnd/src/index.css | 5 +- FrontEnd/src/views/common/button/Button.css | 14 +- FrontEnd/src/views/common/index.css | 5 + FrontEnd/src/views/common/theme.css | 296 +++++++++++++++------------- FrontEnd/tools/theme-generator.ts | 24 ++- 5 files changed, 189 insertions(+), 155 deletions(-) diff --git a/FrontEnd/src/index.css b/FrontEnd/src/index.css index 2faecfae..925d9c26 100644 --- a/FrontEnd/src/index.css +++ b/FrontEnd/src/index.css @@ -4,9 +4,6 @@ @import "./views/common/index.css"; -body { - background: var(--cru-background-color); -} small { line-height: 1.2; @@ -24,7 +21,7 @@ small { textarea { resize: none; outline: none; - border-color: var(--cru-background-2-color); + border-color: var(--cru-bg-2-color); } textarea:hover { diff --git a/FrontEnd/src/views/common/button/Button.css b/FrontEnd/src/views/common/button/Button.css index e0b8e733..7a271446 100644 --- a/FrontEnd/src/views/common/button/Button.css +++ b/FrontEnd/src/views/common/button/Button.css @@ -1,5 +1,5 @@ .cru-button:not(.outline) { - color: var(--cru-text-color); + color: var(--cru-light-color); cursor: pointer; padding: 0.2em 0.5em; border-radius: 0.2em; @@ -9,11 +9,11 @@ } .cru-button:not(.outline):hover { - background-color: var(--cru-theme-f1-color); + background-color: var(--cru-theme-b1-color); } .cru-button:not(.outline):active { - background-color: var(--cru-theme-f2-color); + background-color: var(--cru-theme-b2-color); } .cru-button:not(.outline):disabled { @@ -32,14 +32,14 @@ } .cru-button.outline:hover { - color: var(--cru-theme-f1-color); - border-color: var(--cru-theme-f1-color); + color: var(--cru-theme-b1-color); + border-color: var(--cru-theme-b1-color); background-color: var(--cru-background-color); } .cru-button.outline:active { - color: var(--cru-theme-f2-color); - border-color: var(--cru-theme-f2-color); + color: var(--cru-theme-b2-color); + border-color: var(--cru-theme-b2-color); background-color: var(--cru-background-1-color); } diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css index 06f2556b..16a7f924 100644 --- a/FrontEnd/src/views/common/index.css +++ b/FrontEnd/src/views/common/index.css @@ -1,5 +1,10 @@ @import "./theme.css"; +body { + background: var(--cru-bg-color); + color: var(--cru-text-color); +} + .cru-text-center { text-align: center; } diff --git a/FrontEnd/src/views/common/theme.css b/FrontEnd/src/views/common/theme.css index 816bd3d1..9dfa1d9a 100644 --- a/FrontEnd/src/views/common/theme.css +++ b/FrontEnd/src/views/common/theme.css @@ -2,163 +2,179 @@ :root { --cru-primary-color: hsl(210 100% 50%); - --cru-primary-l1-color: hsl(210 100% 60%); - --cru-primary-l2-color: hsl(210 100% 70%); - --cru-primary-l3-color: hsl(210 100% 80%); - --cru-primary-d1-color: hsl(210 100% 40%); - --cru-primary-d2-color: hsl(210 100% 30%); - --cru-primary-d3-color: hsl(210 100% 20%); - --cru-primary-f1-color: hsl(210 100% 60%); - --cru-primary-f2-color: hsl(210 100% 70%); - --cru-primary-f3-color: hsl(210 100% 80%); - --cru-primary-b1-color: hsl(210 100% 40%); - --cru-primary-b2-color: hsl(210 100% 30%); - --cru-primary-b3-color: hsl(210 100% 20%); + --cru-primary-l1-color: hsl(210 100% 55%); + --cru-primary-l2-color: hsl(210 100% 60%); + --cru-primary-l3-color: hsl(210 100% 65%); + --cru-primary-d1-color: hsl(210 100% 45%); + --cru-primary-d2-color: hsl(210 100% 40%); + --cru-primary-d3-color: hsl(210 100% 35%); + --cru-primary-f1-color: hsl(210 100% 55%); + --cru-primary-f2-color: hsl(210 100% 60%); + --cru-primary-f3-color: hsl(210 100% 65%); + --cru-primary-b1-color: hsl(210 100% 45%); + --cru-primary-b2-color: hsl(210 100% 40%); + --cru-primary-b3-color: hsl(210 100% 35%); --cru-secondary-color: hsl(40 100% 50%); - --cru-secondary-l1-color: hsl(40 100% 60%); - --cru-secondary-l2-color: hsl(40 100% 70%); - --cru-secondary-l3-color: hsl(40 100% 80%); - --cru-secondary-d1-color: hsl(40 100% 40%); - --cru-secondary-d2-color: hsl(40 100% 30%); - --cru-secondary-d3-color: hsl(40 100% 20%); - --cru-secondary-f1-color: hsl(40 100% 60%); - --cru-secondary-f2-color: hsl(40 100% 70%); - --cru-secondary-f3-color: hsl(40 100% 80%); - --cru-secondary-b1-color: hsl(40 100% 40%); - --cru-secondary-b2-color: hsl(40 100% 30%); - --cru-secondary-b3-color: hsl(40 100% 20%); + --cru-secondary-l1-color: hsl(40 100% 55%); + --cru-secondary-l2-color: hsl(40 100% 60%); + --cru-secondary-l3-color: hsl(40 100% 65%); + --cru-secondary-d1-color: hsl(40 100% 45%); + --cru-secondary-d2-color: hsl(40 100% 40%); + --cru-secondary-d3-color: hsl(40 100% 35%); + --cru-secondary-f1-color: hsl(40 100% 55%); + --cru-secondary-f2-color: hsl(40 100% 60%); + --cru-secondary-f3-color: hsl(40 100% 65%); + --cru-secondary-b1-color: hsl(40 100% 45%); + --cru-secondary-b2-color: hsl(40 100% 40%); + --cru-secondary-b3-color: hsl(40 100% 35%); --cru-tertiary-color: hsl(160 100% 50%); - --cru-tertiary-l1-color: hsl(160 100% 60%); - --cru-tertiary-l2-color: hsl(160 100% 70%); - --cru-tertiary-l3-color: hsl(160 100% 80%); - --cru-tertiary-d1-color: hsl(160 100% 40%); - --cru-tertiary-d2-color: hsl(160 100% 30%); - --cru-tertiary-d3-color: hsl(160 100% 20%); - --cru-tertiary-f1-color: hsl(160 100% 60%); - --cru-tertiary-f2-color: hsl(160 100% 70%); - --cru-tertiary-f3-color: hsl(160 100% 80%); - --cru-tertiary-b1-color: hsl(160 100% 40%); - --cru-tertiary-b2-color: hsl(160 100% 30%); - --cru-tertiary-b3-color: hsl(160 100% 20%); + --cru-tertiary-l1-color: hsl(160 100% 55%); + --cru-tertiary-l2-color: hsl(160 100% 60%); + --cru-tertiary-l3-color: hsl(160 100% 65%); + --cru-tertiary-d1-color: hsl(160 100% 45%); + --cru-tertiary-d2-color: hsl(160 100% 40%); + --cru-tertiary-d3-color: hsl(160 100% 35%); + --cru-tertiary-f1-color: hsl(160 100% 55%); + --cru-tertiary-f2-color: hsl(160 100% 60%); + --cru-tertiary-f3-color: hsl(160 100% 65%); + --cru-tertiary-b1-color: hsl(160 100% 45%); + --cru-tertiary-b2-color: hsl(160 100% 40%); + --cru-tertiary-b3-color: hsl(160 100% 35%); --cru-danger-color: hsl(0 100% 50%); - --cru-danger-l1-color: hsl(0 100% 60%); - --cru-danger-l2-color: hsl(0 100% 70%); - --cru-danger-l3-color: hsl(0 100% 80%); - --cru-danger-d1-color: hsl(0 100% 40%); - --cru-danger-d2-color: hsl(0 100% 30%); - --cru-danger-d3-color: hsl(0 100% 20%); - --cru-danger-f1-color: hsl(0 100% 60%); - --cru-danger-f2-color: hsl(0 100% 70%); - --cru-danger-f3-color: hsl(0 100% 80%); - --cru-danger-b1-color: hsl(0 100% 40%); - --cru-danger-b2-color: hsl(0 100% 30%); - --cru-danger-b3-color: hsl(0 100% 20%); - --cru-success-color: hsl(120 100% 50%); - --cru-success-l1-color: hsl(120 100% 60%); - --cru-success-l2-color: hsl(120 100% 70%); - --cru-success-l3-color: hsl(120 100% 80%); - --cru-success-d1-color: hsl(120 100% 40%); - --cru-success-d2-color: hsl(120 100% 30%); - --cru-success-d3-color: hsl(120 100% 20%); - --cru-success-f1-color: hsl(120 100% 60%); - --cru-success-f2-color: hsl(120 100% 70%); - --cru-success-f3-color: hsl(120 100% 80%); - --cru-success-b1-color: hsl(120 100% 40%); - --cru-success-b2-color: hsl(120 100% 30%); - --cru-success-b3-color: hsl(120 100% 20%); + --cru-danger-l1-color: hsl(0 100% 55%); + --cru-danger-l2-color: hsl(0 100% 60%); + --cru-danger-l3-color: hsl(0 100% 65%); + --cru-danger-d1-color: hsl(0 100% 45%); + --cru-danger-d2-color: hsl(0 100% 40%); + --cru-danger-d3-color: hsl(0 100% 35%); + --cru-danger-f1-color: hsl(0 100% 55%); + --cru-danger-f2-color: hsl(0 100% 60%); + --cru-danger-f3-color: hsl(0 100% 65%); + --cru-danger-b1-color: hsl(0 100% 45%); + --cru-danger-b2-color: hsl(0 100% 40%); + --cru-danger-b3-color: hsl(0 100% 35%); + --cru-success-color: hsl(120 60% 50%); + --cru-success-l1-color: hsl(120 60% 55%); + --cru-success-l2-color: hsl(120 60% 60%); + --cru-success-l3-color: hsl(120 60% 65%); + --cru-success-d1-color: hsl(120 60% 45%); + --cru-success-d2-color: hsl(120 60% 40%); + --cru-success-d3-color: hsl(120 60% 35%); + --cru-success-f1-color: hsl(120 60% 55%); + --cru-success-f2-color: hsl(120 60% 60%); + --cru-success-f3-color: hsl(120 60% 65%); + --cru-success-b1-color: hsl(120 60% 45%); + --cru-success-b2-color: hsl(120 60% 40%); + --cru-success-b3-color: hsl(120 60% 35%); --cru-text-color: hsl(0 0% 0%); - --cru-text-1-color: hsl(0 0% 10%); - --cru-text-2-color: hsl(0 0% 20%); - --cru-text-3-color: hsl(0 0% 30%); + --cru-text-1-color: hsl(0 0% 5%); + --cru-text-2-color: hsl(0 0% 10%); + --cru-text-3-color: hsl(0 0% 15%); --cru-bg-color: hsl(0 0% 100%); - --cru-bg-1-color: hsl(0 0% 90%); - --cru-bg-2-color: hsl(0 0% 80%); - --cru-bg-3-color: hsl(0 0% 70%); + --cru-bg-1-color: hsl(0 0% 95%); + --cru-bg-2-color: hsl(0 0% 90%); + --cru-bg-3-color: hsl(0 0% 85%); + --cru-light-color: hsl(0 0% 100%); + --cru-light-1-color: hsl(0 0% 95%); + --cru-light-2-color: hsl(0 0% 90%); + --cru-light-3-color: hsl(0 0% 85%); + --cru-dark-color: hsl(0 0% 0%); + --cru-dark-1-color: hsl(0 0% 5%); + --cru-dark-2-color: hsl(0 0% 10%); + --cru-dark-3-color: hsl(0 0% 15%); --cru-disabled-color: hsl(0 0% 75%); - --cru-disabled-1-color: hsl(0 0% 65%); - --cru-disabled-2-color: hsl(0 0% 55%); - --cru-disabled-3-color: hsl(0 0% 45%); + --cru-disabled-1-color: hsl(0 0% 70%); + --cru-disabled-2-color: hsl(0 0% 65%); + --cru-disabled-3-color: hsl(0 0% 60%); } @media (prefers-color-scheme: dark) { :root { --cru-primary-color: hsl(210 100% 50%); - --cru-primary-l1-color: hsl(210 100% 60%); - --cru-primary-l2-color: hsl(210 100% 70%); - --cru-primary-l3-color: hsl(210 100% 80%); - --cru-primary-d1-color: hsl(210 100% 40%); - --cru-primary-d2-color: hsl(210 100% 30%); - --cru-primary-d3-color: hsl(210 100% 20%); - --cru-primary-f1-color: hsl(210 100% 40%); - --cru-primary-f2-color: hsl(210 100% 30%); - --cru-primary-f3-color: hsl(210 100% 20%); - --cru-primary-b1-color: hsl(210 100% 60%); - --cru-primary-b2-color: hsl(210 100% 70%); - --cru-primary-b3-color: hsl(210 100% 80%); + --cru-primary-l1-color: hsl(210 100% 55%); + --cru-primary-l2-color: hsl(210 100% 60%); + --cru-primary-l3-color: hsl(210 100% 65%); + --cru-primary-d1-color: hsl(210 100% 45%); + --cru-primary-d2-color: hsl(210 100% 40%); + --cru-primary-d3-color: hsl(210 100% 35%); + --cru-primary-f1-color: hsl(210 100% 45%); + --cru-primary-f2-color: hsl(210 100% 40%); + --cru-primary-f3-color: hsl(210 100% 35%); + --cru-primary-b1-color: hsl(210 100% 55%); + --cru-primary-b2-color: hsl(210 100% 60%); + --cru-primary-b3-color: hsl(210 100% 65%); --cru-secondary-color: hsl(40 100% 50%); - --cru-secondary-l1-color: hsl(40 100% 60%); - --cru-secondary-l2-color: hsl(40 100% 70%); - --cru-secondary-l3-color: hsl(40 100% 80%); - --cru-secondary-d1-color: hsl(40 100% 40%); - --cru-secondary-d2-color: hsl(40 100% 30%); - --cru-secondary-d3-color: hsl(40 100% 20%); - --cru-secondary-f1-color: hsl(40 100% 40%); - --cru-secondary-f2-color: hsl(40 100% 30%); - --cru-secondary-f3-color: hsl(40 100% 20%); - --cru-secondary-b1-color: hsl(40 100% 60%); - --cru-secondary-b2-color: hsl(40 100% 70%); - --cru-secondary-b3-color: hsl(40 100% 80%); + --cru-secondary-l1-color: hsl(40 100% 55%); + --cru-secondary-l2-color: hsl(40 100% 60%); + --cru-secondary-l3-color: hsl(40 100% 65%); + --cru-secondary-d1-color: hsl(40 100% 45%); + --cru-secondary-d2-color: hsl(40 100% 40%); + --cru-secondary-d3-color: hsl(40 100% 35%); + --cru-secondary-f1-color: hsl(40 100% 45%); + --cru-secondary-f2-color: hsl(40 100% 40%); + --cru-secondary-f3-color: hsl(40 100% 35%); + --cru-secondary-b1-color: hsl(40 100% 55%); + --cru-secondary-b2-color: hsl(40 100% 60%); + --cru-secondary-b3-color: hsl(40 100% 65%); --cru-tertiary-color: hsl(160 100% 50%); - --cru-tertiary-l1-color: hsl(160 100% 60%); - --cru-tertiary-l2-color: hsl(160 100% 70%); - --cru-tertiary-l3-color: hsl(160 100% 80%); - --cru-tertiary-d1-color: hsl(160 100% 40%); - --cru-tertiary-d2-color: hsl(160 100% 30%); - --cru-tertiary-d3-color: hsl(160 100% 20%); - --cru-tertiary-f1-color: hsl(160 100% 40%); - --cru-tertiary-f2-color: hsl(160 100% 30%); - --cru-tertiary-f3-color: hsl(160 100% 20%); - --cru-tertiary-b1-color: hsl(160 100% 60%); - --cru-tertiary-b2-color: hsl(160 100% 70%); - --cru-tertiary-b3-color: hsl(160 100% 80%); + --cru-tertiary-l1-color: hsl(160 100% 55%); + --cru-tertiary-l2-color: hsl(160 100% 60%); + --cru-tertiary-l3-color: hsl(160 100% 65%); + --cru-tertiary-d1-color: hsl(160 100% 45%); + --cru-tertiary-d2-color: hsl(160 100% 40%); + --cru-tertiary-d3-color: hsl(160 100% 35%); + --cru-tertiary-f1-color: hsl(160 100% 45%); + --cru-tertiary-f2-color: hsl(160 100% 40%); + --cru-tertiary-f3-color: hsl(160 100% 35%); + --cru-tertiary-b1-color: hsl(160 100% 55%); + --cru-tertiary-b2-color: hsl(160 100% 60%); + --cru-tertiary-b3-color: hsl(160 100% 65%); --cru-danger-color: hsl(0 100% 50%); - --cru-danger-l1-color: hsl(0 100% 60%); - --cru-danger-l2-color: hsl(0 100% 70%); - --cru-danger-l3-color: hsl(0 100% 80%); - --cru-danger-d1-color: hsl(0 100% 40%); - --cru-danger-d2-color: hsl(0 100% 30%); - --cru-danger-d3-color: hsl(0 100% 20%); - --cru-danger-f1-color: hsl(0 100% 40%); - --cru-danger-f2-color: hsl(0 100% 30%); - --cru-danger-f3-color: hsl(0 100% 20%); - --cru-danger-b1-color: hsl(0 100% 60%); - --cru-danger-b2-color: hsl(0 100% 70%); - --cru-danger-b3-color: hsl(0 100% 80%); - --cru-success-color: hsl(120 100% 50%); - --cru-success-l1-color: hsl(120 100% 60%); - --cru-success-l2-color: hsl(120 100% 70%); - --cru-success-l3-color: hsl(120 100% 80%); - --cru-success-d1-color: hsl(120 100% 40%); - --cru-success-d2-color: hsl(120 100% 30%); - --cru-success-d3-color: hsl(120 100% 20%); - --cru-success-f1-color: hsl(120 100% 40%); - --cru-success-f2-color: hsl(120 100% 30%); - --cru-success-f3-color: hsl(120 100% 20%); - --cru-success-b1-color: hsl(120 100% 60%); - --cru-success-b2-color: hsl(120 100% 70%); - --cru-success-b3-color: hsl(120 100% 80%); + --cru-danger-l1-color: hsl(0 100% 55%); + --cru-danger-l2-color: hsl(0 100% 60%); + --cru-danger-l3-color: hsl(0 100% 65%); + --cru-danger-d1-color: hsl(0 100% 45%); + --cru-danger-d2-color: hsl(0 100% 40%); + --cru-danger-d3-color: hsl(0 100% 35%); + --cru-danger-f1-color: hsl(0 100% 45%); + --cru-danger-f2-color: hsl(0 100% 40%); + --cru-danger-f3-color: hsl(0 100% 35%); + --cru-danger-b1-color: hsl(0 100% 55%); + --cru-danger-b2-color: hsl(0 100% 60%); + --cru-danger-b3-color: hsl(0 100% 65%); + --cru-success-color: hsl(120 60% 50%); + --cru-success-l1-color: hsl(120 60% 55%); + --cru-success-l2-color: hsl(120 60% 60%); + --cru-success-l3-color: hsl(120 60% 65%); + --cru-success-d1-color: hsl(120 60% 45%); + --cru-success-d2-color: hsl(120 60% 40%); + --cru-success-d3-color: hsl(120 60% 35%); + --cru-success-f1-color: hsl(120 60% 45%); + --cru-success-f2-color: hsl(120 60% 40%); + --cru-success-f3-color: hsl(120 60% 35%); + --cru-success-b1-color: hsl(120 60% 55%); + --cru-success-b2-color: hsl(120 60% 60%); + --cru-success-b3-color: hsl(120 60% 65%); --cru-text-color: hsl(0 0% 100%); - --cru-text-1-color: hsl(0 0% 90%); - --cru-text-2-color: hsl(0 0% 80%); - --cru-text-3-color: hsl(0 0% 70%); + --cru-text-1-color: hsl(0 0% 95%); + --cru-text-2-color: hsl(0 0% 90%); + --cru-text-3-color: hsl(0 0% 85%); --cru-bg-color: hsl(0 0% 0%); - --cru-bg-1-color: hsl(0 0% 10%); - --cru-bg-2-color: hsl(0 0% 20%); - --cru-bg-3-color: hsl(0 0% 30%); + --cru-bg-1-color: hsl(0 0% 5%); + --cru-bg-2-color: hsl(0 0% 10%); + --cru-bg-3-color: hsl(0 0% 15%); + --cru-light-color: hsl(0 0% 100%); + --cru-light-1-color: hsl(0 0% 95%); + --cru-light-2-color: hsl(0 0% 90%); + --cru-light-3-color: hsl(0 0% 85%); + --cru-dark-color: hsl(0 0% 0%); + --cru-dark-1-color: hsl(0 0% 5%); + --cru-dark-2-color: hsl(0 0% 10%); + --cru-dark-3-color: hsl(0 0% 15%); --cru-disabled-color: hsl(0 0% 25%); - --cru-disabled-1-color: hsl(0 0% 35%); - --cru-disabled-2-color: hsl(0 0% 45%); - --cru-disabled-3-color: hsl(0 0% 55%); + --cru-disabled-1-color: hsl(0 0% 30%); + --cru-disabled-2-color: hsl(0 0% 35%); + --cru-disabled-3-color: hsl(0 0% 40%); } } diff --git a/FrontEnd/tools/theme-generator.ts b/FrontEnd/tools/theme-generator.ts index 27dd5d1d..704a1052 100644 --- a/FrontEnd/tools/theme-generator.ts +++ b/FrontEnd/tools/theme-generator.ts @@ -30,11 +30,11 @@ class HslColor implements Color { ) {} lighter(level: number): HslColor { - return new HslColor(this.h, this.s, this.l + level * 10); + return new HslColor(this.h, this.s, this.l + level * 5); } darker(level: number): HslColor { - return new HslColor(this.h, this.s, this.l - level * 10); + return new HslColor(this.h, this.s, this.l - level * 5); } toCssString(): string { @@ -317,6 +317,16 @@ class Theme { mode === "light" ? GrayscaleColorGroup.white(this.prefix, "bg", this.levels) : GrayscaleColorGroup.black(this.prefix, "bg", this.levels); + const lightGroup = GrayscaleColorGroup.white( + this.prefix, + "light", + this.levels, + ); + const darkGroup = GrayscaleColorGroup.black( + this.prefix, + "dark", + this.levels, + ); const disabledGroup = mode == "light" ? new GrayscaleColorGroup( @@ -333,7 +343,13 @@ class Theme { "lighter", this.levels, ); - return new CompositeColorGroup([textGroup, bgGroup, disabledGroup]); + return new CompositeColorGroup([ + textGroup, + bgGroup, + lightGroup, + darkGroup, + disabledGroup, + ]); } generateCss(print: (text: string, indent: number) => void): void { @@ -370,7 +386,7 @@ class Theme { { name: "secondary", color: new HslColor(40, 100, 50) }, { name: "tertiary", color: new HslColor(160, 100, 50) }, { name: "danger", color: new HslColor(0, 100, 50) }, - { name: "success", color: new HslColor(120, 100, 50) }, + { name: "success", color: new HslColor(120, 60, 50) }, ]; const theme = new Theme(prefix, themeColors); -- cgit v1.2.3 From 59c424a38809be6afb170f11eadb0e4d14f10f69 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 14 Jul 2023 23:35:46 +0800 Subject: ... --- FrontEnd/src/common.ts | 10 - FrontEnd/src/index.css | 1 - FrontEnd/src/views/common/Card.css | 7 +- FrontEnd/src/views/common/button/Button.css | 12 +- FrontEnd/src/views/common/button/FlatButton.css | 2 +- FrontEnd/src/views/common/index.css | 8 + FrontEnd/src/views/common/theme-color.css | 260 +++++++++++++++++++++++ FrontEnd/src/views/common/theme.css | 261 +----------------------- 8 files changed, 279 insertions(+), 282 deletions(-) create mode 100644 FrontEnd/src/views/common/theme-color.css diff --git a/FrontEnd/src/common.ts b/FrontEnd/src/common.ts index 6dcd2a9e..965f9933 100644 --- a/FrontEnd/src/common.ts +++ b/FrontEnd/src/common.ts @@ -8,13 +8,3 @@ export const highlightTimelineUsername = "crupest"; export type { I18nText } from "./i18n"; export { c, convertI18nText } from "./i18n"; export { default as useC } from "./utilities/hooks/use-c"; - -export const themeColors = [ - "primary", - "secondary", - "tertiary", - "danger", - "success", -] as const; - -export type ThemeColor = (typeof themeColors)[number]; diff --git a/FrontEnd/src/index.css b/FrontEnd/src/index.css index 925d9c26..3478db05 100644 --- a/FrontEnd/src/index.css +++ b/FrontEnd/src/index.css @@ -1,4 +1,3 @@ -@import "npm:bootstrap/dist/css/bootstrap-reboot.css"; @import "npm:bootstrap/dist/css/bootstrap-grid.css"; @import "npm:bootstrap-icons/font/bootstrap-icons.css"; diff --git a/FrontEnd/src/views/common/Card.css b/FrontEnd/src/views/common/Card.css index 6de0dd8e..fa470130 100644 --- a/FrontEnd/src/views/common/Card.css +++ b/FrontEnd/src/views/common/Card.css @@ -1,15 +1,10 @@ -:root { - --cru-card-border-radius: 8px; -} - .cru-card { border: 1px solid; border-color: #e9ecef; border-radius: var(--cru-card-border-radius); - background: #fefeff; transition: all 0.3s; } .cru-card:hover { border-color: var(--cru-primary-color); -} +} \ No newline at end of file diff --git a/FrontEnd/src/views/common/button/Button.css b/FrontEnd/src/views/common/button/Button.css index 7a271446..0df22ebe 100644 --- a/FrontEnd/src/views/common/button/Button.css +++ b/FrontEnd/src/views/common/button/Button.css @@ -9,11 +9,11 @@ } .cru-button:not(.outline):hover { - background-color: var(--cru-theme-b1-color); + background-color: var(--cru-theme-d1-color); } .cru-button:not(.outline):active { - background-color: var(--cru-theme-b2-color); + background-color: var(--cru-theme-d2-color); } .cru-button:not(.outline):disabled { @@ -32,14 +32,14 @@ } .cru-button.outline:hover { - color: var(--cru-theme-b1-color); - border-color: var(--cru-theme-b1-color); + color: var(--cru-theme-d1-color); + border-color: var(--cru-theme-d1-color); background-color: var(--cru-background-color); } .cru-button.outline:active { - color: var(--cru-theme-b2-color); - border-color: var(--cru-theme-b2-color); + color: var(--cru-theme-l2-color); + border-color: var(--cru-theme-l2-color); background-color: var(--cru-background-1-color); } diff --git a/FrontEnd/src/views/common/button/FlatButton.css b/FrontEnd/src/views/common/button/FlatButton.css index ea45e783..01eabca9 100644 --- a/FrontEnd/src/views/common/button/FlatButton.css +++ b/FrontEnd/src/views/common/button/FlatButton.css @@ -9,7 +9,7 @@ } .cru-flat-button.disabled { - color: var(--cru-theme-f1-color); + color: var(--cru-disabled-color); cursor: default; } diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css index 16a7f924..9d69997b 100644 --- a/FrontEnd/src/views/common/index.css +++ b/FrontEnd/src/views/common/index.css @@ -1,10 +1,18 @@ @import "./theme.css"; +* { + box-sizing: border-box; + margin-inline: 0; + margin-block: 0; +} + body { background: var(--cru-bg-color); color: var(--cru-text-color); + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } + .cru-text-center { text-align: center; } diff --git a/FrontEnd/src/views/common/theme-color.css b/FrontEnd/src/views/common/theme-color.css new file mode 100644 index 00000000..9dfa1d9a --- /dev/null +++ b/FrontEnd/src/views/common/theme-color.css @@ -0,0 +1,260 @@ +/* Generated by theme-generator.ts */ + +:root { + --cru-primary-color: hsl(210 100% 50%); + --cru-primary-l1-color: hsl(210 100% 55%); + --cru-primary-l2-color: hsl(210 100% 60%); + --cru-primary-l3-color: hsl(210 100% 65%); + --cru-primary-d1-color: hsl(210 100% 45%); + --cru-primary-d2-color: hsl(210 100% 40%); + --cru-primary-d3-color: hsl(210 100% 35%); + --cru-primary-f1-color: hsl(210 100% 55%); + --cru-primary-f2-color: hsl(210 100% 60%); + --cru-primary-f3-color: hsl(210 100% 65%); + --cru-primary-b1-color: hsl(210 100% 45%); + --cru-primary-b2-color: hsl(210 100% 40%); + --cru-primary-b3-color: hsl(210 100% 35%); + --cru-secondary-color: hsl(40 100% 50%); + --cru-secondary-l1-color: hsl(40 100% 55%); + --cru-secondary-l2-color: hsl(40 100% 60%); + --cru-secondary-l3-color: hsl(40 100% 65%); + --cru-secondary-d1-color: hsl(40 100% 45%); + --cru-secondary-d2-color: hsl(40 100% 40%); + --cru-secondary-d3-color: hsl(40 100% 35%); + --cru-secondary-f1-color: hsl(40 100% 55%); + --cru-secondary-f2-color: hsl(40 100% 60%); + --cru-secondary-f3-color: hsl(40 100% 65%); + --cru-secondary-b1-color: hsl(40 100% 45%); + --cru-secondary-b2-color: hsl(40 100% 40%); + --cru-secondary-b3-color: hsl(40 100% 35%); + --cru-tertiary-color: hsl(160 100% 50%); + --cru-tertiary-l1-color: hsl(160 100% 55%); + --cru-tertiary-l2-color: hsl(160 100% 60%); + --cru-tertiary-l3-color: hsl(160 100% 65%); + --cru-tertiary-d1-color: hsl(160 100% 45%); + --cru-tertiary-d2-color: hsl(160 100% 40%); + --cru-tertiary-d3-color: hsl(160 100% 35%); + --cru-tertiary-f1-color: hsl(160 100% 55%); + --cru-tertiary-f2-color: hsl(160 100% 60%); + --cru-tertiary-f3-color: hsl(160 100% 65%); + --cru-tertiary-b1-color: hsl(160 100% 45%); + --cru-tertiary-b2-color: hsl(160 100% 40%); + --cru-tertiary-b3-color: hsl(160 100% 35%); + --cru-danger-color: hsl(0 100% 50%); + --cru-danger-l1-color: hsl(0 100% 55%); + --cru-danger-l2-color: hsl(0 100% 60%); + --cru-danger-l3-color: hsl(0 100% 65%); + --cru-danger-d1-color: hsl(0 100% 45%); + --cru-danger-d2-color: hsl(0 100% 40%); + --cru-danger-d3-color: hsl(0 100% 35%); + --cru-danger-f1-color: hsl(0 100% 55%); + --cru-danger-f2-color: hsl(0 100% 60%); + --cru-danger-f3-color: hsl(0 100% 65%); + --cru-danger-b1-color: hsl(0 100% 45%); + --cru-danger-b2-color: hsl(0 100% 40%); + --cru-danger-b3-color: hsl(0 100% 35%); + --cru-success-color: hsl(120 60% 50%); + --cru-success-l1-color: hsl(120 60% 55%); + --cru-success-l2-color: hsl(120 60% 60%); + --cru-success-l3-color: hsl(120 60% 65%); + --cru-success-d1-color: hsl(120 60% 45%); + --cru-success-d2-color: hsl(120 60% 40%); + --cru-success-d3-color: hsl(120 60% 35%); + --cru-success-f1-color: hsl(120 60% 55%); + --cru-success-f2-color: hsl(120 60% 60%); + --cru-success-f3-color: hsl(120 60% 65%); + --cru-success-b1-color: hsl(120 60% 45%); + --cru-success-b2-color: hsl(120 60% 40%); + --cru-success-b3-color: hsl(120 60% 35%); + --cru-text-color: hsl(0 0% 0%); + --cru-text-1-color: hsl(0 0% 5%); + --cru-text-2-color: hsl(0 0% 10%); + --cru-text-3-color: hsl(0 0% 15%); + --cru-bg-color: hsl(0 0% 100%); + --cru-bg-1-color: hsl(0 0% 95%); + --cru-bg-2-color: hsl(0 0% 90%); + --cru-bg-3-color: hsl(0 0% 85%); + --cru-light-color: hsl(0 0% 100%); + --cru-light-1-color: hsl(0 0% 95%); + --cru-light-2-color: hsl(0 0% 90%); + --cru-light-3-color: hsl(0 0% 85%); + --cru-dark-color: hsl(0 0% 0%); + --cru-dark-1-color: hsl(0 0% 5%); + --cru-dark-2-color: hsl(0 0% 10%); + --cru-dark-3-color: hsl(0 0% 15%); + --cru-disabled-color: hsl(0 0% 75%); + --cru-disabled-1-color: hsl(0 0% 70%); + --cru-disabled-2-color: hsl(0 0% 65%); + --cru-disabled-3-color: hsl(0 0% 60%); +} + +@media (prefers-color-scheme: dark) { + :root { + --cru-primary-color: hsl(210 100% 50%); + --cru-primary-l1-color: hsl(210 100% 55%); + --cru-primary-l2-color: hsl(210 100% 60%); + --cru-primary-l3-color: hsl(210 100% 65%); + --cru-primary-d1-color: hsl(210 100% 45%); + --cru-primary-d2-color: hsl(210 100% 40%); + --cru-primary-d3-color: hsl(210 100% 35%); + --cru-primary-f1-color: hsl(210 100% 45%); + --cru-primary-f2-color: hsl(210 100% 40%); + --cru-primary-f3-color: hsl(210 100% 35%); + --cru-primary-b1-color: hsl(210 100% 55%); + --cru-primary-b2-color: hsl(210 100% 60%); + --cru-primary-b3-color: hsl(210 100% 65%); + --cru-secondary-color: hsl(40 100% 50%); + --cru-secondary-l1-color: hsl(40 100% 55%); + --cru-secondary-l2-color: hsl(40 100% 60%); + --cru-secondary-l3-color: hsl(40 100% 65%); + --cru-secondary-d1-color: hsl(40 100% 45%); + --cru-secondary-d2-color: hsl(40 100% 40%); + --cru-secondary-d3-color: hsl(40 100% 35%); + --cru-secondary-f1-color: hsl(40 100% 45%); + --cru-secondary-f2-color: hsl(40 100% 40%); + --cru-secondary-f3-color: hsl(40 100% 35%); + --cru-secondary-b1-color: hsl(40 100% 55%); + --cru-secondary-b2-color: hsl(40 100% 60%); + --cru-secondary-b3-color: hsl(40 100% 65%); + --cru-tertiary-color: hsl(160 100% 50%); + --cru-tertiary-l1-color: hsl(160 100% 55%); + --cru-tertiary-l2-color: hsl(160 100% 60%); + --cru-tertiary-l3-color: hsl(160 100% 65%); + --cru-tertiary-d1-color: hsl(160 100% 45%); + --cru-tertiary-d2-color: hsl(160 100% 40%); + --cru-tertiary-d3-color: hsl(160 100% 35%); + --cru-tertiary-f1-color: hsl(160 100% 45%); + --cru-tertiary-f2-color: hsl(160 100% 40%); + --cru-tertiary-f3-color: hsl(160 100% 35%); + --cru-tertiary-b1-color: hsl(160 100% 55%); + --cru-tertiary-b2-color: hsl(160 100% 60%); + --cru-tertiary-b3-color: hsl(160 100% 65%); + --cru-danger-color: hsl(0 100% 50%); + --cru-danger-l1-color: hsl(0 100% 55%); + --cru-danger-l2-color: hsl(0 100% 60%); + --cru-danger-l3-color: hsl(0 100% 65%); + --cru-danger-d1-color: hsl(0 100% 45%); + --cru-danger-d2-color: hsl(0 100% 40%); + --cru-danger-d3-color: hsl(0 100% 35%); + --cru-danger-f1-color: hsl(0 100% 45%); + --cru-danger-f2-color: hsl(0 100% 40%); + --cru-danger-f3-color: hsl(0 100% 35%); + --cru-danger-b1-color: hsl(0 100% 55%); + --cru-danger-b2-color: hsl(0 100% 60%); + --cru-danger-b3-color: hsl(0 100% 65%); + --cru-success-color: hsl(120 60% 50%); + --cru-success-l1-color: hsl(120 60% 55%); + --cru-success-l2-color: hsl(120 60% 60%); + --cru-success-l3-color: hsl(120 60% 65%); + --cru-success-d1-color: hsl(120 60% 45%); + --cru-success-d2-color: hsl(120 60% 40%); + --cru-success-d3-color: hsl(120 60% 35%); + --cru-success-f1-color: hsl(120 60% 45%); + --cru-success-f2-color: hsl(120 60% 40%); + --cru-success-f3-color: hsl(120 60% 35%); + --cru-success-b1-color: hsl(120 60% 55%); + --cru-success-b2-color: hsl(120 60% 60%); + --cru-success-b3-color: hsl(120 60% 65%); + --cru-text-color: hsl(0 0% 100%); + --cru-text-1-color: hsl(0 0% 95%); + --cru-text-2-color: hsl(0 0% 90%); + --cru-text-3-color: hsl(0 0% 85%); + --cru-bg-color: hsl(0 0% 0%); + --cru-bg-1-color: hsl(0 0% 5%); + --cru-bg-2-color: hsl(0 0% 10%); + --cru-bg-3-color: hsl(0 0% 15%); + --cru-light-color: hsl(0 0% 100%); + --cru-light-1-color: hsl(0 0% 95%); + --cru-light-2-color: hsl(0 0% 90%); + --cru-light-3-color: hsl(0 0% 85%); + --cru-dark-color: hsl(0 0% 0%); + --cru-dark-1-color: hsl(0 0% 5%); + --cru-dark-2-color: hsl(0 0% 10%); + --cru-dark-3-color: hsl(0 0% 15%); + --cru-disabled-color: hsl(0 0% 25%); + --cru-disabled-1-color: hsl(0 0% 30%); + --cru-disabled-2-color: hsl(0 0% 35%); + --cru-disabled-3-color: hsl(0 0% 40%); + } +} + +.cru-primary { + --cru-theme-color: var(--cru-primary-color); + --cru-theme-l1-color: var(--cru-primary-l1-color); + --cru-theme-l2-color: var(--cru-primary-l2-color); + --cru-theme-l3-color: var(--cru-primary-l3-color); + --cru-theme-d1-color: var(--cru-primary-d1-color); + --cru-theme-d2-color: var(--cru-primary-d2-color); + --cru-theme-d3-color: var(--cru-primary-d3-color); + --cru-theme-f1-color: var(--cru-primary-f1-color); + --cru-theme-f2-color: var(--cru-primary-f2-color); + --cru-theme-f3-color: var(--cru-primary-f3-color); + --cru-theme-b1-color: var(--cru-primary-b1-color); + --cru-theme-b2-color: var(--cru-primary-b2-color); + --cru-theme-b3-color: var(--cru-primary-b3-color); +} + +.cru-secondary { + --cru-theme-color: var(--cru-secondary-color); + --cru-theme-l1-color: var(--cru-secondary-l1-color); + --cru-theme-l2-color: var(--cru-secondary-l2-color); + --cru-theme-l3-color: var(--cru-secondary-l3-color); + --cru-theme-d1-color: var(--cru-secondary-d1-color); + --cru-theme-d2-color: var(--cru-secondary-d2-color); + --cru-theme-d3-color: var(--cru-secondary-d3-color); + --cru-theme-f1-color: var(--cru-secondary-f1-color); + --cru-theme-f2-color: var(--cru-secondary-f2-color); + --cru-theme-f3-color: var(--cru-secondary-f3-color); + --cru-theme-b1-color: var(--cru-secondary-b1-color); + --cru-theme-b2-color: var(--cru-secondary-b2-color); + --cru-theme-b3-color: var(--cru-secondary-b3-color); +} + +.cru-tertiary { + --cru-theme-color: var(--cru-tertiary-color); + --cru-theme-l1-color: var(--cru-tertiary-l1-color); + --cru-theme-l2-color: var(--cru-tertiary-l2-color); + --cru-theme-l3-color: var(--cru-tertiary-l3-color); + --cru-theme-d1-color: var(--cru-tertiary-d1-color); + --cru-theme-d2-color: var(--cru-tertiary-d2-color); + --cru-theme-d3-color: var(--cru-tertiary-d3-color); + --cru-theme-f1-color: var(--cru-tertiary-f1-color); + --cru-theme-f2-color: var(--cru-tertiary-f2-color); + --cru-theme-f3-color: var(--cru-tertiary-f3-color); + --cru-theme-b1-color: var(--cru-tertiary-b1-color); + --cru-theme-b2-color: var(--cru-tertiary-b2-color); + --cru-theme-b3-color: var(--cru-tertiary-b3-color); +} + +.cru-danger { + --cru-theme-color: var(--cru-danger-color); + --cru-theme-l1-color: var(--cru-danger-l1-color); + --cru-theme-l2-color: var(--cru-danger-l2-color); + --cru-theme-l3-color: var(--cru-danger-l3-color); + --cru-theme-d1-color: var(--cru-danger-d1-color); + --cru-theme-d2-color: var(--cru-danger-d2-color); + --cru-theme-d3-color: var(--cru-danger-d3-color); + --cru-theme-f1-color: var(--cru-danger-f1-color); + --cru-theme-f2-color: var(--cru-danger-f2-color); + --cru-theme-f3-color: var(--cru-danger-f3-color); + --cru-theme-b1-color: var(--cru-danger-b1-color); + --cru-theme-b2-color: var(--cru-danger-b2-color); + --cru-theme-b3-color: var(--cru-danger-b3-color); +} + +.cru-success { + --cru-theme-color: var(--cru-success-color); + --cru-theme-l1-color: var(--cru-success-l1-color); + --cru-theme-l2-color: var(--cru-success-l2-color); + --cru-theme-l3-color: var(--cru-success-l3-color); + --cru-theme-d1-color: var(--cru-success-d1-color); + --cru-theme-d2-color: var(--cru-success-d2-color); + --cru-theme-d3-color: var(--cru-success-d3-color); + --cru-theme-f1-color: var(--cru-success-f1-color); + --cru-theme-f2-color: var(--cru-success-f2-color); + --cru-theme-f3-color: var(--cru-success-f3-color); + --cru-theme-b1-color: var(--cru-success-b1-color); + --cru-theme-b2-color: var(--cru-success-b2-color); + --cru-theme-b3-color: var(--cru-success-b3-color); +} + diff --git a/FrontEnd/src/views/common/theme.css b/FrontEnd/src/views/common/theme.css index 9dfa1d9a..28c16627 100644 --- a/FrontEnd/src/views/common/theme.css +++ b/FrontEnd/src/views/common/theme.css @@ -1,260 +1,5 @@ -/* Generated by theme-generator.ts */ +@import "./theme-color.css"; :root { - --cru-primary-color: hsl(210 100% 50%); - --cru-primary-l1-color: hsl(210 100% 55%); - --cru-primary-l2-color: hsl(210 100% 60%); - --cru-primary-l3-color: hsl(210 100% 65%); - --cru-primary-d1-color: hsl(210 100% 45%); - --cru-primary-d2-color: hsl(210 100% 40%); - --cru-primary-d3-color: hsl(210 100% 35%); - --cru-primary-f1-color: hsl(210 100% 55%); - --cru-primary-f2-color: hsl(210 100% 60%); - --cru-primary-f3-color: hsl(210 100% 65%); - --cru-primary-b1-color: hsl(210 100% 45%); - --cru-primary-b2-color: hsl(210 100% 40%); - --cru-primary-b3-color: hsl(210 100% 35%); - --cru-secondary-color: hsl(40 100% 50%); - --cru-secondary-l1-color: hsl(40 100% 55%); - --cru-secondary-l2-color: hsl(40 100% 60%); - --cru-secondary-l3-color: hsl(40 100% 65%); - --cru-secondary-d1-color: hsl(40 100% 45%); - --cru-secondary-d2-color: hsl(40 100% 40%); - --cru-secondary-d3-color: hsl(40 100% 35%); - --cru-secondary-f1-color: hsl(40 100% 55%); - --cru-secondary-f2-color: hsl(40 100% 60%); - --cru-secondary-f3-color: hsl(40 100% 65%); - --cru-secondary-b1-color: hsl(40 100% 45%); - --cru-secondary-b2-color: hsl(40 100% 40%); - --cru-secondary-b3-color: hsl(40 100% 35%); - --cru-tertiary-color: hsl(160 100% 50%); - --cru-tertiary-l1-color: hsl(160 100% 55%); - --cru-tertiary-l2-color: hsl(160 100% 60%); - --cru-tertiary-l3-color: hsl(160 100% 65%); - --cru-tertiary-d1-color: hsl(160 100% 45%); - --cru-tertiary-d2-color: hsl(160 100% 40%); - --cru-tertiary-d3-color: hsl(160 100% 35%); - --cru-tertiary-f1-color: hsl(160 100% 55%); - --cru-tertiary-f2-color: hsl(160 100% 60%); - --cru-tertiary-f3-color: hsl(160 100% 65%); - --cru-tertiary-b1-color: hsl(160 100% 45%); - --cru-tertiary-b2-color: hsl(160 100% 40%); - --cru-tertiary-b3-color: hsl(160 100% 35%); - --cru-danger-color: hsl(0 100% 50%); - --cru-danger-l1-color: hsl(0 100% 55%); - --cru-danger-l2-color: hsl(0 100% 60%); - --cru-danger-l3-color: hsl(0 100% 65%); - --cru-danger-d1-color: hsl(0 100% 45%); - --cru-danger-d2-color: hsl(0 100% 40%); - --cru-danger-d3-color: hsl(0 100% 35%); - --cru-danger-f1-color: hsl(0 100% 55%); - --cru-danger-f2-color: hsl(0 100% 60%); - --cru-danger-f3-color: hsl(0 100% 65%); - --cru-danger-b1-color: hsl(0 100% 45%); - --cru-danger-b2-color: hsl(0 100% 40%); - --cru-danger-b3-color: hsl(0 100% 35%); - --cru-success-color: hsl(120 60% 50%); - --cru-success-l1-color: hsl(120 60% 55%); - --cru-success-l2-color: hsl(120 60% 60%); - --cru-success-l3-color: hsl(120 60% 65%); - --cru-success-d1-color: hsl(120 60% 45%); - --cru-success-d2-color: hsl(120 60% 40%); - --cru-success-d3-color: hsl(120 60% 35%); - --cru-success-f1-color: hsl(120 60% 55%); - --cru-success-f2-color: hsl(120 60% 60%); - --cru-success-f3-color: hsl(120 60% 65%); - --cru-success-b1-color: hsl(120 60% 45%); - --cru-success-b2-color: hsl(120 60% 40%); - --cru-success-b3-color: hsl(120 60% 35%); - --cru-text-color: hsl(0 0% 0%); - --cru-text-1-color: hsl(0 0% 5%); - --cru-text-2-color: hsl(0 0% 10%); - --cru-text-3-color: hsl(0 0% 15%); - --cru-bg-color: hsl(0 0% 100%); - --cru-bg-1-color: hsl(0 0% 95%); - --cru-bg-2-color: hsl(0 0% 90%); - --cru-bg-3-color: hsl(0 0% 85%); - --cru-light-color: hsl(0 0% 100%); - --cru-light-1-color: hsl(0 0% 95%); - --cru-light-2-color: hsl(0 0% 90%); - --cru-light-3-color: hsl(0 0% 85%); - --cru-dark-color: hsl(0 0% 0%); - --cru-dark-1-color: hsl(0 0% 5%); - --cru-dark-2-color: hsl(0 0% 10%); - --cru-dark-3-color: hsl(0 0% 15%); - --cru-disabled-color: hsl(0 0% 75%); - --cru-disabled-1-color: hsl(0 0% 70%); - --cru-disabled-2-color: hsl(0 0% 65%); - --cru-disabled-3-color: hsl(0 0% 60%); -} - -@media (prefers-color-scheme: dark) { - :root { - --cru-primary-color: hsl(210 100% 50%); - --cru-primary-l1-color: hsl(210 100% 55%); - --cru-primary-l2-color: hsl(210 100% 60%); - --cru-primary-l3-color: hsl(210 100% 65%); - --cru-primary-d1-color: hsl(210 100% 45%); - --cru-primary-d2-color: hsl(210 100% 40%); - --cru-primary-d3-color: hsl(210 100% 35%); - --cru-primary-f1-color: hsl(210 100% 45%); - --cru-primary-f2-color: hsl(210 100% 40%); - --cru-primary-f3-color: hsl(210 100% 35%); - --cru-primary-b1-color: hsl(210 100% 55%); - --cru-primary-b2-color: hsl(210 100% 60%); - --cru-primary-b3-color: hsl(210 100% 65%); - --cru-secondary-color: hsl(40 100% 50%); - --cru-secondary-l1-color: hsl(40 100% 55%); - --cru-secondary-l2-color: hsl(40 100% 60%); - --cru-secondary-l3-color: hsl(40 100% 65%); - --cru-secondary-d1-color: hsl(40 100% 45%); - --cru-secondary-d2-color: hsl(40 100% 40%); - --cru-secondary-d3-color: hsl(40 100% 35%); - --cru-secondary-f1-color: hsl(40 100% 45%); - --cru-secondary-f2-color: hsl(40 100% 40%); - --cru-secondary-f3-color: hsl(40 100% 35%); - --cru-secondary-b1-color: hsl(40 100% 55%); - --cru-secondary-b2-color: hsl(40 100% 60%); - --cru-secondary-b3-color: hsl(40 100% 65%); - --cru-tertiary-color: hsl(160 100% 50%); - --cru-tertiary-l1-color: hsl(160 100% 55%); - --cru-tertiary-l2-color: hsl(160 100% 60%); - --cru-tertiary-l3-color: hsl(160 100% 65%); - --cru-tertiary-d1-color: hsl(160 100% 45%); - --cru-tertiary-d2-color: hsl(160 100% 40%); - --cru-tertiary-d3-color: hsl(160 100% 35%); - --cru-tertiary-f1-color: hsl(160 100% 45%); - --cru-tertiary-f2-color: hsl(160 100% 40%); - --cru-tertiary-f3-color: hsl(160 100% 35%); - --cru-tertiary-b1-color: hsl(160 100% 55%); - --cru-tertiary-b2-color: hsl(160 100% 60%); - --cru-tertiary-b3-color: hsl(160 100% 65%); - --cru-danger-color: hsl(0 100% 50%); - --cru-danger-l1-color: hsl(0 100% 55%); - --cru-danger-l2-color: hsl(0 100% 60%); - --cru-danger-l3-color: hsl(0 100% 65%); - --cru-danger-d1-color: hsl(0 100% 45%); - --cru-danger-d2-color: hsl(0 100% 40%); - --cru-danger-d3-color: hsl(0 100% 35%); - --cru-danger-f1-color: hsl(0 100% 45%); - --cru-danger-f2-color: hsl(0 100% 40%); - --cru-danger-f3-color: hsl(0 100% 35%); - --cru-danger-b1-color: hsl(0 100% 55%); - --cru-danger-b2-color: hsl(0 100% 60%); - --cru-danger-b3-color: hsl(0 100% 65%); - --cru-success-color: hsl(120 60% 50%); - --cru-success-l1-color: hsl(120 60% 55%); - --cru-success-l2-color: hsl(120 60% 60%); - --cru-success-l3-color: hsl(120 60% 65%); - --cru-success-d1-color: hsl(120 60% 45%); - --cru-success-d2-color: hsl(120 60% 40%); - --cru-success-d3-color: hsl(120 60% 35%); - --cru-success-f1-color: hsl(120 60% 45%); - --cru-success-f2-color: hsl(120 60% 40%); - --cru-success-f3-color: hsl(120 60% 35%); - --cru-success-b1-color: hsl(120 60% 55%); - --cru-success-b2-color: hsl(120 60% 60%); - --cru-success-b3-color: hsl(120 60% 65%); - --cru-text-color: hsl(0 0% 100%); - --cru-text-1-color: hsl(0 0% 95%); - --cru-text-2-color: hsl(0 0% 90%); - --cru-text-3-color: hsl(0 0% 85%); - --cru-bg-color: hsl(0 0% 0%); - --cru-bg-1-color: hsl(0 0% 5%); - --cru-bg-2-color: hsl(0 0% 10%); - --cru-bg-3-color: hsl(0 0% 15%); - --cru-light-color: hsl(0 0% 100%); - --cru-light-1-color: hsl(0 0% 95%); - --cru-light-2-color: hsl(0 0% 90%); - --cru-light-3-color: hsl(0 0% 85%); - --cru-dark-color: hsl(0 0% 0%); - --cru-dark-1-color: hsl(0 0% 5%); - --cru-dark-2-color: hsl(0 0% 10%); - --cru-dark-3-color: hsl(0 0% 15%); - --cru-disabled-color: hsl(0 0% 25%); - --cru-disabled-1-color: hsl(0 0% 30%); - --cru-disabled-2-color: hsl(0 0% 35%); - --cru-disabled-3-color: hsl(0 0% 40%); - } -} - -.cru-primary { - --cru-theme-color: var(--cru-primary-color); - --cru-theme-l1-color: var(--cru-primary-l1-color); - --cru-theme-l2-color: var(--cru-primary-l2-color); - --cru-theme-l3-color: var(--cru-primary-l3-color); - --cru-theme-d1-color: var(--cru-primary-d1-color); - --cru-theme-d2-color: var(--cru-primary-d2-color); - --cru-theme-d3-color: var(--cru-primary-d3-color); - --cru-theme-f1-color: var(--cru-primary-f1-color); - --cru-theme-f2-color: var(--cru-primary-f2-color); - --cru-theme-f3-color: var(--cru-primary-f3-color); - --cru-theme-b1-color: var(--cru-primary-b1-color); - --cru-theme-b2-color: var(--cru-primary-b2-color); - --cru-theme-b3-color: var(--cru-primary-b3-color); -} - -.cru-secondary { - --cru-theme-color: var(--cru-secondary-color); - --cru-theme-l1-color: var(--cru-secondary-l1-color); - --cru-theme-l2-color: var(--cru-secondary-l2-color); - --cru-theme-l3-color: var(--cru-secondary-l3-color); - --cru-theme-d1-color: var(--cru-secondary-d1-color); - --cru-theme-d2-color: var(--cru-secondary-d2-color); - --cru-theme-d3-color: var(--cru-secondary-d3-color); - --cru-theme-f1-color: var(--cru-secondary-f1-color); - --cru-theme-f2-color: var(--cru-secondary-f2-color); - --cru-theme-f3-color: var(--cru-secondary-f3-color); - --cru-theme-b1-color: var(--cru-secondary-b1-color); - --cru-theme-b2-color: var(--cru-secondary-b2-color); - --cru-theme-b3-color: var(--cru-secondary-b3-color); -} - -.cru-tertiary { - --cru-theme-color: var(--cru-tertiary-color); - --cru-theme-l1-color: var(--cru-tertiary-l1-color); - --cru-theme-l2-color: var(--cru-tertiary-l2-color); - --cru-theme-l3-color: var(--cru-tertiary-l3-color); - --cru-theme-d1-color: var(--cru-tertiary-d1-color); - --cru-theme-d2-color: var(--cru-tertiary-d2-color); - --cru-theme-d3-color: var(--cru-tertiary-d3-color); - --cru-theme-f1-color: var(--cru-tertiary-f1-color); - --cru-theme-f2-color: var(--cru-tertiary-f2-color); - --cru-theme-f3-color: var(--cru-tertiary-f3-color); - --cru-theme-b1-color: var(--cru-tertiary-b1-color); - --cru-theme-b2-color: var(--cru-tertiary-b2-color); - --cru-theme-b3-color: var(--cru-tertiary-b3-color); -} - -.cru-danger { - --cru-theme-color: var(--cru-danger-color); - --cru-theme-l1-color: var(--cru-danger-l1-color); - --cru-theme-l2-color: var(--cru-danger-l2-color); - --cru-theme-l3-color: var(--cru-danger-l3-color); - --cru-theme-d1-color: var(--cru-danger-d1-color); - --cru-theme-d2-color: var(--cru-danger-d2-color); - --cru-theme-d3-color: var(--cru-danger-d3-color); - --cru-theme-f1-color: var(--cru-danger-f1-color); - --cru-theme-f2-color: var(--cru-danger-f2-color); - --cru-theme-f3-color: var(--cru-danger-f3-color); - --cru-theme-b1-color: var(--cru-danger-b1-color); - --cru-theme-b2-color: var(--cru-danger-b2-color); - --cru-theme-b3-color: var(--cru-danger-b3-color); -} - -.cru-success { - --cru-theme-color: var(--cru-success-color); - --cru-theme-l1-color: var(--cru-success-l1-color); - --cru-theme-l2-color: var(--cru-success-l2-color); - --cru-theme-l3-color: var(--cru-success-l3-color); - --cru-theme-d1-color: var(--cru-success-d1-color); - --cru-theme-d2-color: var(--cru-success-d2-color); - --cru-theme-d3-color: var(--cru-success-d3-color); - --cru-theme-f1-color: var(--cru-success-f1-color); - --cru-theme-f2-color: var(--cru-success-f2-color); - --cru-theme-f3-color: var(--cru-success-f3-color); - --cru-theme-b1-color: var(--cru-success-b1-color); - --cru-theme-b2-color: var(--cru-success-b2-color); - --cru-theme-b3-color: var(--cru-success-b3-color); -} - + --cru-card-border-radius: 8px; +} \ No newline at end of file -- cgit v1.2.3 From 85659d977ac501a13886c1c7098763935af416e2 Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 15 Jul 2023 17:02:00 +0800 Subject: ... --- FrontEnd/src/views/common/AppBar.css | 15 +- FrontEnd/src/views/common/AppBar.tsx | 24 +- FrontEnd/src/views/common/alert/alert.css | 10 +- FrontEnd/src/views/common/button/Button.css | 52 ++-- FrontEnd/src/views/common/button/FlatButton.css | 31 +- FrontEnd/src/views/common/button/IconButton.css | 2 +- FrontEnd/src/views/common/index.css | 14 +- FrontEnd/src/views/common/menu/Menu.css | 6 +- FrontEnd/src/views/common/theme-color.css | 319 ++++++--------------- FrontEnd/src/views/common/theme.css | 31 ++ FrontEnd/tools/theme-generator.ts | 366 ++++++++++++------------ 11 files changed, 385 insertions(+), 485 deletions(-) diff --git a/FrontEnd/src/views/common/AppBar.css b/FrontEnd/src/views/common/AppBar.css index 3ec4fa36..272a99ad 100644 --- a/FrontEnd/src/views/common/AppBar.css +++ b/FrontEnd/src/views/common/AppBar.css @@ -16,16 +16,18 @@ } .app-bar a { - color: var(--cru-primary-t1-color); + color: var(--cru-primary-on-color); text-decoration: none; margin: 0 1em; transition: color 1s; } + .app-bar a:hover { - color: var(--cru-primary-t-color); + color: var(--cru-primary-on-color); } + .app-bar a.active { - color: var(--cru-primary-t-color); + color: var(--cru-primary-on-color); } .app-bar-brand { @@ -65,22 +67,27 @@ background-color: var(--cru-primary-color); flex-direction: column; } + .small-screen .app-bar-main-area.app-bar-collapse { transform: scale(1, 0); } + .small-screen .app-bar-main-area a { text-align: left; padding: 0.5em 0.5em; } + .small-screen .app-bar-link-area { flex-direction: column; align-items: stretch; } + .small-screen .app-bar-user-area { flex-direction: column; align-items: stretch; margin-left: unset; } + .small-screen .app-bar-avatar { align-self: flex-end; } @@ -92,4 +99,4 @@ color: var(--cru-primary-t-color); cursor: pointer; user-select: none; -} +} \ No newline at end of file diff --git a/FrontEnd/src/views/common/AppBar.tsx b/FrontEnd/src/views/common/AppBar.tsx index 278c70fd..444d903e 100644 --- a/FrontEnd/src/views/common/AppBar.tsx +++ b/FrontEnd/src/views/common/AppBar.tsx @@ -1,9 +1,9 @@ import * as React from "react"; import classnames from "classnames"; -import { useTranslation } from "react-i18next"; import { Link, NavLink } from "react-router-dom"; import { useMediaQuery } from "react-responsive"; +import { useC } from "./common"; import { useUser } from "@/services/user"; import TimelineLogo from "./TimelineLogo"; @@ -11,8 +11,8 @@ import UserAvatar from "./user/UserAvatar"; import "./AppBar.css"; -const AppBar: React.FC = () => { - const { t } = useTranslation(); +export default function AppBar() { + const c = useC(); const user = useUser(); const hasAdministrationPermission = user && user.hasAdministrationPermission; @@ -26,7 +26,7 @@ const AppBar: React.FC = () => { const createLink = ( link: string, label: React.ReactNode, - className?: string + className?: string, ): React.ReactNode => ( {
- {createLink("/settings", t("nav.settings"))} - {createLink("/about", t("nav.about"))} + {createLink("/settings", c("nav.settings"))} + {createLink("/about", c("nav.about"))} {hasAdministrationPermission && - createLink("/admin", t("nav.administration"))} + createLink("/admin", c("nav.administration"))}
@@ -69,13 +69,11 @@ const AppBar: React.FC = () => { username={user.username} className="cru-avatar small cru-round cursor-pointer ml-auto" />, - "app-bar-avatar" + "app-bar-avatar", ) - : createLink("/login", t("nav.login"))} + : createLink("/login", c("nav.login"))}
); -}; - -export default AppBar; +} diff --git a/FrontEnd/src/views/common/alert/alert.css b/FrontEnd/src/views/common/alert/alert.css index 83e1af28..54c2b87f 100644 --- a/FrontEnd/src/views/common/alert/alert.css +++ b/FrontEnd/src/views/common/alert/alert.css @@ -5,9 +5,9 @@ .cru-alert { border-radius: 5px; - border: var(--cru-theme-color) 1px solid; - color: var(--cru-theme-t-color); - background-color: var(--cru-theme-b1-color); + border: var(--cru-key-color) 1px solid; + color: var(--cru-key-t-color); + background-color: var(--cru-key-b1-color); display: flex; overflow: hidden; @@ -25,9 +25,9 @@ display: flex; align-items: center; justify-content: center; - background-color: var(--cru-theme-t-color); + background-color: var(--cru-key-t-color); } .cru-alert-close-button { - color: var(--cru-theme-color); + color: var(--cru-key-color); } diff --git a/FrontEnd/src/views/common/button/Button.css b/FrontEnd/src/views/common/button/Button.css index 0df22ebe..dacea3e1 100644 --- a/FrontEnd/src/views/common/button/Button.css +++ b/FrontEnd/src/views/common/button/Button.css @@ -1,46 +1,52 @@ -.cru-button:not(.outline) { - color: var(--cru-light-color); - cursor: pointer; - padding: 0.2em 0.5em; - border-radius: 0.2em; - border: none; +.cru-button { + font-size: 1rem; + padding: 0.4em 0.8em; transition: all 0.5s; - background-color: var(--cru-theme-color); + border-radius: 0.2em; + border: 1px solid; + cursor: pointer; +} + +.cru-button:not(.outline) { + color: var(--cru-key-on-color); + background-color: var(--cru-key-color); + border-color: var(--cru-key-color); } .cru-button:not(.outline):hover { - background-color: var(--cru-theme-d1-color); + filter: brightness(var(--cru-hover-darkness)); +} + +.cru-button:not(.outline):focus { + filter: brightness(var(--cru-focus-darkness)); } .cru-button:not(.outline):active { - background-color: var(--cru-theme-d2-color); + filter: brightness(var(--cru-press-darkness)); } .cru-button:not(.outline):disabled { - background-color: var(--cru-disabled-color); + background-color: var(--cru-surface-on-color); cursor: auto; } + .cru-button.outline { - color: var(--cru-theme-color); - border: var(--cru-theme-color) 1px solid; - cursor: pointer; - padding: 0.2em 0.5em; - border-radius: 0.2em; - transition: all 0.6s; - background-color: var(--cru-background-color); + color: var(--cru-key-color); + border: var(--cru-key-color) 1px solid; + background-color: var(--cru-surface-color); } .cru-button.outline:hover { - color: var(--cru-theme-d1-color); - border-color: var(--cru-theme-d1-color); - background-color: var(--cru-background-color); + filter: brightness(var(--cru-hover-brightness)); +} + +.cru-button.outline:focus { + filter: brightness(var(--cru-focus-brightness)); } .cru-button.outline:active { - color: var(--cru-theme-l2-color); - border-color: var(--cru-theme-l2-color); - background-color: var(--cru-background-1-color); + filter: brightness(var(--cru-press-brightness)); } .cru-button.outline:disabled { diff --git a/FrontEnd/src/views/common/button/FlatButton.css b/FrontEnd/src/views/common/button/FlatButton.css index 01eabca9..f9a7d772 100644 --- a/FrontEnd/src/views/common/button/FlatButton.css +++ b/FrontEnd/src/views/common/button/FlatButton.css @@ -1,18 +1,27 @@ .cru-flat-button { - cursor: pointer; - padding: 0.2em 0.5em; + font-size: 1rem; + padding: 0.4em 0.8em; + transition: all 0.5s; border-radius: 0.2em; - border: none; - background-color: transparent; - transition: all 0.6s; - color: var(--cru-theme-color); + background-color: var(--cru-surface-color); + border: 1px none; + color: var(--cru-key-color); + cursor: pointer; } -.cru-flat-button.disabled { - color: var(--cru-disabled-color); - cursor: default; +.cru-flat-button:hover { + filter: brightness(var(--cru-hover-darkness)); } -.cru-flat-button:hover:not(.disabled) { - background-color: #e9ecef; +.cru-flat-button:focus { + filter: brightness(var(--cru-focus-darkness)); } + +.cru-flat-button:active { + filter: brightness(var(--cru-press-darkness)); +} + +.cru-flat-button.disabled { + color: var(--cru-disabled-color); + cursor: auto; +} \ No newline at end of file diff --git a/FrontEnd/src/views/common/button/IconButton.css b/FrontEnd/src/views/common/button/IconButton.css index 45fb103c..25c5f84c 100644 --- a/FrontEnd/src/views/common/button/IconButton.css +++ b/FrontEnd/src/views/common/button/IconButton.css @@ -1,5 +1,5 @@ .cru-icon-button { - color: var(--cru-theme-color); + color: var(--cru-key-color); font-size: 1.4rem; background: none; border: none; diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css index 9d69997b..bd556a81 100644 --- a/FrontEnd/src/views/common/index.css +++ b/FrontEnd/src/views/common/index.css @@ -6,10 +6,18 @@ margin-block: 0; } +*::before { + box-sizing: border-box; +} + +*::after { + box-sizing: border-box; +} + body { - background: var(--cru-bg-color); - color: var(--cru-text-color); - font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + font-family: var(--cru-default-font-family); + background: var(--cru-surface-color); + color: var(--cru-surface-on-color); } diff --git a/FrontEnd/src/views/common/menu/Menu.css b/FrontEnd/src/views/common/menu/Menu.css index c3fa82c4..93c229f0 100644 --- a/FrontEnd/src/views/common/menu/Menu.css +++ b/FrontEnd/src/views/common/menu/Menu.css @@ -7,12 +7,12 @@ padding: 0.5em 1.5em; cursor: pointer; transition: all 0.5s; - color: var(--cru-theme-color); + color: var(--cru-key-color); } .cru-menu-item:hover { - color: var(--cru-theme-t-color); - background-color: var(--cru-theme-color); + color: var(--cru-key-t-color); + background-color: var(--cru-key-color); } .cru-menu-item-icon { diff --git a/FrontEnd/src/views/common/theme-color.css b/FrontEnd/src/views/common/theme-color.css index 9dfa1d9a..7cb9a8f8 100644 --- a/FrontEnd/src/views/common/theme-color.css +++ b/FrontEnd/src/views/common/theme-color.css @@ -1,260 +1,109 @@ /* Generated by theme-generator.ts */ :root { - --cru-primary-color: hsl(210 100% 50%); - --cru-primary-l1-color: hsl(210 100% 55%); - --cru-primary-l2-color: hsl(210 100% 60%); - --cru-primary-l3-color: hsl(210 100% 65%); - --cru-primary-d1-color: hsl(210 100% 45%); - --cru-primary-d2-color: hsl(210 100% 40%); - --cru-primary-d3-color: hsl(210 100% 35%); - --cru-primary-f1-color: hsl(210 100% 55%); - --cru-primary-f2-color: hsl(210 100% 60%); - --cru-primary-f3-color: hsl(210 100% 65%); - --cru-primary-b1-color: hsl(210 100% 45%); - --cru-primary-b2-color: hsl(210 100% 40%); - --cru-primary-b3-color: hsl(210 100% 35%); - --cru-secondary-color: hsl(40 100% 50%); - --cru-secondary-l1-color: hsl(40 100% 55%); - --cru-secondary-l2-color: hsl(40 100% 60%); - --cru-secondary-l3-color: hsl(40 100% 65%); - --cru-secondary-d1-color: hsl(40 100% 45%); - --cru-secondary-d2-color: hsl(40 100% 40%); - --cru-secondary-d3-color: hsl(40 100% 35%); - --cru-secondary-f1-color: hsl(40 100% 55%); - --cru-secondary-f2-color: hsl(40 100% 60%); - --cru-secondary-f3-color: hsl(40 100% 65%); - --cru-secondary-b1-color: hsl(40 100% 45%); - --cru-secondary-b2-color: hsl(40 100% 40%); - --cru-secondary-b3-color: hsl(40 100% 35%); - --cru-tertiary-color: hsl(160 100% 50%); - --cru-tertiary-l1-color: hsl(160 100% 55%); - --cru-tertiary-l2-color: hsl(160 100% 60%); - --cru-tertiary-l3-color: hsl(160 100% 65%); - --cru-tertiary-d1-color: hsl(160 100% 45%); - --cru-tertiary-d2-color: hsl(160 100% 40%); - --cru-tertiary-d3-color: hsl(160 100% 35%); - --cru-tertiary-f1-color: hsl(160 100% 55%); - --cru-tertiary-f2-color: hsl(160 100% 60%); - --cru-tertiary-f3-color: hsl(160 100% 65%); - --cru-tertiary-b1-color: hsl(160 100% 45%); - --cru-tertiary-b2-color: hsl(160 100% 40%); - --cru-tertiary-b3-color: hsl(160 100% 35%); - --cru-danger-color: hsl(0 100% 50%); - --cru-danger-l1-color: hsl(0 100% 55%); - --cru-danger-l2-color: hsl(0 100% 60%); - --cru-danger-l3-color: hsl(0 100% 65%); - --cru-danger-d1-color: hsl(0 100% 45%); - --cru-danger-d2-color: hsl(0 100% 40%); - --cru-danger-d3-color: hsl(0 100% 35%); - --cru-danger-f1-color: hsl(0 100% 55%); - --cru-danger-f2-color: hsl(0 100% 60%); - --cru-danger-f3-color: hsl(0 100% 65%); - --cru-danger-b1-color: hsl(0 100% 45%); - --cru-danger-b2-color: hsl(0 100% 40%); - --cru-danger-b3-color: hsl(0 100% 35%); - --cru-success-color: hsl(120 60% 50%); - --cru-success-l1-color: hsl(120 60% 55%); - --cru-success-l2-color: hsl(120 60% 60%); - --cru-success-l3-color: hsl(120 60% 65%); - --cru-success-d1-color: hsl(120 60% 45%); - --cru-success-d2-color: hsl(120 60% 40%); - --cru-success-d3-color: hsl(120 60% 35%); - --cru-success-f1-color: hsl(120 60% 55%); - --cru-success-f2-color: hsl(120 60% 60%); - --cru-success-f3-color: hsl(120 60% 65%); - --cru-success-b1-color: hsl(120 60% 45%); - --cru-success-b2-color: hsl(120 60% 40%); - --cru-success-b3-color: hsl(120 60% 35%); - --cru-text-color: hsl(0 0% 0%); - --cru-text-1-color: hsl(0 0% 5%); - --cru-text-2-color: hsl(0 0% 10%); - --cru-text-3-color: hsl(0 0% 15%); - --cru-bg-color: hsl(0 0% 100%); - --cru-bg-1-color: hsl(0 0% 95%); - --cru-bg-2-color: hsl(0 0% 90%); - --cru-bg-3-color: hsl(0 0% 85%); - --cru-light-color: hsl(0 0% 100%); - --cru-light-1-color: hsl(0 0% 95%); - --cru-light-2-color: hsl(0 0% 90%); - --cru-light-3-color: hsl(0 0% 85%); - --cru-dark-color: hsl(0 0% 0%); - --cru-dark-1-color: hsl(0 0% 5%); - --cru-dark-2-color: hsl(0 0% 10%); - --cru-dark-3-color: hsl(0 0% 15%); - --cru-disabled-color: hsl(0 0% 75%); - --cru-disabled-1-color: hsl(0 0% 70%); - --cru-disabled-2-color: hsl(0 0% 65%); - --cru-disabled-3-color: hsl(0 0% 60%); + --cru-primary-color: hsl(210 100% 40%); + --cru-primary-on-color: hsl(210 100% 100%); + --cru-primary-container-color: hsl(210 100% 90%); + --cru-primary-on-container-color: hsl(210 100% 10%); + --cru-secondary-color: hsl(40 100% 40%); + --cru-secondary-on-color: hsl(40 100% 100%); + --cru-secondary-container-color: hsl(40 100% 90%); + --cru-secondary-on-container-color: hsl(40 100% 10%); + --cru-tertiary-color: hsl(160 100% 40%); + --cru-tertiary-on-color: hsl(160 100% 100%); + --cru-tertiary-container-color: hsl(160 100% 90%); + --cru-tertiary-on-container-color: hsl(160 100% 10%); + --cru-danger-color: hsl(0 100% 40%); + --cru-danger-on-color: hsl(0 100% 100%); + --cru-danger-container-color: hsl(0 100% 90%); + --cru-danger-on-container-color: hsl(0 100% 10%); + --cru-success-color: hsl(120 60% 40%); + --cru-success-on-color: hsl(120 60% 100%); + --cru-success-container-color: hsl(120 60% 90%); + --cru-success-on-container-color: hsl(120 60% 10%); + --cru-surface-dim-color: hsl(0 0% 87%); + --cru-surface-color: hsl(0 0% 98%); + --cru-surface-bright-color: hsl(0 0% 98%); + --cru-surface-container-lowest-color: hsl(0 0% 100%); + --cru-surface-container-low-color: hsl(0 0% 96%); + --cru-surface-container-color: hsl(0 0% 94%); + --cru-surface-container-high-color: hsl(0 0% 92%); + --cru-surface-container-highest-color: hsl(0 0% 90%); + --cru-surface-on-color: hsl(0 0% 10%); + --cru-surface-on-variant-color: hsl(0 0% 30%); + --cru-surface-outline-color: hsl(0 0% 50%); + --cru-surface-outline-variant-color: hsl(0 0% 80%); } @media (prefers-color-scheme: dark) { :root { - --cru-primary-color: hsl(210 100% 50%); - --cru-primary-l1-color: hsl(210 100% 55%); - --cru-primary-l2-color: hsl(210 100% 60%); - --cru-primary-l3-color: hsl(210 100% 65%); - --cru-primary-d1-color: hsl(210 100% 45%); - --cru-primary-d2-color: hsl(210 100% 40%); - --cru-primary-d3-color: hsl(210 100% 35%); - --cru-primary-f1-color: hsl(210 100% 45%); - --cru-primary-f2-color: hsl(210 100% 40%); - --cru-primary-f3-color: hsl(210 100% 35%); - --cru-primary-b1-color: hsl(210 100% 55%); - --cru-primary-b2-color: hsl(210 100% 60%); - --cru-primary-b3-color: hsl(210 100% 65%); - --cru-secondary-color: hsl(40 100% 50%); - --cru-secondary-l1-color: hsl(40 100% 55%); - --cru-secondary-l2-color: hsl(40 100% 60%); - --cru-secondary-l3-color: hsl(40 100% 65%); - --cru-secondary-d1-color: hsl(40 100% 45%); - --cru-secondary-d2-color: hsl(40 100% 40%); - --cru-secondary-d3-color: hsl(40 100% 35%); - --cru-secondary-f1-color: hsl(40 100% 45%); - --cru-secondary-f2-color: hsl(40 100% 40%); - --cru-secondary-f3-color: hsl(40 100% 35%); - --cru-secondary-b1-color: hsl(40 100% 55%); - --cru-secondary-b2-color: hsl(40 100% 60%); - --cru-secondary-b3-color: hsl(40 100% 65%); - --cru-tertiary-color: hsl(160 100% 50%); - --cru-tertiary-l1-color: hsl(160 100% 55%); - --cru-tertiary-l2-color: hsl(160 100% 60%); - --cru-tertiary-l3-color: hsl(160 100% 65%); - --cru-tertiary-d1-color: hsl(160 100% 45%); - --cru-tertiary-d2-color: hsl(160 100% 40%); - --cru-tertiary-d3-color: hsl(160 100% 35%); - --cru-tertiary-f1-color: hsl(160 100% 45%); - --cru-tertiary-f2-color: hsl(160 100% 40%); - --cru-tertiary-f3-color: hsl(160 100% 35%); - --cru-tertiary-b1-color: hsl(160 100% 55%); - --cru-tertiary-b2-color: hsl(160 100% 60%); - --cru-tertiary-b3-color: hsl(160 100% 65%); - --cru-danger-color: hsl(0 100% 50%); - --cru-danger-l1-color: hsl(0 100% 55%); - --cru-danger-l2-color: hsl(0 100% 60%); - --cru-danger-l3-color: hsl(0 100% 65%); - --cru-danger-d1-color: hsl(0 100% 45%); - --cru-danger-d2-color: hsl(0 100% 40%); - --cru-danger-d3-color: hsl(0 100% 35%); - --cru-danger-f1-color: hsl(0 100% 45%); - --cru-danger-f2-color: hsl(0 100% 40%); - --cru-danger-f3-color: hsl(0 100% 35%); - --cru-danger-b1-color: hsl(0 100% 55%); - --cru-danger-b2-color: hsl(0 100% 60%); - --cru-danger-b3-color: hsl(0 100% 65%); - --cru-success-color: hsl(120 60% 50%); - --cru-success-l1-color: hsl(120 60% 55%); - --cru-success-l2-color: hsl(120 60% 60%); - --cru-success-l3-color: hsl(120 60% 65%); - --cru-success-d1-color: hsl(120 60% 45%); - --cru-success-d2-color: hsl(120 60% 40%); - --cru-success-d3-color: hsl(120 60% 35%); - --cru-success-f1-color: hsl(120 60% 45%); - --cru-success-f2-color: hsl(120 60% 40%); - --cru-success-f3-color: hsl(120 60% 35%); - --cru-success-b1-color: hsl(120 60% 55%); - --cru-success-b2-color: hsl(120 60% 60%); - --cru-success-b3-color: hsl(120 60% 65%); - --cru-text-color: hsl(0 0% 100%); - --cru-text-1-color: hsl(0 0% 95%); - --cru-text-2-color: hsl(0 0% 90%); - --cru-text-3-color: hsl(0 0% 85%); - --cru-bg-color: hsl(0 0% 0%); - --cru-bg-1-color: hsl(0 0% 5%); - --cru-bg-2-color: hsl(0 0% 10%); - --cru-bg-3-color: hsl(0 0% 15%); - --cru-light-color: hsl(0 0% 100%); - --cru-light-1-color: hsl(0 0% 95%); - --cru-light-2-color: hsl(0 0% 90%); - --cru-light-3-color: hsl(0 0% 85%); - --cru-dark-color: hsl(0 0% 0%); - --cru-dark-1-color: hsl(0 0% 5%); - --cru-dark-2-color: hsl(0 0% 10%); - --cru-dark-3-color: hsl(0 0% 15%); - --cru-disabled-color: hsl(0 0% 25%); - --cru-disabled-1-color: hsl(0 0% 30%); - --cru-disabled-2-color: hsl(0 0% 35%); - --cru-disabled-3-color: hsl(0 0% 40%); + --cru-primary-color: hsl(210 100% 80%); + --cru-primary-on-color: hsl(210 100% 20%); + --cru-primary-container-color: hsl(210 100% 30%); + --cru-primary-on-container-color: hsl(210 100% 90%); + --cru-secondary-color: hsl(40 100% 80%); + --cru-secondary-on-color: hsl(40 100% 20%); + --cru-secondary-container-color: hsl(40 100% 30%); + --cru-secondary-on-container-color: hsl(40 100% 90%); + --cru-tertiary-color: hsl(160 100% 80%); + --cru-tertiary-on-color: hsl(160 100% 20%); + --cru-tertiary-container-color: hsl(160 100% 30%); + --cru-tertiary-on-container-color: hsl(160 100% 90%); + --cru-danger-color: hsl(0 100% 80%); + --cru-danger-on-color: hsl(0 100% 20%); + --cru-danger-container-color: hsl(0 100% 30%); + --cru-danger-on-container-color: hsl(0 100% 90%); + --cru-success-color: hsl(120 60% 80%); + --cru-success-on-color: hsl(120 60% 20%); + --cru-success-container-color: hsl(120 60% 30%); + --cru-success-on-container-color: hsl(120 60% 90%); + --cru-surface-dim-color: hsl(0 0% 6%); + --cru-surface-color: hsl(0 0% 6%); + --cru-surface-bright-color: hsl(0 0% 24%); + --cru-surface-container-lowest-color: hsl(0 0% 4%); + --cru-surface-container-low-color: hsl(0 0% 10%); + --cru-surface-container-color: hsl(0 0% 12%); + --cru-surface-container-high-color: hsl(0 0% 17%); + --cru-surface-container-highest-color: hsl(0 0% 22%); + --cru-surface-on-color: hsl(0 0% 90%); + --cru-surface-on-variant-color: hsl(0 0% 80%); + --cru-surface-outline-color: hsl(0 0% 60%); + --cru-surface-outline-variant-color: hsl(0 0% 30%); } } .cru-primary { - --cru-theme-color: var(--cru-primary-color); - --cru-theme-l1-color: var(--cru-primary-l1-color); - --cru-theme-l2-color: var(--cru-primary-l2-color); - --cru-theme-l3-color: var(--cru-primary-l3-color); - --cru-theme-d1-color: var(--cru-primary-d1-color); - --cru-theme-d2-color: var(--cru-primary-d2-color); - --cru-theme-d3-color: var(--cru-primary-d3-color); - --cru-theme-f1-color: var(--cru-primary-f1-color); - --cru-theme-f2-color: var(--cru-primary-f2-color); - --cru-theme-f3-color: var(--cru-primary-f3-color); - --cru-theme-b1-color: var(--cru-primary-b1-color); - --cru-theme-b2-color: var(--cru-primary-b2-color); - --cru-theme-b3-color: var(--cru-primary-b3-color); + --cru-key-color: var(--cru-primary-color); + --cru-key-on-color: var(--cru-primary-on-color); + --cru-key-container-color: var(--cru-primary-container-color); + --cru-key-on-container-color: var(--cru-primary-on-container-color); } .cru-secondary { - --cru-theme-color: var(--cru-secondary-color); - --cru-theme-l1-color: var(--cru-secondary-l1-color); - --cru-theme-l2-color: var(--cru-secondary-l2-color); - --cru-theme-l3-color: var(--cru-secondary-l3-color); - --cru-theme-d1-color: var(--cru-secondary-d1-color); - --cru-theme-d2-color: var(--cru-secondary-d2-color); - --cru-theme-d3-color: var(--cru-secondary-d3-color); - --cru-theme-f1-color: var(--cru-secondary-f1-color); - --cru-theme-f2-color: var(--cru-secondary-f2-color); - --cru-theme-f3-color: var(--cru-secondary-f3-color); - --cru-theme-b1-color: var(--cru-secondary-b1-color); - --cru-theme-b2-color: var(--cru-secondary-b2-color); - --cru-theme-b3-color: var(--cru-secondary-b3-color); + --cru-key-color: var(--cru-secondary-color); + --cru-key-on-color: var(--cru-secondary-on-color); + --cru-key-container-color: var(--cru-secondary-container-color); + --cru-key-on-container-color: var(--cru-secondary-on-container-color); } .cru-tertiary { - --cru-theme-color: var(--cru-tertiary-color); - --cru-theme-l1-color: var(--cru-tertiary-l1-color); - --cru-theme-l2-color: var(--cru-tertiary-l2-color); - --cru-theme-l3-color: var(--cru-tertiary-l3-color); - --cru-theme-d1-color: var(--cru-tertiary-d1-color); - --cru-theme-d2-color: var(--cru-tertiary-d2-color); - --cru-theme-d3-color: var(--cru-tertiary-d3-color); - --cru-theme-f1-color: var(--cru-tertiary-f1-color); - --cru-theme-f2-color: var(--cru-tertiary-f2-color); - --cru-theme-f3-color: var(--cru-tertiary-f3-color); - --cru-theme-b1-color: var(--cru-tertiary-b1-color); - --cru-theme-b2-color: var(--cru-tertiary-b2-color); - --cru-theme-b3-color: var(--cru-tertiary-b3-color); + --cru-key-color: var(--cru-tertiary-color); + --cru-key-on-color: var(--cru-tertiary-on-color); + --cru-key-container-color: var(--cru-tertiary-container-color); + --cru-key-on-container-color: var(--cru-tertiary-on-container-color); } .cru-danger { - --cru-theme-color: var(--cru-danger-color); - --cru-theme-l1-color: var(--cru-danger-l1-color); - --cru-theme-l2-color: var(--cru-danger-l2-color); - --cru-theme-l3-color: var(--cru-danger-l3-color); - --cru-theme-d1-color: var(--cru-danger-d1-color); - --cru-theme-d2-color: var(--cru-danger-d2-color); - --cru-theme-d3-color: var(--cru-danger-d3-color); - --cru-theme-f1-color: var(--cru-danger-f1-color); - --cru-theme-f2-color: var(--cru-danger-f2-color); - --cru-theme-f3-color: var(--cru-danger-f3-color); - --cru-theme-b1-color: var(--cru-danger-b1-color); - --cru-theme-b2-color: var(--cru-danger-b2-color); - --cru-theme-b3-color: var(--cru-danger-b3-color); + --cru-key-color: var(--cru-danger-color); + --cru-key-on-color: var(--cru-danger-on-color); + --cru-key-container-color: var(--cru-danger-container-color); + --cru-key-on-container-color: var(--cru-danger-on-container-color); } .cru-success { - --cru-theme-color: var(--cru-success-color); - --cru-theme-l1-color: var(--cru-success-l1-color); - --cru-theme-l2-color: var(--cru-success-l2-color); - --cru-theme-l3-color: var(--cru-success-l3-color); - --cru-theme-d1-color: var(--cru-success-d1-color); - --cru-theme-d2-color: var(--cru-success-d2-color); - --cru-theme-d3-color: var(--cru-success-d3-color); - --cru-theme-f1-color: var(--cru-success-f1-color); - --cru-theme-f2-color: var(--cru-success-f2-color); - --cru-theme-f3-color: var(--cru-success-f3-color); - --cru-theme-b1-color: var(--cru-success-b1-color); - --cru-theme-b2-color: var(--cru-success-b2-color); - --cru-theme-b3-color: var(--cru-success-b3-color); + --cru-key-color: var(--cru-success-color); + --cru-key-on-color: var(--cru-success-on-color); + --cru-key-container-color: var(--cru-success-container-color); + --cru-key-on-container-color: var(--cru-success-on-container-color); } diff --git a/FrontEnd/src/views/common/theme.css b/FrontEnd/src/views/common/theme.css index 28c16627..6cbc06b4 100644 --- a/FrontEnd/src/views/common/theme.css +++ b/FrontEnd/src/views/common/theme.css @@ -1,5 +1,36 @@ @import "./theme-color.css"; :root { + --cru-hover-lightness-change: 4%; + --cru-focus-lightness-change: 10%; + --cru-press-lightness-change: 10%; + --cru-drag-lightness-change: 15%; + + --cru-hover-darkness: calc(100% - var(--cru-hover-lightness-change)); + --cru-focus-darkness: calc(100% - var(--cru-focus-lightness-change)); + --cru-press-darkness: calc(100% - var(--cru-press-lightness-change)); + --cru-drag-darkness: calc(100% - var(--cru-drag-lightness-change)); + --cru-hover-brightness: calc(100% + var(--cru-hover-lightness-change)); + --cru-focus-brightness: calc(100% + var(--cru-focus-lightness-change)); + --cru-press-brightness: calc(100% + var(--cru-press-lightness-change)); + --cru-drag-brightness: calc(100% + var(--cru-drag-lightness-change)); +} + +/* +:hover { + filter: brightness(var(--cru-hover-darkness)); +} + +:focus { + filter: brightness(var(--cru-focus-darkness)); +} + +:active { + filter: brightness(var(--cru-press-darkness)); +} +*/ + +:root { + --cru-default-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; --cru-card-border-radius: 8px; } \ No newline at end of file diff --git a/FrontEnd/tools/theme-generator.ts b/FrontEnd/tools/theme-generator.ts index 704a1052..c1036d80 100644 --- a/FrontEnd/tools/theme-generator.ts +++ b/FrontEnd/tools/theme-generator.ts @@ -2,11 +2,10 @@ /** * 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]; + * with variant: --[prefix]-[name]-[variant]-color: [color]; + * + * Lightness variants come from material design (https://m3.material.io/styles/color/the-color-system/tokens) */ import { stdout } from "process"; @@ -29,12 +28,8 @@ class HslColor implements Color { public l: number, ) {} - lighter(level: number): HslColor { - return new HslColor(this.h, this.s, this.l + level * 5); - } - - darker(level: number): HslColor { - return new HslColor(this.h, this.s, this.l - level * 5); + withLightness(lightness: number): HslColor { + return new HslColor(this.h, this.s, lightness); } toCssString(): string { @@ -53,11 +48,11 @@ class ColorVariable implements CssSegment { constructor( public prefix: string, public name: string, - public variant?: string | null, + public variant: string, ) {} toString(): string { - const variantPart = this.variant == null ? "" : `-${this.variant}`; + const variantPart = this.variant !== "" ? `-${this.variant}` : ""; return `--${this.prefix}-${this.name}${variantPart}-color`; } @@ -82,23 +77,15 @@ class CssVarColor implements Color { class ColorVariableDefinition implements CssSegment { constructor( - public name: ColorVariable, + public variable: ColorVariable, public color: Color, ) {} toCssString(): string { - return `${this.name.toCssString()}: ${this.color.toCssString()};`; + return `${this.variable.toCssString()}: ${this.color.toCssString()};`; } } -type LightnessVariantType = "lighter" | "darker"; - -interface LightnessVariantInfo { - prefix: string; - type: LightnessVariantType; - levels: number; -} - abstract class ColorGroup implements CssSegment { abstract getColorVariables(): ColorVariableDefinition[]; toCssString(): string { @@ -108,6 +95,11 @@ abstract class ColorGroup implements CssSegment { } } +interface LightnessVariantInfo { + variant: string; + lightness: number; +} + class LightnessVariantColorGroup extends ColorGroup { constructor( public prefix: string, @@ -119,27 +111,16 @@ class LightnessVariantColorGroup extends ColorGroup { } getColorVariables(): ColorVariableDefinition[] { - const result: ColorVariableDefinition[] = [ - new ColorVariableDefinition( - new ColorVariable(this.prefix, this.name), - this.baseColor, - ), - ]; + const result: ColorVariableDefinition[] = []; for (const lightnessVariant of this.lightnessVariants) { - for (let i = 1; i <= lightnessVariant.levels; i++) { - const color = - lightnessVariant.type === "lighter" - ? this.baseColor.lighter(i) - : this.baseColor.darker(i); - const colorVariant = `${lightnessVariant.prefix}${i}`; - result.push( - new ColorVariableDefinition( - new ColorVariable(this.prefix, this.name, colorVariant), - color, - ), - ); - } + const color = this.baseColor.withLightness(lightnessVariant.lightness); + result.push( + new ColorVariableDefinition( + new ColorVariable(this.prefix, this.name, lightnessVariant.variant), + color, + ), + ); } return result; @@ -157,12 +138,7 @@ class VarAliasColorGroup extends ColorGroup { } getColorVariables(): ColorVariableDefinition[] { - const result = [ - new ColorVariableDefinition( - new ColorVariable(this.prefix, this.newName), - new CssVarColor(new ColorVariable(this.prefix, this.oldName)), - ), - ]; + const result = []; for (const variant of this.variants) { result.push( new ColorVariableDefinition( @@ -177,51 +153,6 @@ class VarAliasColorGroup extends ColorGroup { } } -class GrayscaleColorGroup extends ColorGroup { - _delegate: LightnessVariantColorGroup; - - constructor( - public prefix: string, - public name: string, - public baseColor: HslColor, - public type: LightnessVariantType, - public levels = 3, - ) { - super(); - - this._delegate = new LightnessVariantColorGroup( - prefix, - name, - this.baseColor, - [{ prefix: "", type: this.type, levels }], - ); - } - - getColorVariables(): ColorVariableDefinition[] { - return this._delegate.getColorVariables(); - } - - static white(prefix: string, name: string, levels = 3): GrayscaleColorGroup { - return new GrayscaleColorGroup( - prefix, - name, - HslColor.white, - "darker", - levels, - ); - } - - static black(prefix: string, name: string, levels = 3): GrayscaleColorGroup { - return new GrayscaleColorGroup( - prefix, - name, - HslColor.black, - "lighter", - levels, - ); - } -} - class CompositeColorGroup extends ColorGroup { constructor(public groups: ColorGroup[]) { super(); @@ -234,49 +165,145 @@ class CompositeColorGroup extends ColorGroup { } } -type ThemeColors = { name: string; color: HslColor }[]; +interface ThemeColors { + keyColors: { name: string; color: HslColor }[]; + neutralColor: HslColor; +} type ColorMode = "light" | "dark"; +interface ColorModeColorVariant { + variant: string; + lightness: { light: number; dark: number }; +} + class Theme { - static getDefaultThemeColorLightnessVariants( - mode: ColorMode, - levels = 3, - ): LightnessVariantInfo[] { - return [ - { - prefix: "l", - type: "lighter", - levels, + static keyColorVariants: ColorModeColorVariant[] = [ + { + variant: "", + lightness: { + light: 40, + dark: 80, }, - { - prefix: "d", - type: "darker", - levels, + }, + { + variant: "on", + lightness: { + light: 100, + dark: 20, }, - { - prefix: "f", - type: mode === "light" ? "lighter" : "darker", - levels, + }, + { + variant: "container", + lightness: { + light: 90, + dark: 30, }, - { - prefix: "b", - type: mode === "light" ? "darker" : "lighter", - levels, + }, + { + variant: "on-container", + lightness: { + light: 10, + dark: 90, }, - ]; - } + }, + ]; - static getThemeColorAllVariants(): string[] { - const lightnessVariantInfos = - Theme.getDefaultThemeColorLightnessVariants("light"); - const result: string[] = []; - for (const { prefix, levels } of lightnessVariantInfos) { - for (let i = 1; i <= levels; i++) { - result.push(`${prefix}${i}`); - } - } - return result; + static surfaceColorVariants: ColorModeColorVariant[] = [ + { + variant: "dim", + lightness: { + light: 87, + dark: 6, + }, + }, + { + variant: "", + lightness: { + light: 98, + dark: 6, + }, + }, + { + variant: "bright", + lightness: { + light: 98, + dark: 24, + }, + }, + { + variant: "container-lowest", + lightness: { + light: 100, + dark: 4, + }, + }, + { + variant: "container-low", + lightness: { + light: 96, + dark: 10, + }, + }, + { + variant: "container", + lightness: { + light: 94, + dark: 12, + }, + }, + { + variant: "container-high", + lightness: { + light: 92, + dark: 17, + }, + }, + { + variant: "container-highest", + lightness: { + light: 90, + dark: 22, + }, + }, + { + variant: "on", + lightness: { + light: 10, + dark: 90, + }, + }, + { + variant: "on-variant", + lightness: { + light: 30, + dark: 80, + }, + }, + { + variant: "outline", + lightness: { + light: 50, + dark: 60, + }, + }, + { + variant: "outline-variant", + lightness: { + light: 80, + dark: 30, + }, + }, + ]; + + static getLightnessVariants( + mode: ColorMode, + colorModeColorVariants: ColorModeColorVariant[], + ): LightnessVariantInfo[] { + return colorModeColorVariants.map((v) => ({ + variant: v.variant, + lightness: v.lightness[mode], + })); } constructor( @@ -285,91 +312,53 @@ class Theme { public levels = 3, ) {} - getThemeColorDefinitions(mode: ColorMode): ColorGroup { + getColorModeColorDefinitions(mode: ColorMode): ColorGroup { const groups: ColorGroup[] = []; - for (const { name, color } of this.themeColors) { + for (const { name, color } of this.themeColors.keyColors) { const colorGroup = new LightnessVariantColorGroup( this.prefix, name, color, - Theme.getDefaultThemeColorLightnessVariants(mode, this.levels), + Theme.getLightnessVariants(mode, Theme.keyColorVariants), ); groups.push(colorGroup); } + groups.push( + new LightnessVariantColorGroup( + this.prefix, + "surface", + this.themeColors.neutralColor, + Theme.getLightnessVariants(mode, Theme.surfaceColorVariants), + ), + ); return new CompositeColorGroup(groups); } getAliasColorDefinitions(name: string): ColorGroup { return new VarAliasColorGroup( this.prefix, - "theme", + "key", name, - Theme.getThemeColorAllVariants(), + Theme.keyColorVariants.map((v) => v.variant), ); } - getGrayscaleDefinitions(mode: ColorMode): ColorGroup { - const textGroup = - mode === "light" - ? GrayscaleColorGroup.black(this.prefix, "text", this.levels) - : GrayscaleColorGroup.white(this.prefix, "text", this.levels); - const bgGroup = - mode === "light" - ? GrayscaleColorGroup.white(this.prefix, "bg", this.levels) - : GrayscaleColorGroup.black(this.prefix, "bg", this.levels); - const lightGroup = GrayscaleColorGroup.white( - this.prefix, - "light", - this.levels, - ); - const darkGroup = GrayscaleColorGroup.black( - this.prefix, - "dark", - this.levels, - ); - const disabledGroup = - mode == "light" - ? new GrayscaleColorGroup( - this.prefix, - "disabled", - new HslColor(0, 0, 75), - "darker", - this.levels, - ) - : new GrayscaleColorGroup( - this.prefix, - "disabled", - new HslColor(0, 0, 25), - "lighter", - this.levels, - ); - return new CompositeColorGroup([ - textGroup, - bgGroup, - lightGroup, - darkGroup, - disabledGroup, - ]); - } - generateCss(print: (text: string, indent: number) => void): void { print(":root {", 0); - print(this.getThemeColorDefinitions("light").toCssString(), 1); - print(this.getGrayscaleDefinitions("light").toCssString(), 1); + print(this.getColorModeColorDefinitions("light").toCssString(), 1); print("}", 0); print("", 0); print("@media (prefers-color-scheme: dark) {", 0); print(":root {", 1); - print(this.getThemeColorDefinitions("dark").toCssString(), 2); - print(this.getGrayscaleDefinitions("dark").toCssString(), 2); + print(this.getColorModeColorDefinitions("dark").toCssString(), 2); print("}", 1); print("}", 0); print("", 0); - for (const { name } of this.themeColors) { + for (const { name } of this.themeColors.keyColors) { print(`.${this.prefix}-${name} {`, 0); print(this.getAliasColorDefinitions(name).toCssString(), 1); print("}", 0); @@ -381,13 +370,16 @@ class Theme { (function main() { const prefix = "cru"; - const themeColors: ThemeColors = [ - { name: "primary", color: new HslColor(210, 100, 50) }, - { name: "secondary", color: new HslColor(40, 100, 50) }, - { name: "tertiary", color: new HslColor(160, 100, 50) }, - { name: "danger", color: new HslColor(0, 100, 50) }, - { name: "success", color: new HslColor(120, 60, 50) }, - ]; + const themeColors: ThemeColors = { + keyColors: [ + { name: "primary", color: new HslColor(210, 100, 50) }, + { name: "secondary", color: new HslColor(40, 100, 50) }, + { name: "tertiary", color: new HslColor(160, 100, 50) }, + { name: "danger", color: new HslColor(0, 100, 50) }, + { name: "success", color: new HslColor(120, 60, 50) }, + ], + neutralColor: new HslColor(0, 0, 50), + }; const theme = new Theme(prefix, themeColors); -- cgit v1.2.3 From 2514e709c3ad0a5b7fc62b67462c8ba668f89d2c Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 15 Jul 2023 23:54:25 +0800 Subject: ... --- FrontEnd/src/views/common/AppBar.css | 53 ++++++++++++----------- FrontEnd/src/views/common/AppBar.tsx | 73 +++++++++++++++++++++++++++++++- FrontEnd/src/views/common/breakpoints.ts | 3 ++ FrontEnd/src/views/common/common.ts | 3 ++ FrontEnd/src/views/common/hooks.ts | 14 ++++++ FrontEnd/src/views/common/index.css | 9 ---- 6 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 FrontEnd/src/views/common/breakpoints.ts create mode 100644 FrontEnd/src/views/common/hooks.ts diff --git a/FrontEnd/src/views/common/AppBar.css b/FrontEnd/src/views/common/AppBar.css index 272a99ad..67fd9516 100644 --- a/FrontEnd/src/views/common/AppBar.css +++ b/FrontEnd/src/views/common/AppBar.css @@ -1,6 +1,4 @@ .app-bar { - display: flex; - align-items: center; height: 56px; position: fixed; z-index: 1030; @@ -8,52 +6,53 @@ left: 0; right: 0; background-color: var(--cru-primary-color); - transition: background-color 1s; } -.app-bar .cru-avatar { - background-color: white; +.app-bar.desktop { + display: flex; } -.app-bar a { - color: var(--cru-primary-on-color); - text-decoration: none; - margin: 0 1em; - transition: color 1s; +.app-bar.desktop .app-bar-brand { + display: flex; + align-items: center; } -.app-bar a:hover { - color: var(--cru-primary-on-color); +.app-bar.desktop .app-bar-brand-icon { + height: 2em; } -.app-bar a.active { - color: var(--cru-primary-on-color); +.app-bar.desktop .app-bar-main-area { + display: flex; + flex-grow: 1; } -.app-bar-brand { +.app-bar.desktop .app-bar-link-area { + display: flex; +} + +.app-bar.desktop a { + background-color: var(--cru-primary-color); + color: var(--cru-primary-on-color); + text-decoration: none; display: flex; align-items: center; + padding: 0 1em; } -.app-bar-brand-icon { - height: 2em; +.app-bar.desktop a:hover { + filter: brightness(var(--cru-hover-brightness)); } -.app-bar-main-area { - display: flex; - flex-grow: 1; +.app-bar.desktop a:focus { + filter: brightness(var(--cru-focus-brightness)); } -.app-bar-link-area { - display: flex; - align-items: center; - flex-shrink: 0; +.app-bar.desktop a:active { + filter: brightness(var(--cru-press-brightness)); } -.app-bar-user-area { +.app-bar.desktop .app-bar-user-area { display: flex; - align-items: center; - flex-shrink: 0; margin-left: auto; } diff --git a/FrontEnd/src/views/common/AppBar.tsx b/FrontEnd/src/views/common/AppBar.tsx index 444d903e..180d0db6 100644 --- a/FrontEnd/src/views/common/AppBar.tsx +++ b/FrontEnd/src/views/common/AppBar.tsx @@ -3,7 +3,7 @@ import classnames from "classnames"; import { Link, NavLink } from "react-router-dom"; import { useMediaQuery } from "react-responsive"; -import { useC } from "./common"; +import { I18nText, useC, useMobile } from "./common"; import { useUser } from "@/services/user"; import TimelineLogo from "./TimelineLogo"; @@ -11,7 +11,71 @@ import UserAvatar from "./user/UserAvatar"; import "./AppBar.css"; -export default function AppBar() { +function AppBarNavLink({ + link, + className, + label, + children, +}: { + link: string; + className?: string; + label?: I18nText; + children?: React.ReactNode; +}) { + if (label != null && children != null) { + throw new Error("AppBarNavLink: label and children cannot be both set"); + } + + const c = useC(); + + return ( + classnames(className, isActive && "active")} + > + {children != null ? children : c(label)} + + ); +} + +function DesktopAppBar() { + const user = useUser(); + const hasAdministrationPermission = user && user.hasAdministrationPermission; + + return ( + + ); +} + +// TODO: Go make this! +function MobileAppBar() { const c = useC(); const user = useUser(); @@ -77,3 +141,8 @@ export default function AppBar() { ); } + +export default function AppBar() { + const isMobile = useMobile(); + return isMobile ? : ; +} diff --git a/FrontEnd/src/views/common/breakpoints.ts b/FrontEnd/src/views/common/breakpoints.ts new file mode 100644 index 00000000..fb281610 --- /dev/null +++ b/FrontEnd/src/views/common/breakpoints.ts @@ -0,0 +1,3 @@ +export const breakpoints = { + sm: 576, +} as const; diff --git a/FrontEnd/src/views/common/common.ts b/FrontEnd/src/views/common/common.ts index e3a5a2a2..d3db9f93 100644 --- a/FrontEnd/src/views/common/common.ts +++ b/FrontEnd/src/views/common/common.ts @@ -10,3 +10,6 @@ export const themeColors = [ ] as const; export type ThemeColor = (typeof themeColors)[number]; + +export { breakpoints } from "./breakpoints"; +export { useMobile } from "./hooks"; diff --git a/FrontEnd/src/views/common/hooks.ts b/FrontEnd/src/views/common/hooks.ts new file mode 100644 index 00000000..c1fa5774 --- /dev/null +++ b/FrontEnd/src/views/common/hooks.ts @@ -0,0 +1,14 @@ +// TODO: Migrate hooks + +export { + useIsSmallScreen, + useClickOutside, + useScrollToBottom, +} from "@/utilities/hooks"; + +import { useMediaQuery } from "react-responsive"; +import { breakpoints } from "./breakpoints"; + +export function useMobile(): boolean { + return useMediaQuery({ maxWidth: breakpoints.sm }); +} diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css index bd556a81..f87fdfd2 100644 --- a/FrontEnd/src/views/common/index.css +++ b/FrontEnd/src/views/common/index.css @@ -6,21 +6,12 @@ margin-block: 0; } -*::before { - box-sizing: border-box; -} - -*::after { - box-sizing: border-box; -} - body { font-family: var(--cru-default-font-family); background: var(--cru-surface-color); color: var(--cru-surface-on-color); } - .cru-text-center { text-align: center; } -- cgit v1.2.3 From d712d3847506c5c2df62f741d9d2cb91e34f6bfd Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 17 Jul 2023 17:06:32 +0800 Subject: ... --- FrontEnd/src/views/common/AppBar.css | 7 +- FrontEnd/src/views/common/button/Button.css | 21 ++- FrontEnd/src/views/common/button/FlatButton.css | 6 +- FrontEnd/src/views/common/index.css | 4 + FrontEnd/src/views/common/theme-color.css | 64 +++++++ FrontEnd/src/views/common/theme.css | 30 ---- FrontEnd/tools/theme-generator.ts | 230 ++++++++++++++++-------- 7 files changed, 245 insertions(+), 117 deletions(-) diff --git a/FrontEnd/src/views/common/AppBar.css b/FrontEnd/src/views/common/AppBar.css index 67fd9516..c278aa1e 100644 --- a/FrontEnd/src/views/common/AppBar.css +++ b/FrontEnd/src/views/common/AppBar.css @@ -37,18 +37,19 @@ display: flex; align-items: center; padding: 0 1em; + transition: all 0.5s; } .app-bar.desktop a:hover { - filter: brightness(var(--cru-hover-brightness)); + background-color: var(--cru-primary-1-color); } .app-bar.desktop a:focus { - filter: brightness(var(--cru-focus-brightness)); + background-color: var(--cru-primary-1-color); } .app-bar.desktop a:active { - filter: brightness(var(--cru-press-brightness)); + background-color: var(--cru-primary-2-color); } .app-bar.desktop .app-bar-user-area { diff --git a/FrontEnd/src/views/common/button/Button.css b/FrontEnd/src/views/common/button/Button.css index dacea3e1..55563e00 100644 --- a/FrontEnd/src/views/common/button/Button.css +++ b/FrontEnd/src/views/common/button/Button.css @@ -14,15 +14,18 @@ } .cru-button:not(.outline):hover { - filter: brightness(var(--cru-hover-darkness)); + background-color: var(--cru-key-1-color); + border-color: var(--cru-key-1-color); } .cru-button:not(.outline):focus { - filter: brightness(var(--cru-focus-darkness)); + background-color: var(--cru-key-1-color); + border-color: var(--cru-key-1-color); } .cru-button:not(.outline):active { - filter: brightness(var(--cru-press-darkness)); + background-color: var(--cru-key-2-color); + border-color: var(--cru-key-2-color); } .cru-button:not(.outline):disabled { @@ -33,20 +36,22 @@ .cru-button.outline { color: var(--cru-key-color); - border: var(--cru-key-color) 1px solid; - background-color: var(--cru-surface-color); + border-color: var(--cru-key-color); } .cru-button.outline:hover { - filter: brightness(var(--cru-hover-brightness)); + color: var(--cru-key-1-color); + border-color: var(--cru-key-1-color); } .cru-button.outline:focus { - filter: brightness(var(--cru-focus-brightness)); + color: var(--cru-key-1-color); + border-color: var(--cru-key-1-color); } .cru-button.outline:active { - filter: brightness(var(--cru-press-brightness)); + color: var(--cru-key-2-color); + border-color: var(--cru-key-2-color); } .cru-button.outline:disabled { diff --git a/FrontEnd/src/views/common/button/FlatButton.css b/FrontEnd/src/views/common/button/FlatButton.css index f9a7d772..921fafe4 100644 --- a/FrontEnd/src/views/common/button/FlatButton.css +++ b/FrontEnd/src/views/common/button/FlatButton.css @@ -10,15 +10,15 @@ } .cru-flat-button:hover { - filter: brightness(var(--cru-hover-darkness)); + background-color: var(--cru-surface-1-color); } .cru-flat-button:focus { - filter: brightness(var(--cru-focus-darkness)); + background-color: var(--cru-surface-1-color); } .cru-flat-button:active { - filter: brightness(var(--cru-press-darkness)); + background-color: var(--cru-surface-2-color); } .cru-flat-button.disabled { diff --git a/FrontEnd/src/views/common/index.css b/FrontEnd/src/views/common/index.css index f87fdfd2..789a0f05 100644 --- a/FrontEnd/src/views/common/index.css +++ b/FrontEnd/src/views/common/index.css @@ -12,6 +12,10 @@ body { color: var(--cru-surface-on-color); } +button { + background-color: unset; +} + .cru-text-center { text-align: center; } diff --git a/FrontEnd/src/views/common/theme-color.css b/FrontEnd/src/views/common/theme-color.css index 7cb9a8f8..24a7e267 100644 --- a/FrontEnd/src/views/common/theme-color.css +++ b/FrontEnd/src/views/common/theme-color.css @@ -2,27 +2,49 @@ :root { --cru-primary-color: hsl(210 100% 40%); + --cru-primary-1-color: hsl(210 100% 37%); + --cru-primary-2-color: hsl(210 100% 34%); --cru-primary-on-color: hsl(210 100% 100%); --cru-primary-container-color: hsl(210 100% 90%); + --cru-primary-container-1-color: hsl(210 100% 80%); + --cru-primary-container-2-color: hsl(210 100% 70%); --cru-primary-on-container-color: hsl(210 100% 10%); --cru-secondary-color: hsl(40 100% 40%); + --cru-secondary-1-color: hsl(40 100% 37%); + --cru-secondary-2-color: hsl(40 100% 34%); --cru-secondary-on-color: hsl(40 100% 100%); --cru-secondary-container-color: hsl(40 100% 90%); + --cru-secondary-container-1-color: hsl(40 100% 80%); + --cru-secondary-container-2-color: hsl(40 100% 70%); --cru-secondary-on-container-color: hsl(40 100% 10%); --cru-tertiary-color: hsl(160 100% 40%); + --cru-tertiary-1-color: hsl(160 100% 37%); + --cru-tertiary-2-color: hsl(160 100% 34%); --cru-tertiary-on-color: hsl(160 100% 100%); --cru-tertiary-container-color: hsl(160 100% 90%); + --cru-tertiary-container-1-color: hsl(160 100% 80%); + --cru-tertiary-container-2-color: hsl(160 100% 70%); --cru-tertiary-on-container-color: hsl(160 100% 10%); --cru-danger-color: hsl(0 100% 40%); + --cru-danger-1-color: hsl(0 100% 37%); + --cru-danger-2-color: hsl(0 100% 34%); --cru-danger-on-color: hsl(0 100% 100%); --cru-danger-container-color: hsl(0 100% 90%); + --cru-danger-container-1-color: hsl(0 100% 80%); + --cru-danger-container-2-color: hsl(0 100% 70%); --cru-danger-on-container-color: hsl(0 100% 10%); --cru-success-color: hsl(120 60% 40%); + --cru-success-1-color: hsl(120 60% 37%); + --cru-success-2-color: hsl(120 60% 34%); --cru-success-on-color: hsl(120 60% 100%); --cru-success-container-color: hsl(120 60% 90%); + --cru-success-container-1-color: hsl(120 60% 80%); + --cru-success-container-2-color: hsl(120 60% 70%); --cru-success-on-container-color: hsl(120 60% 10%); --cru-surface-dim-color: hsl(0 0% 87%); --cru-surface-color: hsl(0 0% 98%); + --cru-surface-1-color: hsl(0 0% 90%); + --cru-surface-2-color: hsl(0 0% 82%); --cru-surface-bright-color: hsl(0 0% 98%); --cru-surface-container-lowest-color: hsl(0 0% 100%); --cru-surface-container-low-color: hsl(0 0% 96%); @@ -38,27 +60,49 @@ @media (prefers-color-scheme: dark) { :root { --cru-primary-color: hsl(210 100% 80%); + --cru-primary-1-color: hsl(210 100% 75%); + --cru-primary-2-color: hsl(210 100% 68%); --cru-primary-on-color: hsl(210 100% 20%); --cru-primary-container-color: hsl(210 100% 30%); + --cru-primary-container-1-color: hsl(210 100% 25%); + --cru-primary-container-2-color: hsl(210 100% 20%); --cru-primary-on-container-color: hsl(210 100% 90%); --cru-secondary-color: hsl(40 100% 80%); + --cru-secondary-1-color: hsl(40 100% 75%); + --cru-secondary-2-color: hsl(40 100% 68%); --cru-secondary-on-color: hsl(40 100% 20%); --cru-secondary-container-color: hsl(40 100% 30%); + --cru-secondary-container-1-color: hsl(40 100% 25%); + --cru-secondary-container-2-color: hsl(40 100% 20%); --cru-secondary-on-container-color: hsl(40 100% 90%); --cru-tertiary-color: hsl(160 100% 80%); + --cru-tertiary-1-color: hsl(160 100% 75%); + --cru-tertiary-2-color: hsl(160 100% 68%); --cru-tertiary-on-color: hsl(160 100% 20%); --cru-tertiary-container-color: hsl(160 100% 30%); + --cru-tertiary-container-1-color: hsl(160 100% 25%); + --cru-tertiary-container-2-color: hsl(160 100% 20%); --cru-tertiary-on-container-color: hsl(160 100% 90%); --cru-danger-color: hsl(0 100% 80%); + --cru-danger-1-color: hsl(0 100% 75%); + --cru-danger-2-color: hsl(0 100% 68%); --cru-danger-on-color: hsl(0 100% 20%); --cru-danger-container-color: hsl(0 100% 30%); + --cru-danger-container-1-color: hsl(0 100% 25%); + --cru-danger-container-2-color: hsl(0 100% 20%); --cru-danger-on-container-color: hsl(0 100% 90%); --cru-success-color: hsl(120 60% 80%); + --cru-success-1-color: hsl(120 60% 75%); + --cru-success-2-color: hsl(120 60% 68%); --cru-success-on-color: hsl(120 60% 20%); --cru-success-container-color: hsl(120 60% 30%); + --cru-success-container-1-color: hsl(120 60% 25%); + --cru-success-container-2-color: hsl(120 60% 20%); --cru-success-on-container-color: hsl(120 60% 90%); --cru-surface-dim-color: hsl(0 0% 6%); --cru-surface-color: hsl(0 0% 6%); + --cru-surface-1-color: hsl(0 0% 25%); + --cru-surface-2-color: hsl(0 0% 40%); --cru-surface-bright-color: hsl(0 0% 24%); --cru-surface-container-lowest-color: hsl(0 0% 4%); --cru-surface-container-low-color: hsl(0 0% 10%); @@ -74,36 +118,56 @@ .cru-primary { --cru-key-color: var(--cru-primary-color); + --cru-key-1-color: var(--cru-primary-1-color); + --cru-key-2-color: var(--cru-primary-2-color); --cru-key-on-color: var(--cru-primary-on-color); --cru-key-container-color: var(--cru-primary-container-color); + --cru-key-container-1-color: var(--cru-primary-container-1-color); + --cru-key-container-2-color: var(--cru-primary-container-2-color); --cru-key-on-container-color: var(--cru-primary-on-container-color); } .cru-secondary { --cru-key-color: var(--cru-secondary-color); + --cru-key-1-color: var(--cru-secondary-1-color); + --cru-key-2-color: var(--cru-secondary-2-color); --cru-key-on-color: var(--cru-secondary-on-color); --cru-key-container-color: var(--cru-secondary-container-color); + --cru-key-container-1-color: var(--cru-secondary-container-1-color); + --cru-key-container-2-color: var(--cru-secondary-container-2-color); --cru-key-on-container-color: var(--cru-secondary-on-container-color); } .cru-tertiary { --cru-key-color: var(--cru-tertiary-color); + --cru-key-1-color: var(--cru-tertiary-1-color); + --cru-key-2-color: var(--cru-tertiary-2-color); --cru-key-on-color: var(--cru-tertiary-on-color); --cru-key-container-color: var(--cru-tertiary-container-color); + --cru-key-container-1-color: var(--cru-tertiary-container-1-color); + --cru-key-container-2-color: var(--cru-tertiary-container-2-color); --cru-key-on-container-color: var(--cru-tertiary-on-container-color); } .cru-danger { --cru-key-color: var(--cru-danger-color); + --cru-key-1-color: var(--cru-danger-1-color); + --cru-key-2-color: var(--cru-danger-2-color); --cru-key-on-color: var(--cru-danger-on-color); --cru-key-container-color: var(--cru-danger-container-color); + --cru-key-container-1-color: var(--cru-danger-container-1-color); + --cru-key-container-2-color: var(--cru-danger-container-2-color); --cru-key-on-container-color: var(--cru-danger-on-container-color); } .cru-success { --cru-key-color: var(--cru-success-color); + --cru-key-1-color: var(--cru-success-1-color); + --cru-key-2-color: var(--cru-success-2-color); --cru-key-on-color: var(--cru-success-on-color); --cru-key-container-color: var(--cru-success-container-color); + --cru-key-container-1-color: var(--cru-success-container-1-color); + --cru-key-container-2-color: var(--cru-success-container-2-color); --cru-key-on-container-color: var(--cru-success-on-container-color); } diff --git a/FrontEnd/src/views/common/theme.css b/FrontEnd/src/views/common/theme.css index 6cbc06b4..9c9e1645 100644 --- a/FrontEnd/src/views/common/theme.css +++ b/FrontEnd/src/views/common/theme.css @@ -1,35 +1,5 @@ @import "./theme-color.css"; -:root { - --cru-hover-lightness-change: 4%; - --cru-focus-lightness-change: 10%; - --cru-press-lightness-change: 10%; - --cru-drag-lightness-change: 15%; - - --cru-hover-darkness: calc(100% - var(--cru-hover-lightness-change)); - --cru-focus-darkness: calc(100% - var(--cru-focus-lightness-change)); - --cru-press-darkness: calc(100% - var(--cru-press-lightness-change)); - --cru-drag-darkness: calc(100% - var(--cru-drag-lightness-change)); - --cru-hover-brightness: calc(100% + var(--cru-hover-lightness-change)); - --cru-focus-brightness: calc(100% + var(--cru-focus-lightness-change)); - --cru-press-brightness: calc(100% + var(--cru-press-lightness-change)); - --cru-drag-brightness: calc(100% + var(--cru-drag-lightness-change)); -} - -/* -:hover { - filter: brightness(var(--cru-hover-darkness)); -} - -:focus { - filter: brightness(var(--cru-focus-darkness)); -} - -:active { - filter: brightness(var(--cru-press-darkness)); -} -*/ - :root { --cru-default-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; --cru-card-border-radius: 8px; diff --git a/FrontEnd/tools/theme-generator.ts b/FrontEnd/tools/theme-generator.ts index c1036d80..3583d240 100644 --- a/FrontEnd/tools/theme-generator.ts +++ b/FrontEnd/tools/theme-generator.ts @@ -96,7 +96,7 @@ abstract class ColorGroup implements CssSegment { } interface LightnessVariantInfo { - variant: string; + name: string; lightness: number; } @@ -105,7 +105,7 @@ class LightnessVariantColorGroup extends ColorGroup { public prefix: string, public name: string, public baseColor: HslColor, - public lightnessVariants: LightnessVariantInfo[], + public variants: LightnessVariantInfo[], ) { super(); } @@ -113,11 +113,11 @@ class LightnessVariantColorGroup extends ColorGroup { getColorVariables(): ColorVariableDefinition[] { const result: ColorVariableDefinition[] = []; - for (const lightnessVariant of this.lightnessVariants) { - const color = this.baseColor.withLightness(lightnessVariant.lightness); + for (const variant of this.variants) { + const color = this.baseColor.withLightness(variant.lightness); result.push( new ColorVariableDefinition( - new ColorVariable(this.prefix, this.name, lightnessVariant.variant), + new ColorVariable(this.prefix, this.name, variant.name), color, ), ); @@ -165,181 +165,265 @@ class CompositeColorGroup extends ColorGroup { } } -interface ThemeColors { +interface ThemeColorsInfo { keyColors: { name: string; color: HslColor }[]; neutralColor: HslColor; } type ColorMode = "light" | "dark"; -interface ColorModeColorVariant { - variant: string; - lightness: { light: number; dark: number }; +type ThemeColorVariantLightnessVariantsInfo = + | number + | number[] + | { + base: number; + direction: "darker" | "lighter"; + levels: number; + step: number; + }; + +interface ThemeColorVariantInfo { + name: string; + variants: { + light: ThemeColorVariantLightnessVariantsInfo; + dark: ThemeColorVariantLightnessVariantsInfo; + }; +} + +class ThemeColorVariant { + constructor( + public name: string, + public variants: { + light: ThemeColorVariantLightnessVariantsInfo; + dark: ThemeColorVariantLightnessVariantsInfo; + }, + ) {} + getLightnessVariants(mode: ColorMode): LightnessVariantInfo[] { + const { name, variants } = this; + const list = variants[mode]; + + function variantName(i: number) { + if (name.length === 0) { + return i === 0 ? "" : String(i); + } else { + return i === 0 ? name : `${name}-${i}`; + } + } + + function fromList(list: number[]): LightnessVariantInfo[] { + return list.map((l, i) => ({ + name: variantName(i), + lightness: l, + })); + } + + if (typeof list === "number") { + return fromList([list]); + } else if (Array.isArray(list)) { + return fromList(list); + } else { + const l = [list.base]; + for (let i = 1; i <= list.levels; i++) { + if (list.direction === "darker") { + l.push(list.base - i * list.step); + } else { + l.push(list.base + i * list.step); + } + } + return fromList(l); + } + } + + static from(info: ThemeColorVariantInfo): ThemeColorVariant { + return new ThemeColorVariant(info.name, info.variants); + } +} + +class ThemeColor { + variants: ThemeColorVariant[]; + + constructor( + public prefix: string, + public name: string, + public color: HslColor, + variants: ThemeColorVariantInfo[], + ) { + this.variants = variants.map((v) => ThemeColorVariant.from(v)); + } + + getLightnessVariants(mode: ColorMode): LightnessVariantInfo[] { + return this.variants.flatMap((v) => v.getLightnessVariants(mode)); + } + + getLightnessVariantColorGroup(mode: ColorMode): LightnessVariantColorGroup { + return new LightnessVariantColorGroup( + this.prefix, + this.name, + this.color, + this.getLightnessVariants(mode), + ); + } } class Theme { - static keyColorVariants: ColorModeColorVariant[] = [ + static keyColorVariants: ThemeColorVariantInfo[] = [ { - variant: "", - lightness: { - light: 40, - dark: 80, + name: "", + variants: { + light: [40, 37, 34], + dark: [80, 75, 68], }, }, { - variant: "on", - lightness: { + name: "on", + variants: { light: 100, dark: 20, }, }, { - variant: "container", - lightness: { - light: 90, - dark: 30, + name: "container", + variants: { + light: [90, 80, 70], + dark: [30, 25, 20], }, }, { - variant: "on-container", - lightness: { + name: "on-container", + variants: { light: 10, dark: 90, }, }, ]; - static surfaceColorVariants: ColorModeColorVariant[] = [ + static surfaceColorVariants: ThemeColorVariantInfo[] = [ { - variant: "dim", - lightness: { + name: "dim", + variants: { light: 87, dark: 6, }, }, { - variant: "", - lightness: { - light: 98, - dark: 6, + name: "", + variants: { + light: [98, 90, 82], + dark: [6, 25, 40], }, }, { - variant: "bright", - lightness: { + name: "bright", + variants: { light: 98, dark: 24, }, }, { - variant: "container-lowest", - lightness: { + name: "container-lowest", + variants: { light: 100, dark: 4, }, }, { - variant: "container-low", - lightness: { + name: "container-low", + variants: { light: 96, dark: 10, }, }, { - variant: "container", - lightness: { + name: "container", + variants: { light: 94, dark: 12, }, }, { - variant: "container-high", - lightness: { + name: "container-high", + variants: { light: 92, dark: 17, }, }, { - variant: "container-highest", - lightness: { + name: "container-highest", + variants: { light: 90, dark: 22, }, }, { - variant: "on", - lightness: { + name: "on", + variants: { light: 10, dark: 90, }, }, { - variant: "on-variant", - lightness: { + name: "on-variant", + variants: { light: 30, dark: 80, }, }, { - variant: "outline", - lightness: { + name: "outline", + variants: { light: 50, dark: 60, }, }, { - variant: "outline-variant", - lightness: { + name: "outline-variant", + variants: { light: 80, dark: 30, }, }, ]; - static getLightnessVariants( - mode: ColorMode, - colorModeColorVariants: ColorModeColorVariant[], - ): LightnessVariantInfo[] { - return colorModeColorVariants.map((v) => ({ - variant: v.variant, - lightness: v.lightness[mode], - })); - } - constructor( public prefix: string, - public themeColors: ThemeColors, - public levels = 3, + public themeColors: ThemeColorsInfo, ) {} getColorModeColorDefinitions(mode: ColorMode): ColorGroup { const groups: ColorGroup[] = []; for (const { name, color } of this.themeColors.keyColors) { - const colorGroup = new LightnessVariantColorGroup( + const themeColor = new ThemeColor( this.prefix, name, color, - Theme.getLightnessVariants(mode, Theme.keyColorVariants), + Theme.keyColorVariants, ); - groups.push(colorGroup); + groups.push(themeColor.getLightnessVariantColorGroup(mode)); } - groups.push( - new LightnessVariantColorGroup( - this.prefix, - "surface", - this.themeColors.neutralColor, - Theme.getLightnessVariants(mode, Theme.surfaceColorVariants), - ), + const neutralThemeColor = new ThemeColor( + this.prefix, + "surface", + this.themeColors.neutralColor, + Theme.surfaceColorVariants, ); + groups.push(neutralThemeColor.getLightnessVariantColorGroup(mode)); return new CompositeColorGroup(groups); } getAliasColorDefinitions(name: string): ColorGroup { + const sampleThemeColor = this.themeColors.keyColors[0]; + const themeColor = new ThemeColor( + this.prefix, + sampleThemeColor.name, + sampleThemeColor.color, + Theme.keyColorVariants, + ); + const sampleMode = "light"; return new VarAliasColorGroup( this.prefix, "key", name, - Theme.keyColorVariants.map((v) => v.variant), + themeColor.getLightnessVariants(sampleMode).map((v) => v.name), ); } @@ -370,7 +454,7 @@ class Theme { (function main() { const prefix = "cru"; - const themeColors: ThemeColors = { + const themeColors: ThemeColorsInfo = { keyColors: [ { name: "primary", color: new HslColor(210, 100, 50) }, { name: "secondary", color: new HslColor(40, 100, 50) }, -- cgit v1.2.3 From adc91a81fe53fdbc3d63065baa0b56862c104824 Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 19 Jul 2023 18:26:00 +0800 Subject: AppBar done! --- FrontEnd/src/views/common/AppBar.css | 72 +++++------- FrontEnd/src/views/common/AppBar.tsx | 143 ++++++++---------------- FrontEnd/src/views/common/button/Button.css | 5 +- FrontEnd/src/views/common/button/FlatButton.css | 4 +- FrontEnd/src/views/common/button/IconButton.css | 41 +++++++ FrontEnd/src/views/common/button/IconButton.tsx | 8 +- FrontEnd/src/views/common/user/UserAvatar.tsx | 17 +-- 7 files changed, 137 insertions(+), 153 deletions(-) diff --git a/FrontEnd/src/views/common/AppBar.css b/FrontEnd/src/views/common/AppBar.css index c278aa1e..bd8d0986 100644 --- a/FrontEnd/src/views/common/AppBar.css +++ b/FrontEnd/src/views/common/AppBar.css @@ -8,29 +8,25 @@ background-color: var(--cru-primary-color); } -.app-bar.desktop { +.app-bar { display: flex; } -.app-bar.desktop .app-bar-brand { +.app-bar .app-bar-brand { display: flex; align-items: center; } -.app-bar.desktop .app-bar-brand-icon { +.app-bar .app-bar-brand-icon { height: 2em; } -.app-bar.desktop .app-bar-main-area { - display: flex; - flex-grow: 1; -} - -.app-bar.desktop .app-bar-link-area { +.app-bar .app-bar-user-area { display: flex; + margin-left: auto; } -.app-bar.desktop a { +.app-bar a { background-color: var(--cru-primary-color); color: var(--cru-primary-on-color); text-decoration: none; @@ -40,63 +36,47 @@ transition: all 0.5s; } -.app-bar.desktop a:hover { +.app-bar a:hover { background-color: var(--cru-primary-1-color); } -.app-bar.desktop a:focus { +.app-bar a:focus { background-color: var(--cru-primary-1-color); } -.app-bar.desktop a:active { +.app-bar a:active { background-color: var(--cru-primary-2-color); } -.app-bar.desktop .app-bar-user-area { +.app-bar .app-bar-avatar img { + width: 45px; + height: 45px; + background-color: white; + border-radius: 50%; +} + +.app-bar.desktop .app-bar-link-area { display: flex; - margin-left: auto; } -.small-screen .app-bar-main-area { +.app-bar.mobile .app-bar-link-area { position: absolute; + z-index: -1; top: 56px; left: 0; right: 0; - transform-origin: top; - transition: transform 0.6s, background-color 1s; - background-color: var(--cru-primary-color); - flex-direction: column; -} - -.small-screen .app-bar-main-area.app-bar-collapse { - transform: scale(1, 0); -} - -.small-screen .app-bar-main-area a { - text-align: left; - padding: 0.5em 0.5em; + transition: transform 0.5s; } -.small-screen .app-bar-link-area { - flex-direction: column; - align-items: stretch; -} - -.small-screen .app-bar-user-area { - flex-direction: column; - align-items: stretch; - margin-left: unset; +.app-bar.mobile a { + height: 56px; } -.small-screen .app-bar-avatar { - align-self: flex-end; +.app-bar.mobile.collapse .app-bar-link-area { + transform: translateY(-100%); } -.app-bar-toggler { - margin-left: auto; +.app-bar .toggler { font-size: 2em; - margin-right: 1em; - color: var(--cru-primary-t-color); - cursor: pointer; - user-select: none; + margin-right: 0.5em; } \ No newline at end of file diff --git a/FrontEnd/src/views/common/AppBar.tsx b/FrontEnd/src/views/common/AppBar.tsx index 180d0db6..dacd608a 100644 --- a/FrontEnd/src/views/common/AppBar.tsx +++ b/FrontEnd/src/views/common/AppBar.tsx @@ -1,12 +1,12 @@ -import * as React from "react"; +import { useState } from "react"; import classnames from "classnames"; import { Link, NavLink } from "react-router-dom"; -import { useMediaQuery } from "react-responsive"; import { I18nText, useC, useMobile } from "./common"; import { useUser } from "@/services/user"; import TimelineLogo from "./TimelineLogo"; +import { IconButton } from "./button"; import UserAvatar from "./user/UserAvatar"; import "./AppBar.css"; @@ -15,11 +15,13 @@ function AppBarNavLink({ link, className, label, + onClick, children, }: { link: string; className?: string; label?: I18nText; + onClick?: () => void; children?: React.ReactNode; }) { if (label != null && children != null) { @@ -32,117 +34,70 @@ function AppBarNavLink({ classnames(className, isActive && "active")} + onClick={onClick} > {children != null ? children : c(label)} ); } -function DesktopAppBar() { - const user = useUser(); - const hasAdministrationPermission = user && user.hasAdministrationPermission; - - return ( - - ); -} +export default function AppBar() { + const isMobile = useMobile(); -// TODO: Go make this! -function MobileAppBar() { - const c = useC(); + const [isCollapse, setIsCollapse] = useState(true); + const collapse = isMobile ? () => setIsCollapse(true) : undefined; + const toggleCollapse = () => setIsCollapse(!isCollapse); const user = useUser(); const hasAdministrationPermission = user && user.hasAdministrationPermission; - const isSmallScreen = useMediaQuery({ maxWidth: 576 }); - - const [expand, setExpand] = React.useState(false); - const collapse = (): void => setExpand(false); - const toggleExpand = (): void => setExpand(!expand); - - const createLink = ( - link: string, - label: React.ReactNode, - className?: string, - ): React.ReactNode => ( - classnames(className, isActive && "active")} - > - {label} - - ); - return ( -