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