Skip to content

Commit 2c68ff3

Browse files
authored
Merge pull request #3 from data-privacy-stack/feat/mobile-nav
2 parents 9d8a146 + 8930baf commit 2c68ff3

2 files changed

Lines changed: 76 additions & 8 deletions

File tree

‎astro.config.mjs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ export default defineConfig({
2020
},
2121
customCss: ["./src/styles/tokens.css"],
2222
head: [
23+
{
24+
// Default to dark regardless of OS; only an explicit toggle overrides it.
25+
tag: "script",
26+
content:
27+
'try{var t=localStorage.getItem("starlight-theme");if(t!=="light"&&t!=="dark"){t="dark";localStorage.setItem("starlight-theme",t)}document.documentElement.dataset.theme=t}catch(e){}',
28+
},
2329
{ tag: "link", attrs: { rel: "preconnect", href: "https://fonts.googleapis.com" } },
2430
{ tag: "link", attrs: { rel: "preconnect", href: "https://fonts.gstatic.com", crossorigin: true } },
2531
{

‎src/pages/index.astro‎

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,14 @@ const posts = (await getCollection("docs"))
4646
<script is:inline>
4747
// Set theme before paint to avoid a flash. Shares Starlight's key so the
4848
// choice carries over to the docs/blog pages.
49+
// Default is DARK regardless of OS; only an explicit toggle overrides it.
4950
(function () {
5051
try {
51-
const stored = localStorage.getItem("starlight-theme");
52-
const theme =
53-
stored === "light" || stored === "dark"
54-
? stored
55-
: window.matchMedia("(prefers-color-scheme: dark)").matches
56-
? "dark"
57-
: "light";
52+
let theme = localStorage.getItem("starlight-theme");
53+
if (theme !== "light" && theme !== "dark") {
54+
theme = "dark";
55+
localStorage.setItem("starlight-theme", theme);
56+
}
5857
document.documentElement.dataset.theme = theme;
5958
} catch (e) {}
6059
})();
@@ -66,7 +65,7 @@ const posts = (await getCollection("docs"))
6665
<Image class="brand-mark" src={mark} alt="" width={28} height={28} aria-hidden="true" />
6766
Data Privacy Stack
6867
</a>
69-
<nav class="links">
68+
<nav id="nav-links" class="links">
7069
<a href="#about">About</a>
7170
<a href="#projects">Projects</a>
7271
<a href="#governance">Governance</a>
@@ -79,6 +78,10 @@ const posts = (await getCollection("docs"))
7978
<svg class="icon-sun" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>
8079
<svg class="icon-moon" width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
8180
</button>
81+
<button id="menu-toggle" class="menu-toggle" type="button" aria-label="Toggle menu" aria-expanded="false" aria-controls="nav-links">
82+
<svg class="icon-menu" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
83+
<svg class="icon-close" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6 6 18"/></svg>
84+
</button>
8285
</header>
8386

8487
<main id="top">
@@ -244,6 +247,25 @@ const posts = (await getCollection("docs"))
244247
document.documentElement.dataset.theme = next;
245248
try { localStorage.setItem("starlight-theme", next); } catch (e) {}
246249
});
250+
251+
// Mobile hamburger menu
252+
const nav = document.querySelector(".nav");
253+
const mbtn = document.getElementById("menu-toggle");
254+
const setMenu = (open) => {
255+
nav.classList.toggle("open", open);
256+
mbtn?.setAttribute("aria-expanded", open ? "true" : "false");
257+
};
258+
mbtn?.addEventListener("click", () =>
259+
setMenu(!nav.classList.contains("open"))
260+
);
261+
// Close after choosing a destination
262+
document
263+
.querySelectorAll("#nav-links a")
264+
.forEach((a) => a.addEventListener("click", () => setMenu(false)));
265+
// Close on Escape
266+
document.addEventListener("keydown", (e) => {
267+
if (e.key === "Escape") setMenu(false);
268+
});
247269
</script>
248270

249271
<style>
@@ -339,6 +361,46 @@ const posts = (await getCollection("docs"))
339361
:root[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
340362
:root[data-theme="dark"] .theme-toggle .icon-moon { display: block; }
341363

364+
/* Mobile hamburger (hidden on desktop) */
365+
.menu-toggle {
366+
display: none;
367+
place-items: center;
368+
width: 36px; height: 36px;
369+
border-radius: 999px;
370+
border: 1px solid var(--card-border);
371+
background: var(--card-bg);
372+
color: var(--text);
373+
cursor: pointer;
374+
}
375+
.menu-toggle .icon-close { display: none; }
376+
.nav.open .menu-toggle .icon-menu { display: none; }
377+
.nav.open .menu-toggle .icon-close { display: block; }
378+
379+
@media (max-width: 880px) {
380+
.nav { flex-wrap: nowrap; }
381+
.menu-toggle { display: inline-grid; }
382+
.links {
383+
display: none;
384+
position: absolute;
385+
top: 100%;
386+
left: 0;
387+
right: 0;
388+
flex-direction: column;
389+
align-items: stretch;
390+
gap: 0;
391+
padding: 0.4rem 0;
392+
background: var(--nav-bg);
393+
backdrop-filter: saturate(180%) blur(10px);
394+
border-bottom: 1px solid var(--nav-border);
395+
}
396+
.nav.open .links { display: flex; }
397+
.links a {
398+
padding: 0.75rem clamp(1rem, 5vw, 3rem);
399+
font-size: 1rem;
400+
}
401+
.links a:hover { background: rgba(127, 127, 127, 0.1); color: var(--accent-strong); }
402+
}
403+
342404
main { width: min(1040px, 92vw); margin: 0 auto; }
343405

344406
/* Hero */

0 commit comments

Comments
 (0)