Rewrite class-based theme provider and toggle.
next-themes still defaults to dark with no system follow. Clerk theme wrapper stays inherited.
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
import { ThemeProvider as NextThemes } from "next-themes";
|
||||||
|
|
||||||
|
/** Class-based color scheme. Default is dark; OS preference is ignored. */
|
||||||
|
export function ThemeProvider({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<NextThemes
|
||||||
|
attribute="class"
|
||||||
|
defaultTheme="dark"
|
||||||
|
enableSystem={false}
|
||||||
|
disableTransitionOnChange
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</NextThemes>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Moon, Sun } from "lucide-react";
|
||||||
|
import { useTheme } from "next-themes";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
export function ThemeToggle({ className }: { className?: string }) {
|
||||||
|
const { resolvedTheme, setTheme } = useTheme();
|
||||||
|
|
||||||
|
const flip = () => {
|
||||||
|
setTheme(resolvedTheme === "dark" ? "light" : "dark");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label="Toggle theme"
|
||||||
|
onClick={flip}
|
||||||
|
className={cn(
|
||||||
|
"inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Sun className="hidden h-4 w-4 dark:block" />
|
||||||
|
<Moon className="h-4 w-4 dark:hidden" />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
"""next-themes wrapper and toggle live under periscope/src."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
SRC = ROOT / "periscope" / "src" / "frontend" / "src"
|
||||||
|
|
||||||
|
|
||||||
|
def test_theme_modules_are_src():
|
||||||
|
for rel in (
|
||||||
|
"components/theme/theme-provider.tsx",
|
||||||
|
"components/theme/theme-toggle.tsx",
|
||||||
|
):
|
||||||
|
text = (SRC / rel).read_text(encoding="utf-8")
|
||||||
|
assert "Native Periscope overlay" not in text[:400]
|
||||||
|
|
||||||
|
|
||||||
|
def test_theme_provider_contract():
|
||||||
|
text = (SRC / "components/theme/theme-provider.tsx").read_text(encoding="utf-8")
|
||||||
|
assert "export function ThemeProvider" in text
|
||||||
|
assert 'attribute="class"' in text
|
||||||
|
assert 'defaultTheme="dark"' in text
|
||||||
|
assert "enableSystem={false}" in text
|
||||||
|
assert "disableTransitionOnChange" in text
|
||||||
|
clerk = SRC / "components/theme/clerk-theme-provider.tsx"
|
||||||
|
assert not clerk.exists()
|
||||||
|
|
||||||
|
|
||||||
|
def test_theme_toggle_contract():
|
||||||
|
text = (SRC / "components/theme/theme-toggle.tsx").read_text(encoding="utf-8")
|
||||||
|
assert "export function ThemeToggle" in text
|
||||||
|
assert 'aria-label="Toggle theme"' in text
|
||||||
|
assert "resolvedTheme" in text
|
||||||
|
assert 'className="hidden h-4 w-4 dark:block"' in text
|
||||||
|
assert 'className="h-4 w-4 dark:hidden"' in text
|
||||||
Reference in New Issue
Block a user