feat: build audit outreach review workspace

This commit is contained in:
Matthias
2026-06-05 16:47:22 +02:00
parent 1feccb9bdf
commit 5a42c637c6
15 changed files with 1786 additions and 38 deletions

View File

@@ -6,7 +6,7 @@ import {
type ReactNode,
useContext,
useMemo,
useState,
useSyncExternalStore,
} from "react";
import { Button } from "@/components/ui/button";
@@ -20,34 +20,49 @@ type DashboardThemeContextValue = {
};
const storageKey = "webdev-dashboard-theme";
const themeChangeEvent = "webdev-dashboard-theme-change";
const DashboardThemeContext =
createContext<DashboardThemeContextValue | null>(null);
function isDashboardTheme(value: string | null): value is DashboardTheme {
return value === "dark" || value === "light";
}
function getStoredDashboardTheme(): DashboardTheme {
const storedTheme = window.localStorage.getItem(storageKey);
return isDashboardTheme(storedTheme) ? storedTheme : "light";
}
function getServerDashboardTheme(): DashboardTheme {
return "light";
}
function subscribeToDashboardTheme(onStoreChange: () => void) {
window.addEventListener("storage", onStoreChange);
window.addEventListener(themeChangeEvent, onStoreChange);
return () => {
window.removeEventListener("storage", onStoreChange);
window.removeEventListener(themeChangeEvent, onStoreChange);
};
}
export function DashboardThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<DashboardTheme>(() => {
if (typeof window === "undefined") {
return "light";
}
const storedTheme = window.localStorage.getItem(storageKey);
if (storedTheme === "dark" || storedTheme === "light") {
return storedTheme;
}
return "light";
});
const theme = useSyncExternalStore(
subscribeToDashboardTheme,
getStoredDashboardTheme,
getServerDashboardTheme,
);
const value = useMemo<DashboardThemeContextValue>(
() => ({
theme,
toggleTheme: () => {
setTheme((currentTheme) => {
const nextTheme = currentTheme === "dark" ? "light" : "dark";
window.localStorage.setItem(storageKey, nextTheme);
return nextTheme;
});
const nextTheme = theme === "dark" ? "light" : "dark";
window.localStorage.setItem(storageKey, nextTheme);
window.dispatchEvent(new Event(themeChangeEvent));
},
}),
[theme],