diff --git a/apps/web/src/components/mobile-menu.tsx b/apps/web/src/components/mobile-menu.tsx new file mode 100644 index 00000000..6665e23e --- /dev/null +++ b/apps/web/src/components/mobile-menu.tsx @@ -0,0 +1,40 @@ +'use client' + +import { type ReactNode, useEffect, useRef } from 'react' + +export function MobileMenu({ children }: { readonly children: ReactNode }) { + const details = useRef(null) + + useEffect(() => { + function onKey(event: KeyboardEvent) { + if (event.key === 'Escape' && details.current?.open) { + details.current.open = false + details.current.querySelector('summary')?.focus() + } + } + document.addEventListener('keydown', onKey) + return () => document.removeEventListener('keydown', onKey) + }, []) + + return ( +
+ + + + + + + +
{ + if (event.target instanceof Element && event.target.closest('a') && details.current) { + details.current.open = false + } + }} + > + {children} +
+
+ ) +} diff --git a/apps/web/src/components/site-header.tsx b/apps/web/src/components/site-header.tsx index 936bfb78..2d11824c 100644 --- a/apps/web/src/components/site-header.tsx +++ b/apps/web/src/components/site-header.tsx @@ -7,11 +7,14 @@ import { quickstartHref } from '../docs/registry' import { DemoLink } from './demo-link' import { DocsSearch } from './docs-search' import { Logomark } from './logomark' +import { MobileMenu } from './mobile-menu' import { ThemeToggle } from './theme-toggle' const item = 'text-micro font-medium text-fg-muted transition-colors hover:text-fg' export function SiteHeader() { + const startHref = quickstartHref() + return (
@@ -26,7 +29,7 @@ export function SiteHeader() { Product -
+
Who it’s for @@ -49,24 +52,72 @@ export function SiteHeader() {
- + Docs - Demo + Demo About - + GitHub Get started + + +
    +
  • + + Product + +
  • +
  • + + Who it’s for + +
      + {audiences.map((audience) => ( +
    • + + {audience.name} + +
    • + ))} +
    +
  • +
  • + + Docs + +
  • +
  • + Demo +
  • +
  • + + About + +
  • +
  • + + GitHub + +
  • +
+ + Get started + + → + + +
diff --git a/apps/web/src/styles/globals.css b/apps/web/src/styles/globals.css index 920c4539..35fdcfc5 100644 --- a/apps/web/src/styles/globals.css +++ b/apps/web/src/styles/globals.css @@ -930,6 +930,106 @@ body { font-size: 0.72rem; } +.mobile-menu-button { + display: grid; + place-items: center; + width: 2.25rem; + height: 2.25rem; + border: 1px solid var(--border); + border-radius: var(--radius-control); + background: var(--raised); + color: var(--fg); + cursor: pointer; + list-style: none; + transition: + border-color 0.15s ease, + background-color 0.15s ease; +} + +.mobile-menu-button::-webkit-details-marker { + display: none; +} + +.mobile-menu-button:hover { + border-color: var(--border-strong); + background: var(--surface); +} + +.mobile-menu-bars { + display: grid; + gap: 0.28rem; + width: 1rem; +} + +.mobile-menu-bars > span { + display: block; + height: 1.5px; + border-radius: 999px; + background: currentColor; + transition: + transform 0.15s ease, + opacity 0.15s ease; +} + +.mobile-menu[open] .mobile-menu-bars > span:nth-child(1) { + transform: translateY(0.37rem) rotate(45deg); +} + +.mobile-menu[open] .mobile-menu-bars > span:nth-child(2) { + opacity: 0; +} + +.mobile-menu[open] .mobile-menu-bars > span:nth-child(3) { + transform: translateY(-0.37rem) rotate(-45deg); +} + +.mobile-menu-panel { + position: absolute; + inset: 100% 0 auto; + max-height: calc(100dvh - 4rem); + overflow-y: auto; + padding: 0.75rem 1.25rem 1.25rem; + border-bottom: 1px solid var(--border); + background: var(--canvas); + box-shadow: var(--lift-lg); +} + +.mobile-menu-list { + display: flex; + flex-direction: column; +} + +.mobile-menu-list > li + li { + border-top: 1px solid var(--border); +} + +.mobile-menu-link { + display: block; + padding: 0.8rem 0; + font-size: var(--step-0); + font-weight: 500; + color: var(--fg); +} + +.mobile-menu-sublist { + display: grid; + gap: 0; + margin: -0.25rem 0 0.5rem; + padding-left: 1rem; + border-left: 2px solid var(--border); +} + +.mobile-menu-sublist .mobile-menu-link { + padding: 0.45rem 0; + font-size: var(--step--1); + font-weight: 400; + color: var(--fg-muted); +} + +.mobile-menu-sublist .mobile-menu-link:hover { + color: var(--fg); +} + .kbd { border: 1px solid var(--border); border-radius: 4px;