Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions website/components/MobileNavToggle.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
.sheet {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.94);
backdrop-filter: blur(8px);
/* Portaled to <body>, so this sits in the root stacking context. Kept
below the nav (z-index: 100) so the brand + close button stay on top.
Fully opaque so hero content can't bleed through. */
background: var(--abyss);
z-index: 95;
opacity: 0;
pointer-events: none;
Expand Down
104 changes: 59 additions & 45 deletions website/components/MobileNavToggle.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { formatCompact } from "@/lib/format";
import styles from "./MobileNavToggle.module.css";

Expand All @@ -17,6 +18,11 @@ export function MobileNavToggle({
stars: number;
}) {
const [open, setOpen] = useState(false);
const [mounted, setMounted] = useState(false);

useEffect(() => {
setMounted(true);
}, []);

useEffect(() => {
if (!open) return;
Expand All @@ -31,6 +37,58 @@ export function MobileNavToggle({
};
}, [open]);

// The parent <header> uses `backdrop-filter`, which establishes a containing
// block for fixed descendants — that would clip the sheet to the header
// strip. Portal it to <body> so `position: fixed; inset: 0` covers the
// viewport instead.
const sheet = (
<div
className={`${styles.sheet} ${open ? styles.sheetOpen : ""}`}
aria-hidden={!open}
Comment on lines +46 to +47
onClick={(e) => {
if (e.target === e.currentTarget) setOpen(false);
}}
>
<nav className={styles.panel} aria-label="Site navigation">
<ul className={styles.list}>
{sections.map((s) => (
<li key={s.href}>
<a href={s.href} onClick={() => setOpen(false)}>
{s.label}
</a>
Comment on lines +52 to +58
</li>
))}
</ul>
<div className={styles.foot}>
<a
href="https://github.com/rohitg00/agentmemory"
target="_blank"
rel="noopener"
onClick={() => setOpen(false)}
Comment on lines +63 to +67
>
GITHUB · {formatCompact(stars)}★
</a>
<a
href="https://www.npmjs.com/package/@agentmemory/agentmemory"
target="_blank"
rel="noopener"
onClick={() => setOpen(false)}
>
NPM
</a>
<a
href="https://github.com/rohitg00/agentmemory/blob/main/CHANGELOG.md"
target="_blank"
rel="noopener"
onClick={() => setOpen(false)}
>
CHANGELOG
</a>
</div>
</nav>
</div>
);

return (
<>
<button
Expand All @@ -44,51 +102,7 @@ export function MobileNavToggle({
<span className={`${styles.bar} ${open ? styles.bar3 : ""}`} />
</button>

<div
className={`${styles.sheet} ${open ? styles.sheetOpen : ""}`}
aria-hidden={!open}
onClick={(e) => {
if (e.target === e.currentTarget) setOpen(false);
}}
>
<nav className={styles.panel} aria-label="Site navigation">
<ul className={styles.list}>
{sections.map((s) => (
<li key={s.href}>
<a href={s.href} onClick={() => setOpen(false)}>
{s.label}
</a>
</li>
))}
</ul>
<div className={styles.foot}>
<a
href="https://github.com/rohitg00/agentmemory"
target="_blank"
rel="noopener"
onClick={() => setOpen(false)}
>
GITHUB · {formatCompact(stars)}★
</a>
<a
href="https://www.npmjs.com/package/@agentmemory/agentmemory"
target="_blank"
rel="noopener"
onClick={() => setOpen(false)}
>
NPM
</a>
<a
href="https://github.com/rohitg00/agentmemory/blob/main/CHANGELOG.md"
target="_blank"
rel="noopener"
onClick={() => setOpen(false)}
>
CHANGELOG
</a>
</div>
</nav>
</div>
{mounted ? createPortal(sheet, document.body) : null}
</>
);
}