fix the homepage pages
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
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
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user