From d86483e5a110caf29a699a9a366f6ee0b86f5caa Mon Sep 17 00:00:00 2001 From: Nathan Schneider Date: Wed, 21 Oct 2026 20:46:45 -0600 Subject: [PATCH] restore green-wash theme (lost in the Oct 21 rebuild) + PWA band colors The Oct 19 theming (light = #eaf3ea dashboard green wash, white cards/surfaces, per approval) was never committed - the Oct 21 pin-migration rebuild from this repo silently reverted the deployed theme to the older cream iteration. - custom.css: light block restored to the approved green-wash palette (primary #eaf3ea, white secondary/chat cards, green hover/tertiary/border); loading screen + bare page background match. - Dockerfile: manifest theme_color/background_color and the index.html theme-color media pair now follow the live palette (#eaf3ea light / #22271f deep pine dark). - custom2.js: sync ONE meta theme-color to the app's resolved theme (html.dark class + prefers-color-scheme listener) so Android status/nav bands and iOS safe areas track the theme at runtime; the static media pair remains as the no-JS fallback. --- Dockerfile | 10 ++++++---- assets/custom.css | 18 +++++++++--------- assets/custom2.js | 35 +++++++++++++++++++++++++++++++++++ assets/logo.png | Bin 0 -> 6756 bytes 4 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 assets/logo.png diff --git a/Dockerfile b/Dockerfile index cb5837c..a1c6418 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,7 +59,9 @@ RUN python3 /app/code/patch_index.py && \ # PWA chrome colors: LibreChat ships a teal theme_color (#009688) in the web # manifest (the bright green bar Firefox PWAs draw across the top) and black -# background_color. Point both at the cream page color; the index.html meta -# gets a light + dark pair so browser tabs match the theme too. -RUN sed -i 's|"theme_color": *"#009688"|"theme_color":"#faf8f5"|; s|"background_color": *"#000000"|"background_color":"#faf8f5"|' /app/code/librechat/client/dist/manifest.webmanifest && \ - sed -i 's||\n |' /app/code/librechat/client/dist/index.html +# background_color. Point both at the light page color (#eaf3ea dashboard green +# wash — the manifest can only hold one value; custom2.js re-syncs the meta +# tags to the app's actual theme at runtime). The index.html meta gets a +# light + dark pair so browser/PWA chrome matches the phone theme natively. +RUN sed -i 's|"theme_color": *"#009688"|"theme_color":"#eaf3ea"|; s|"background_color": *"#000000"|"background_color":"#eaf3ea"|' /app/code/librechat/client/dist/manifest.webmanifest && \ + sed -i 's||\n |' /app/code/librechat/client/dist/index.html diff --git a/assets/custom.css b/assets/custom.css index b6b85f9..95bb552 100644 --- a/assets/custom.css +++ b/assets/custom.css @@ -10,10 +10,10 @@ ============================================================ */ html.light { - --surface-primary: 250 248 245; /* --cream #faf8f5 — dashboard page background */ + --surface-primary: 234 243 234; /* #eaf3ea — dashboard green wash, page background */ --surface-secondary: 255 255 255; /* sidebar + composer box: white cards */ - --surface-tertiary: 244 242 236; /* #f4f2ec — dashboard chip background */ - --surface-hover: 234 243 234; /* #eaf3ea — dashboard green wash as hover */ + --surface-tertiary: 240 246 239; /* light green chip background */ + --surface-hover: 223 237 222; /* deeper green hover */ --surface-submit: 91 140 90; /* --green-deep #5b8c5a */ --surface-submit-hover: 107 168 107; /* --green-mid #6ba86b */ --accent-primary: 91 140 90; /* --green-deep */ @@ -22,10 +22,10 @@ html.light { --link: 74 122 74; --text-primary: 45 51 39; /* --ink #2d3327 */ --text-secondary: 107 122 98; /* --muted #6b7a62 */ - --border-light: 228 224 216; /* --border #e4e0d8 */ - --presentation: 250 248 245; /* cream — composer band matches page */ + --border-light: 205 224 203; /* green-tinted border */ + --presentation: 234 243 234; /* composer band matches page */ --surface-chat: 255 255 255; /* chat box text areas: white */ - --surface-composer-hover: 244 242 236; + --surface-composer-hover: 223 237 222; } html.dark { @@ -79,7 +79,7 @@ html.dark { /* ---- Loading screen: brand the pre-React flash instead of white/black ---- */ #loading-container { - background-color: rgb(250, 248, 245); /* cream */ + background-color: rgb(234, 243, 234); /* green wash */ } @media (prefers-color-scheme: dark) { #loading-container { @@ -120,7 +120,7 @@ footer a:hover { text-decoration: underline; } -/* Bare page background: cream in light, deep pine in dark — so any viewport +/* Bare page background: green wash in light, deep pine in dark — so any viewport area the app UI does not cover (e.g. PWA navigation-bar insets) matches. */ -html:not(.dark), html:not(.dark) body { background-color: rgb(250, 248, 245); } +html:not(.dark), html:not(.dark) body { background-color: rgb(234, 243, 234); } html.dark, html.dark body { background-color: rgb(34, 39, 31); } diff --git a/assets/custom2.js b/assets/custom2.js index c41df88..8110008 100644 --- a/assets/custom2.js +++ b/assets/custom2.js @@ -39,9 +39,44 @@ ' · Our AI, governed together'; } + // PWA chrome bands (Android status bar + navigation bar, iOS safe areas): + // LibreChat ships static meta theme-color tags and never updates them, so + // the OS bands keep the install-time colors. Sync ONE meta tag to the app's + // RESOLVED theme (html.dark class — LibreChat applies it from the user's + // theme setting, which defaults to system = the phone's theme). Falls back + // to the light/dark media-query pair in index.html when this script is off. + var COOP_BG = { light: '#eaf3ea', dark: '#22271f' }; + function syncThemeColor() { + var dark = document.documentElement.classList.contains('dark'); + var metas = document.querySelectorAll('meta[name="theme-color"]'); + if (!metas.length) return; + // Replace the media-query pair with a single tag at the resolved color. + metas.forEach(function (m, i) { + if (i === 0) { + m.removeAttribute('media'); + m.setAttribute('content', dark ? COOP_BG.dark : COOP_BG.light); + } else { + m.remove(); + } + }); + } + var themeObserverRunning = false; + function startThemeSync() { + if (themeObserverRunning) return; + themeObserverRunning = true; + syncThemeColor(); + new MutationObserver(syncThemeColor).observe(document.documentElement, { + attributes: true, + attributeFilter: ['class'], + }); + var mq = window.matchMedia('(prefers-color-scheme: dark)'); + if (mq && mq.addEventListener) mq.addEventListener('change', syncThemeColor); + } + function run() { hideSignupPrompt(); fixFooter(); + startThemeSync(); } function start() { diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..63278129959f29921b57decddc30575f504e3550 GIT binary patch literal 6756 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 literal 0 HcmV?d00001