adding appearance toggle (light/dark mode)

This commit is contained in:
Kismet Hasanaj
2026-05-03 10:17:12 +02:00
parent d5e3fcf438
commit eaea202c49
6 changed files with 145 additions and 16 deletions
+19 -2
View File
@@ -13,6 +13,7 @@
import type { Metadata } from "next";
import Link from "next/link";
import { site } from "@/content";
import ThemeToggle from "@/components/ThemeToggle";
const lastUpdated = "2 May 2026";
@@ -37,7 +38,7 @@ export default function CookiePolicyPage() {
{/* Lightweight header — just a back-link */}
<header className="border-b border-[var(--border)]">
<div className="mx-auto flex h-20 w-full max-w-3xl items-center px-6 sm:px-8">
<div className="mx-auto flex h-20 w-full max-w-3xl items-center justify-between gap-4 px-6 sm:px-8">
<Link
href="/"
className="inline-flex items-center gap-2 text-sm text-[var(--text-soft)] transition-colors hover:text-[var(--text)]"
@@ -45,6 +46,7 @@ export default function CookiePolicyPage() {
<span aria-hidden="true"></span>
Back to Novarix Networks
</Link>
<ThemeToggle />
</div>
</header>
@@ -78,7 +80,7 @@ export default function CookiePolicyPage() {
What we store
</h2>
<p className="mt-3">
We use one small browser storage entry. It is first-party,
We use two small browser storage entries. Both are first-party,
confined to your browser, and never shared with anyone:
</p>
@@ -96,6 +98,21 @@ export default function CookiePolicyPage() {
every page. Persists until you clear your browser data.
</p>
</div>
<div className="rounded-2xl border border-[var(--border)] bg-[var(--surface)] p-5 backdrop-blur sm:p-6">
<p className="font-mono text-sm font-semibold text-[var(--text)]">
novarix-theme
</p>
<p className="mt-2 text-sm">
<span className="font-semibold text-[var(--text)]">
Preference.
</span>{" "}
Stored in <code>localStorage</code>. Remembers whether you
chose light mode or dark mode so the site uses your preferred
theme on future visits. Persists until you clear your browser
data.
</p>
</div>
</div>
</section>
+32 -5
View File
@@ -66,8 +66,7 @@
`@media (prefers-color-scheme: dark)` block.
--------------------------------------------------------------------------- */
:root {
color-scheme: light dark;
color-scheme: light;
--bg: var(--color-ink-50);
--surface: oklch(1 0 0 / 0.7);
--surface-strong: oklch(1 0 0 / 0.92);
@@ -85,8 +84,28 @@
--button-hover: var(--color-ink-800);
}
:root[data-theme="dark"] {
color-scheme: dark;
--bg: var(--color-ink-950);
--surface: oklch(0.13 0.028 255 / 0.55);
--surface-strong: oklch(0.13 0.028 255 / 0.85);
--text: var(--color-ink-100);
--text-soft: var(--color-ink-400);
--border: oklch(1 0 0 / 0.08);
--border-strong: oklch(1 0 0 / 0.16);
--accent: var(--color-brand-400);
--accent-soft: oklch(0.7 0.14 240 / 0.18);
--ring: oklch(0.7 0.14 240 / 0.5);
--grid: oklch(0.84 0.012 250 / 0.06);
--button-bg: var(--color-ink-100);
--button-fg: var(--color-ink-950);
--button-hover: var(--color-ink-50);
}
@media (prefers-color-scheme: dark) {
:root {
:root:not([data-theme]) {
color-scheme: dark;
--bg: var(--color-ink-950);
--surface: oklch(0.13 0.028 255 / 0.55);
--surface-strong: oklch(0.13 0.028 255 / 0.85);
@@ -218,12 +237,20 @@
display: none;
}
:root[data-theme="dark"] .brand-light {
display: none;
}
:root[data-theme="dark"] .brand-dark {
display: block;
}
@media (prefers-color-scheme: dark) {
.brand-light {
:root:not([data-theme]) .brand-light {
display: none;
}
.brand-dark {
:root:not([data-theme]) .brand-dark {
display: block;
}
}
+29
View File
@@ -63,6 +63,35 @@ export default function RootLayout({
}: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en-GB" suppressHydrationWarning>
<head>
<script
dangerouslySetInnerHTML={{
__html: `
(function () {
var key = "novarix-theme";
var root = document.documentElement;
var theme = "light";
try {
var saved = window.localStorage.getItem(key);
if (saved === "light" || saved === "dark") {
theme = saved;
} else if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
theme = "dark";
}
} catch (error) {
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
theme = "dark";
}
}
root.dataset.theme = theme;
root.style.colorScheme = theme;
})();
`,
}}
/>
</head>
<body>
{children}
<CookieBanner />
+12 -7
View File
@@ -27,6 +27,7 @@ import Link from "next/link";
import React, { useMemo, useState } from "react";
import { site } from "@/content";
import { openCookieBanner } from "@/components/CookieBanner";
import ThemeToggle from "@/components/ThemeToggle";
// Type for the mouse-pointer position used to move the background glow.
type PointerState = { x: number; y: number };
@@ -212,15 +213,19 @@ export default function HomePage() {
Contact
<span aria-hidden="true"></span>
</a>
<ThemeToggle />
</nav>
{/* Mobile-only Contact pill — replaces the full nav on small screens */}
<a
href="#contact"
className="inline-flex items-center rounded-full border border-[var(--border-strong)] px-3 py-1.5 text-xs text-[var(--text)] transition-colors hover:border-[var(--accent)] hover:text-[var(--accent)] sm:hidden"
>
Contact
</a>
{/* Mobile controls — simplified for smaller screens */}
<div className="flex items-center gap-2 sm:hidden">
<ThemeToggle className="text-xs" />
<a
href="#contact"
className="inline-flex items-center rounded-full border border-[var(--border-strong)] px-3 py-1.5 text-xs text-[var(--text)] transition-colors hover:border-[var(--accent)] hover:text-[var(--accent)]"
>
Contact
</a>
</div>
</div>
</header>