feat: Add persistent Dark Mode with ThemeToggle component and layout script
All checks were successful
Automated Container Build / build-and-push (push) Successful in 58s

This commit is contained in:
Elijah 2026-06-27 20:56:10 -07:00
parent ec8e601332
commit 87fc071961
5 changed files with 117 additions and 16 deletions

View file

@ -36,6 +36,36 @@
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
@layer base {
.dark {
--color-bg-base: #0f1614;
--color-bg-surface: #17221f;
--color-bg-surface-alt: #1e2d28;
--color-bg-callout: #1a332a;
--color-primary: #4ab2b2;
--color-primary-hover: #5ec7c7;
--color-primary-light: #6cd1d1;
--color-text-heading: #e4f0ec;
--color-text-body: #c3d9d3;
--color-text-secondary: #9cb8b0;
--color-text-muted: #6b8a81;
--color-border: #38524a;
--color-border-light: #253832;
--color-success: #4ade80;
--color-success-bg: #143621;
--color-error: #f87171;
--color-error-bg: #3b1c1c;
--color-badge-bg: #214035;
--color-badge-text: #6fd6b8;
--color-danger: #ef4444;
--color-danger-hover: #f87171;
--shadow-card: 0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.2);
--shadow-card-hover: 0 4px 12px rgba(0, 0, 0, 0.6), 0 2px 4px rgba(0, 0, 0, 0.4);
--shadow-modal: 0 20px 60px rgba(0, 0, 0, 0.5), 0 8px 20px rgba(0, 0, 0, 0.3);
}
}
/* ── Base Styles ── */
body {
background: var(--color-bg-base);

View file

@ -20,6 +20,21 @@ export default function RootLayout({
}>) {
return (
<html lang="en" className={`${inter.variable} h-full`} suppressHydrationWarning>
<head>
<script
dangerouslySetInnerHTML={{
__html: `
try {
if (localStorage.theme === 'dark') {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
} catch (_) {}
`,
}}
/>
</head>
<body className="min-h-full flex flex-col font-sans antialiased">
{children}
</body>

View file

@ -2,6 +2,7 @@ import { getShareLink } from "@/services/shareService";
import { notFound } from "next/navigation";
import { FlashcardViewer } from "@/components/flashcards/FlashcardViewer";
import { QuizViewer } from "@/components/quizzes/QuizViewer";
import { ThemeToggle } from "@/components/ui/ThemeToggle";
import Link from "next/link";
interface SharedPageProps {
@ -48,16 +49,19 @@ export default async function SharedPage(props: SharedPageProps) {
Shared {type === "flashcards" ? "Deck" : "Quiz"}
</div>
<div className="flex items-center gap-3">
<span className="text-sm font-medium px-3 py-1 bg-badge-bg text-badge-text rounded-full">
Read Only
</span>
<Link
href="/login"
className="text-sm font-medium text-primary hover:text-primary-hover transition-colors"
>
Sign In
</Link>
<div className="flex items-center gap-4">
<ThemeToggle />
<div className="flex items-center gap-3">
<span className="text-sm font-medium px-3 py-1 bg-badge-bg text-badge-text rounded-full">
Read Only
</span>
<Link
href="/login"
className="text-sm font-medium text-primary hover:text-primary-hover transition-colors"
>
Sign In
</Link>
</div>
</div>
</div>
</div>