From 30162b6a27525dee1ce7d54288fb228fb502f7ad Mon Sep 17 00:00:00 2001 From: Brian Bicknell Date: Tue, 2 Dec 2025 22:39:09 -0500 Subject: [PATCH] Added initial token/theme styles and theme service. --- JSMR.UI.Blazor/Services/ThemeService.cs | 16 +++++++++ JSMR.UI.Blazor/wwwroot/css/theme.frozen.css | 31 ++++++++++++++++ JSMR.UI.Blazor/wwwroot/css/theme.warm.css | 34 ++++++++++++++++++ JSMR.UI.Blazor/wwwroot/css/tokens.css | 33 +++++++++++++++++ JSMR.UI.Blazor/wwwroot/css/utilities.css | 39 +++++++++++++++++++++ 5 files changed, 153 insertions(+) create mode 100644 JSMR.UI.Blazor/Services/ThemeService.cs create mode 100644 JSMR.UI.Blazor/wwwroot/css/theme.frozen.css create mode 100644 JSMR.UI.Blazor/wwwroot/css/theme.warm.css create mode 100644 JSMR.UI.Blazor/wwwroot/css/tokens.css create mode 100644 JSMR.UI.Blazor/wwwroot/css/utilities.css diff --git a/JSMR.UI.Blazor/Services/ThemeService.cs b/JSMR.UI.Blazor/Services/ThemeService.cs new file mode 100644 index 0000000..70bfd71 --- /dev/null +++ b/JSMR.UI.Blazor/Services/ThemeService.cs @@ -0,0 +1,16 @@ +namespace JSMR.UI.Blazor.Services; + +public class ThemeService +{ + public AppTheme Current { get; private set; } = AppTheme.Frozen; + public event Action? Changed; + + public void Set(AppTheme theme) + { + if (theme == Current) return; + Current = theme; + Changed?.Invoke(); + } +} + +public enum AppTheme { Frozen, Warm } \ No newline at end of file diff --git a/JSMR.UI.Blazor/wwwroot/css/theme.frozen.css b/JSMR.UI.Blazor/wwwroot/css/theme.frozen.css new file mode 100644 index 0000000..4d1b0b6 --- /dev/null +++ b/JSMR.UI.Blazor/wwwroot/css/theme.frozen.css @@ -0,0 +1,31 @@ +.theme-frozen { + /* From your values */ + --sys-surface: rgb(16, 36, 50); /* --background-color */ + --sys-surface-1: rgb(39, 59, 73); /* card top */ + --sys-surface-2: rgb(29, 49, 63); /* card bottom (optional gradient) */ + --sys-elevation-1: 1px 1px 4px rgba(0,0,0,.5); /* --product-container-box-shadow */ + + --sys-on-surface: rgb(180,200,214); /* --primary-text-color */ + --sys-on-surface-strong: rgb(200,220,234); /* --product-title-text-color */ + + --sys-color-primary: #304562; /* --input-border-color */ + --sys-color-secondary: #3aa3b8; /* chosen accent */ + --sys-color-success: #33c26b; /* pick to taste */ + --sys-color-warning: #f2c94c; + --sys-color-danger: #ef476f; + --sys-outline: #304562; /* --input-border-color */ + + --sys-input-bg: rgb(0,20,34); /* --input-background-color */ + --sys-input-text: rgb(180,200,214); + --sys-input-placeholder: rgb(150,170,186); + --sys-input-border: #304562; + --sys-input-focus-ring: color-mix(in oklab, #304562, white 25%); + --sys-chip-bg: #415664; /* --tag-background-color */ + --sys-chip-text: rgb(210,220,230); /* --tag-text-color */ + --sys-chip-bg-hover: #596f7e; /* --tag-hover-background-color */ + --sys-chip-radius: .8rem; /* --tag-border-radius */ + --sys-chip-padding: .5rem 1rem; /* --tag-padding */ + --sys-chip-gap: .5rem; /* --tag-margin (horizontal portion) */ + + --sys-image-overlay: rgba(0,0,0,.9); /* from --image-overlay-opacity */ +} \ No newline at end of file diff --git a/JSMR.UI.Blazor/wwwroot/css/theme.warm.css b/JSMR.UI.Blazor/wwwroot/css/theme.warm.css new file mode 100644 index 0000000..b95731e --- /dev/null +++ b/JSMR.UI.Blazor/wwwroot/css/theme.warm.css @@ -0,0 +1,34 @@ +/* wwwroot/css/theme.warm.css */ +.theme-warm { + /* Surfaces & elevation */ + --sys-surface: #1f1713; /* deep cocoa */ + --sys-surface-1: #2a1d18; /* card top */ + --sys-surface-2: #241914; /* card bottom */ + --sys-elevation-1: 0 1px 6px rgba(0,0,0,.45); + /* Text */ + --sys-on-surface: #decfca; /* warm sand */ + --sys-on-surface-strong: #f6e9e3; /* lighter highlight */ + /* Brand roles */ + --sys-color-primary: #d67a2b; /* toasted orange */ + --sys-color-secondary: #b84d7a; /* berry accent */ + --sys-color-success: #5fbf6b; /* fresh green */ + --sys-color-warning: #e6b34e; /* honey */ + --sys-color-danger: #e0564e; /* ember red */ + /* Borders / outlines */ + --sys-outline: #8e5e3c; /* bronze */ + /* Inputs */ + --sys-input-bg: #201713; /* dark mocha */ + --sys-input-text: var(--sys-on-surface); + --sys-input-placeholder: #c5b4ae; + --sys-input-border: #8e5e3c; + --sys-input-focus-ring: color-mix(in oklab, var(--sys-color-primary), white 25%); + /* Tags / chips */ + --sys-chip-bg: #3a2720; /* cinnamon */ + --sys-chip-text: #eddcd6; + --sys-chip-bg-hover: #4a322a; /* deeper */ + --sys-chip-radius: .8rem; + --sys-chip-padding: .5rem 1rem; + --sys-chip-gap: .5rem; + /* Overlays / imagery */ + --sys-image-overlay: rgba(0,0,0,.85); +} \ No newline at end of file diff --git a/JSMR.UI.Blazor/wwwroot/css/tokens.css b/JSMR.UI.Blazor/wwwroot/css/tokens.css new file mode 100644 index 0000000..e066c35 --- /dev/null +++ b/JSMR.UI.Blazor/wwwroot/css/tokens.css @@ -0,0 +1,33 @@ +:root { + /* Surfaces & elevation */ + --sys-surface: #0f1115; /* app/page background */ + --sys-surface-1: #1b1f28; /* card top */ + --sys-surface-2: #161a22; /* card bottom */ + --sys-elevation-1: 0 1px 4px rgba(0,0,0,.5); + /* Text */ + --sys-on-surface: #c9d3dd; /* body text */ + --sys-on-surface-strong: #e4edf6; /* headings/highlights */ + /* Brand roles */ + --sys-color-primary: #3a5a7d; + --sys-color-secondary: #3aa3b8; + --sys-color-success: #27ae60; + --sys-color-warning: #f1c40f; + --sys-color-danger: #e74c3c; + /* Borders / outlines */ + --sys-outline: #3a5a7d; + /* Inputs */ + --sys-input-bg: #121824; + --sys-input-text: var(--sys-on-surface); + --sys-input-placeholder: #9fb0bf; + --sys-input-border: #3a5a7d; + --sys-input-focus-ring: color-mix(in oklab, var(--sys-color-primary), white 25%); + /* Tags / chips */ + --sys-chip-bg: #415664; + --sys-chip-text: #d2dede; + --sys-chip-bg-hover: #596f7e; + --sys-chip-radius: .8rem; + --sys-chip-padding: .5rem 1rem; + --sys-chip-gap: .5rem; + /* Overlays / imagery */ + --sys-image-overlay: rgba(0,0,0,.9); +} \ No newline at end of file diff --git a/JSMR.UI.Blazor/wwwroot/css/utilities.css b/JSMR.UI.Blazor/wwwroot/css/utilities.css new file mode 100644 index 0000000..ff8db2a --- /dev/null +++ b/JSMR.UI.Blazor/wwwroot/css/utilities.css @@ -0,0 +1,39 @@ +.text-primary { + color: var(--sys-color-primary); +} + +.text-secondary { + color: var(--sys-color-secondary); +} + +.text-success { + color: var(--sys-color-success); +} + +.text-warning { + color: var(--sys-color-warning); +} + +.text-danger { + color: var(--sys-color-danger); +} + +.bg-primary { + background: var(--sys-color-primary); +} + +.bg-secondary { + background: var(--sys-color-secondary); +} + +.bg-black { + background: #000; +} + +.bg-surface { + background: var(--sys-surface); +} + +.border-primary { + border-color: var(--sys-color-primary); +} \ No newline at end of file