Files
carmanagement/apps/homepage/src/components/app-shell/ThemePill.tsx
T
root 0f083d8e5d
Build & Deploy / Build & Push Docker Image (push) Failing after 49s
Build & Deploy / Deploy to VPS (push) Has been skipped
Test / API Unit Tests (push) Failing after 5m4s
Test / Marketplace Unit Tests (push) Has been cancelled
Test / Admin Unit Tests (push) Has been cancelled
Test / Dashboard Unit Tests (push) Has been cancelled
Test / API Integration Tests (push) Has been cancelled
fix the homepage pages
2026-06-27 00:48:52 -04:00

94 lines
2.7 KiB
TypeScript

'use client';
import { persistTheme, themePreferenceEvent } from '@/lib/theme/client';
import { type ThemePreference } from '@/lib/theme/config';
import { useEffect, useRef, useState } from 'react';
import styles from './ThemePill.module.css';
interface Props {
initialPreference: ThemePreference;
}
const labels: Record<ThemePreference, string> = {
light: 'Light',
dark: 'Dark',
system: 'System',
};
export function ThemePill({ initialPreference }: Props) {
const [pref, setPref] = useState<ThemePreference>(initialPreference);
const menuRef = useRef<HTMLDivElement | null>(null);
const [open, setOpen] = useState(false);
useEffect(() => {
setPref(initialPreference);
}, [initialPreference]);
useEffect(() => {
const handler = () => {
const stored = localStorage.getItem('hpc.theme.preference');
if (stored === 'light' || stored === 'dark' || stored === 'system') setPref(stored);
};
window.addEventListener(themePreferenceEvent, handler);
return () => window.removeEventListener(themePreferenceEvent, handler);
}, []);
useEffect(() => {
function handleClick(e: MouseEvent) {
if (!menuRef.current?.contains(e.target as Node)) setOpen(false);
}
document.addEventListener('mousedown', handleClick);
return () => document.removeEventListener('mousedown', handleClick);
}, []);
const selectTheme = (next: ThemePreference) => {
setOpen(false);
persistTheme(next);
setPref(next);
};
const options: ThemePreference[] = ['light', 'dark', 'system'];
const otherOptions = options.filter((o) => o !== pref);
const displayLabel = pref === 'dark' ? 'Dark' : 'Light';
return (
<div ref={menuRef} className={styles.wrap}>
<button
type="button"
onClick={() => setOpen((v) => !v)}
className={styles.button}
aria-expanded={open}
aria-haspopup="menu"
aria-label={displayLabel}
>
<span className={styles.label}>{displayLabel}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
className={`${styles.chevron} ${open ? styles.chevronOpen : ''}`}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M19 9l-7 7-7-7" />
</svg>
</button>
{open && (
<div className={styles.menu}>
{otherOptions.map((o) => (
<button
key={o}
type="button"
onClick={() => selectTheme(o)}
className={styles.option}
>
<span>{labels[o]}</span>
</button>
))}
</div>
)}
</div>
);
}