fix: complete devops theme compatibility
This commit is contained in:
parent
d6fa1d9e28
commit
09b16c4b19
@ -5,6 +5,8 @@
|
|||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
font-family: var(--ml-font-body), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
font-family: var(--ml-font-body), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
background: var(--bl-bg-canvas);
|
||||||
|
color: var(--bl-text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
@ -12,3 +14,97 @@ body {
|
|||||||
padding-top: 3.5rem;
|
padding-top: 3.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Legacy pages still use Tailwind gray/white utilities directly. Keep them
|
||||||
|
theme-aware while those pages are migrated to shared @bytelyst/ui primitives.
|
||||||
|
*/
|
||||||
|
[data-theme="dark"] .bg-white {
|
||||||
|
background-color: var(--bl-surface-card) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .bg-gray-50,
|
||||||
|
[data-theme="dark"] .bg-gray-100 {
|
||||||
|
background-color: var(--bl-bg-canvas) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .bg-gray-200,
|
||||||
|
[data-theme="dark"] .bg-gray-300 {
|
||||||
|
background-color: var(--bl-surface-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .bg-gray-700,
|
||||||
|
[data-theme="dark"] .bg-gray-800 {
|
||||||
|
background-color: var(--bl-surface-card) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .bg-blue-50,
|
||||||
|
[data-theme="dark"] .bg-green-50,
|
||||||
|
[data-theme="dark"] .bg-yellow-50,
|
||||||
|
[data-theme="dark"] .bg-red-50,
|
||||||
|
[data-theme="dark"] .bg-purple-50,
|
||||||
|
[data-theme="dark"] .bg-red-50\/40 {
|
||||||
|
background-color: var(--bl-surface-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .text-gray-900,
|
||||||
|
[data-theme="dark"] .text-gray-800,
|
||||||
|
[data-theme="dark"] .text-gray-700 {
|
||||||
|
color: var(--bl-text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .text-gray-600,
|
||||||
|
[data-theme="dark"] .text-gray-500,
|
||||||
|
[data-theme="dark"] .text-gray-400,
|
||||||
|
[data-theme="dark"] .text-gray-300 {
|
||||||
|
color: var(--bl-text-secondary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .border-gray-100,
|
||||||
|
[data-theme="dark"] .border-gray-200,
|
||||||
|
[data-theme="dark"] .border-gray-300,
|
||||||
|
[data-theme="dark"] .border-gray-600 {
|
||||||
|
border-color: var(--bl-border) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .border-blue-200,
|
||||||
|
[data-theme="dark"] .border-green-200,
|
||||||
|
[data-theme="dark"] .border-yellow-200,
|
||||||
|
[data-theme="dark"] .border-red-200,
|
||||||
|
[data-theme="dark"] .border-purple-200 {
|
||||||
|
border-color: var(--bl-border) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] input,
|
||||||
|
[data-theme="dark"] select,
|
||||||
|
[data-theme="dark"] textarea {
|
||||||
|
background-color: var(--bl-input) !important;
|
||||||
|
border-color: var(--bl-border) !important;
|
||||||
|
color: var(--bl-text-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] input::placeholder,
|
||||||
|
[data-theme="dark"] textarea::placeholder {
|
||||||
|
color: var(--bl-text-tertiary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .shadow,
|
||||||
|
[data-theme="dark"] .shadow-md,
|
||||||
|
[data-theme="dark"] .shadow-lg,
|
||||||
|
[data-theme="dark"] .shadow-xl,
|
||||||
|
[data-theme="dark"] .shadow-sm {
|
||||||
|
box-shadow: var(--bl-shadow-sm) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (hover: hover) {
|
||||||
|
[data-theme="dark"] .hover\:bg-gray-50:hover,
|
||||||
|
[data-theme="dark"] .hover\:bg-gray-100:hover,
|
||||||
|
[data-theme="dark"] .hover\:bg-gray-200:hover {
|
||||||
|
background-color: var(--bl-surface-muted) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] .hover\:text-gray-600:hover,
|
||||||
|
[data-theme="dark"] .hover\:text-gray-700:hover {
|
||||||
|
color: var(--bl-text-primary) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import { useAuth } from '@/lib/auth';
|
|||||||
|
|
||||||
const THEME_STORAGE_KEY = 'bytelyst.theme.v1';
|
const THEME_STORAGE_KEY = 'bytelyst.theme.v1';
|
||||||
const SIDEBAR_STORAGE_KEY = 'bytelyst.devops.sidebar.collapsed.v1';
|
const SIDEBAR_STORAGE_KEY = 'bytelyst.devops.sidebar.collapsed.v1';
|
||||||
|
const THEME_EVENT = 'bytelyst-theme-change';
|
||||||
type Theme = 'light' | 'dark';
|
type Theme = 'light' | 'dark';
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
@ -46,6 +47,14 @@ export function SidebarNav() {
|
|||||||
const [theme, setTheme] = useState<Theme>('dark');
|
const [theme, setTheme] = useState<Theme>('dark');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
function handleThemeChange(event: Event) {
|
||||||
|
const next = (event as CustomEvent<Theme>).detail;
|
||||||
|
if (next === 'light' || next === 'dark') {
|
||||||
|
setTheme(next);
|
||||||
|
applyTheme(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const savedTheme = window.localStorage.getItem(THEME_STORAGE_KEY) as Theme | null;
|
const savedTheme = window.localStorage.getItem(THEME_STORAGE_KEY) as Theme | null;
|
||||||
const legacyTheme = window.localStorage.getItem('theme') as Theme | null;
|
const legacyTheme = window.localStorage.getItem('theme') as Theme | null;
|
||||||
@ -61,6 +70,9 @@ export function SidebarNav() {
|
|||||||
} catch {
|
} catch {
|
||||||
applyTheme('dark');
|
applyTheme('dark');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener(THEME_EVENT, handleThemeChange);
|
||||||
|
return () => window.removeEventListener(THEME_EVENT, handleThemeChange);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function applyTheme(next: Theme) {
|
function applyTheme(next: Theme) {
|
||||||
@ -75,6 +87,7 @@ export function SidebarNav() {
|
|||||||
try {
|
try {
|
||||||
window.localStorage.setItem(THEME_STORAGE_KEY, next);
|
window.localStorage.setItem(THEME_STORAGE_KEY, next);
|
||||||
window.localStorage.setItem('theme', next);
|
window.localStorage.setItem('theme', next);
|
||||||
|
window.dispatchEvent(new CustomEvent(THEME_EVENT, { detail: next }));
|
||||||
} catch {
|
} catch {
|
||||||
// localStorage can be unavailable in private browsing.
|
// localStorage can be unavailable in private browsing.
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { Button } from '@/components/ui/Primitives';
|
|||||||
// `app/layout.tsx`.
|
// `app/layout.tsx`.
|
||||||
|
|
||||||
const STORAGE_KEY = 'bytelyst.theme.v1';
|
const STORAGE_KEY = 'bytelyst.theme.v1';
|
||||||
|
const THEME_EVENT = 'bytelyst-theme-change';
|
||||||
type Theme = 'dark' | 'light';
|
type Theme = 'dark' | 'light';
|
||||||
const THEMES: Theme[] = ['dark', 'light'];
|
const THEMES: Theme[] = ['dark', 'light'];
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ function readPersisted(): Theme {
|
|||||||
function applyTheme(theme: Theme) {
|
function applyTheme(theme: Theme) {
|
||||||
if (typeof document === 'undefined') return;
|
if (typeof document === 'undefined') return;
|
||||||
document.documentElement.setAttribute('data-theme', theme);
|
document.documentElement.setAttribute('data-theme', theme);
|
||||||
|
document.documentElement.classList.toggle('dark', theme === 'dark');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ThemeToggle() {
|
export function ThemeToggle() {
|
||||||
@ -37,14 +39,31 @@ export function ThemeToggle() {
|
|||||||
const [theme, setTheme] = useState<Theme>('dark');
|
const [theme, setTheme] = useState<Theme>('dark');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTheme(readPersisted());
|
const persisted = readPersisted();
|
||||||
|
setTheme(persisted);
|
||||||
|
applyTheme(persisted);
|
||||||
|
|
||||||
|
function handleThemeChange(event: Event) {
|
||||||
|
const next = (event as CustomEvent<Theme>).detail;
|
||||||
|
if ((THEMES as string[]).includes(next)) {
|
||||||
|
setTheme(next);
|
||||||
|
applyTheme(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener(THEME_EVENT, handleThemeChange);
|
||||||
|
return () => window.removeEventListener(THEME_EVENT, handleThemeChange);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const toggle = useCallback(() => {
|
const toggle = useCallback(() => {
|
||||||
setTheme((prev) => {
|
setTheme((prev) => {
|
||||||
const next = prev === 'dark' ? 'light' : 'dark';
|
const next = prev === 'dark' ? 'light' : 'dark';
|
||||||
try {
|
try {
|
||||||
if (typeof window !== 'undefined') window.localStorage.setItem(STORAGE_KEY, next);
|
if (typeof window !== 'undefined') {
|
||||||
|
window.localStorage.setItem(STORAGE_KEY, next);
|
||||||
|
window.localStorage.setItem('theme', next);
|
||||||
|
window.dispatchEvent(new CustomEvent(THEME_EVENT, { detail: next }));
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user