From 0ad88d8c6323c28638faac8422a35d79cb54b8d5 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Sat, 24 Oct 2026 12:37:41 +0200 Subject: [PATCH] fix(ui): keep charts and terminal readable in custom themes Co-Authored-By: Claude Opus 5.5 --- resources/js/terminal.js | 15 +++++++---- resources/js/terminal.test.js | 18 +++++++++++++ resources/views/components/navbar.blade.php | 28 +++------------------ resources/views/layouts/base.blade.php | 6 ++--- 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/resources/js/terminal.js b/resources/js/terminal.js index 93d196286b..46495425ef 100644 --- a/resources/js/terminal.js +++ b/resources/js/terminal.js @@ -70,16 +70,15 @@ function customThemeAccent() { return `#${channels.map((channel) => channel.toString(16).padStart(2, '0')).join('')}`; } +// A custom theme can be light or dark: it sets only the cursor accent, and the page brightness picks the text colors. function createSystemTerminalTheme() { - if (document.documentElement.dataset.theme === 'custom') { - return createApplicationTerminalTheme(customThemeAccent()); - } + const isCustomTheme = document.documentElement.dataset.theme === 'custom'; if (document.documentElement.classList.contains('dark')) { - return createApplicationTerminalTheme('#8C8E9C'); + return createApplicationTerminalTheme(isCustomTheme ? customThemeAccent() : '#8C8E9C'); } - return createApplicationTerminalTheme('#52525b', { + return createApplicationTerminalTheme(isCustomTheme ? customThemeAccent() : '#52525b', { black: '#18181b', red: '#dc2626', green: '#15803d', @@ -89,6 +88,12 @@ function createSystemTerminalTheme() { cyan: '#0e7490', white: '#52525b', brightBlack: '#71717a', + brightRed: '#b91c1c', + brightGreen: '#166534', + brightYellow: '#854d0e', + brightBlue: '#1d4ed8', + brightMagenta: '#7e22ce', + brightCyan: '#155e75', brightWhite: '#18181b', foreground: '#18181b', }); diff --git a/resources/js/terminal.test.js b/resources/js/terminal.test.js index ed6f9a696d..5c46c0707c 100644 --- a/resources/js/terminal.test.js +++ b/resources/js/terminal.test.js @@ -91,3 +91,21 @@ test('console input cannot forward control sequences or send into a shell sessio component.submitConsoleCommand(); assert.equal(messages.length, 0); }); + +function systemTerminalTheme({ theme, dark }) { + const source = readFileSync(new URL('./terminal.js', import.meta.url), 'utf8'); + const themeSource = source.slice(source.indexOf('const baseApplicationTerminalTheme'), source.indexOf('const applicationTerminalThemes')); + return vm.runInNewContext(`${themeSource}\ncreateSystemTerminalTheme();`, { + document: { documentElement: { dataset: { theme }, classList: { contains: (name) => name === 'dark' && dark } } }, + localStorage: { getItem: (key) => (key === 'themeColor' ? '#c2410c' : null) }, + }); +} + +test('system terminal theme uses dark text on light custom themes and light text on dark custom themes', () => { + const lightCustom = systemTerminalTheme({ theme: 'custom', dark: false }); + assert.equal(lightCustom.foreground, '#18181b'); + assert.equal(lightCustom.brightGreen, '#166534'); + assert.equal(lightCustom.cursor, systemTerminalTheme({ theme: 'custom', dark: true }).cursor); + assert.equal(systemTerminalTheme({ theme: 'custom', dark: true }).foreground, '#eee9f2'); + assert.equal(systemTerminalTheme({ theme: 'light', dark: false }).cursor, '#52525b'); +}); diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php index e3ddbbf18a..4739c4e09e 100644 --- a/resources/views/components/navbar.blade.php +++ b/resources/views/components/navbar.blade.php @@ -49,33 +49,11 @@ sessionStorage.setItem('navLevel', this.navLevel); this.$watch('navLevel', level => sessionStorage.setItem('navLevel', level)); } - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { - const userSettings = localStorage.getItem('theme'); - if (userSettings !== 'system') { return; } - document.documentElement.classList.toggle('dark', e.matches); - document.documentElement.dataset.theme = e.matches ? 'dark' : 'light'; + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { + if (localStorage.getItem('theme') === 'system') { window.applyStoredTheme(); } }); - this.queryTheme(); + window.applyStoredTheme(); }, - queryTheme() { - const darkModePreference = window.matchMedia('(prefers-color-scheme: dark)').matches; - const userSettings = localStorage.getItem('theme') || 'dark'; - localStorage.setItem('theme', userSettings); - let isDark = false; - if (userSettings === 'dark' || userSettings === 'custom') { - document.documentElement.classList.add('dark'); - isDark = true; - } else if (userSettings === 'light') { - document.documentElement.classList.remove('dark'); - } else if (darkModePreference) { - document.documentElement.classList.add('dark'); - isDark = true; - } else { - document.documentElement.classList.remove('dark'); - } - document.documentElement.dataset.theme = userSettings === 'custom' ? 'custom' : (isDark ? 'dark' : 'light'); - document.querySelector('meta[name=theme-color]')?.setAttribute('content', isDark ? '#101010' : '#ffffff'); - } }"> {{-- Search is only useful when workspace resources are available --}} @if (isSubscribed() || ! isCloud()) diff --git a/resources/views/layouts/base.blade.php b/resources/views/layouts/base.blade.php index cbfb637636..d3bac09361 100644 --- a/resources/views/layouts/base.blade.php +++ b/resources/views/layouts/base.blade.php @@ -379,7 +379,9 @@ let theme = localStorage.theme let cpuColor = '#1e90ff' let ramColor = '#00ced1' - let textColor = '#ffffff' + // Chart text follows the CSS text color, so it stays readable after a theme change without a re-render + // (for example a page that Livewire restores from its cache on Back). + const textColor = 'currentColor' let editorBackground = '#181818' let editorTheme = 'blackboard' @@ -391,13 +393,11 @@ if (theme == 'dark' || (theme == 'custom' && document.documentElement.classList.contains('dark'))) { cpuColor = '#1e90ff' ramColor = '#00ced1' - textColor = '#ffffff' editorBackground = '#181818' editorTheme = 'blackboard' } else { cpuColor = '#1e90ff' ramColor = '#00ced1' - textColor = '#000000' editorBackground = '#ffffff' editorTheme = null }