Merge pull request #6983 from coollabsio/andrasbacsai/fix-dark-mode-flicker

Fix dark mode white screen flicker on page transitions
This commit is contained in:
Andras Bacsai 2025-10-24 13:18:39 +02:00 committed by GitHub
commit 340006db75
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 35 additions and 21 deletions

View file

@ -1,11 +1,19 @@
<!DOCTYPE html> <!DOCTYPE html>
<html data-theme="dark" lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <html data-theme="dark" lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<script>
// Immediate theme application - runs before any rendering
(function() {
const t = localStorage.theme || 'dark';
const d = t === 'dark' || (t === 'system' && matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList[d ? 'add' : 'remove']('dark');
})();
</script>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex"> <meta name="robots" content="noindex">
<meta name="theme-color" content="#ffffff" /> <meta name="theme-color" content="#101010" id="theme-color-meta" />
<meta name="color-scheme" content="dark light" />
<meta name="Description" content="Coolify: An open-source & self-hostable Heroku / Netlify / Vercel alternative" /> <meta name="Description" content="Coolify: An open-source & self-hostable Heroku / Netlify / Vercel alternative" />
<meta name="viewport" content="width=device-width,initial-scale=1" /> <meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
@ -41,6 +49,12 @@
@endenv @endenv
<meta name="csrf-token" content="{{ csrf_token() }}"> <meta name="csrf-token" content="{{ csrf_token() }}">
@vite(['resources/js/app.js', 'resources/css/app.css']) @vite(['resources/js/app.js', 'resources/css/app.css'])
<script>
// Update theme-color meta tag (non-critical, can run async)
const t = localStorage.theme || 'dark';
const isDark = t === 'dark' || (t === 'system' && matchMedia('(prefers-color-scheme: dark)').matches);
document.getElementById('theme-color-meta')?.setAttribute('content', isDark ? '#101010' : '#ffffff');
</script>
<style> <style>
[x-cloak] { [x-cloak] {
display: none !important; display: none !important;
@ -108,7 +122,7 @@
} }
}); });
} }
// Existing link sanitization // Existing link sanitization
if (node.nodeName === 'A' && node.hasAttribute('href')) { if (node.nodeName === 'A' && node.hasAttribute('href')) {
const href = node.getAttribute('href') || ''; const href = node.getAttribute('href') || '';
@ -123,20 +137,11 @@
return DOMPurify.sanitize(html, config); return DOMPurify.sanitize(html, config);
}; };
// Initialize theme if not set
if (!('theme' in localStorage)) { if (!('theme' in localStorage)) {
localStorage.theme = 'dark'; localStorage.theme = 'dark';
document.documentElement.classList.add('dark')
} else if (localStorage.theme === 'dark') {
document.documentElement.classList.add('dark')
} else if (localStorage.theme === 'light') {
document.documentElement.classList.remove('dark')
} else {
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
} }
let theme = localStorage.theme let theme = localStorage.theme
let cpuColor = '#1e90ff' let cpuColor = '#1e90ff'
let ramColor = '#00ced1' let ramColor = '#00ced1'

View file

@ -49,21 +49,30 @@
localStorage.setItem('theme', userSettings); localStorage.setItem('theme', userSettings);
const themeMetaTag = document.querySelector('meta[name=theme-color]'); const themeMetaTag = document.querySelector('meta[name=theme-color]');
let isDark = false;
if (userSettings === 'dark') { if (userSettings === 'dark') {
document.documentElement.classList.add('dark'); document.documentElement.classList.add('dark');
themeMetaTag.setAttribute('content', this.darkColorContent);
this.theme = 'dark'; this.theme = 'dark';
isDark = true;
} else if (userSettings === 'light') { } else if (userSettings === 'light') {
document.documentElement.classList.remove('dark'); document.documentElement.classList.remove('dark');
themeMetaTag.setAttribute('content', this.whiteColorContent);
this.theme = 'light'; this.theme = 'light';
} else if (darkModePreference) { isDark = false;
} else if (userSettings === 'system') {
this.theme = 'system'; this.theme = 'system';
document.documentElement.classList.add('dark'); if (darkModePreference) {
} else if (!darkModePreference) { document.documentElement.classList.add('dark');
this.theme = 'system'; isDark = true;
document.documentElement.classList.remove('dark'); } else {
document.documentElement.classList.remove('dark');
isDark = false;
}
}
// Update theme-color meta tag
if (themeMetaTag) {
themeMetaTag.setAttribute('content', isDark ? '#101010' : '#ffffff');
} }
}, },
mounted() { mounted() {