8f1b1fb5cd
* feat(ui): replace generic building icon with company monogram in user menu The company row and switcher flyout in the sidebar user menu showed lucide Building2 for every company. Render the company's initial in a small rounded square instead (square = company, circle = person), so each company gets a mark of its own. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(mobile): touch behavior polish for the mobile web experience - kill -webkit-tap-highlight-color flash; touch-action: manipulation on interactive elements (no double-tap-to-zoom wait); user-select: none on buttons (long-press no longer enters text selection) - overscroll-behavior-y: contain on html/body: pull-to-refresh no longer hijacks list scrolling, inner scrollers stop chaining to the document (contain, not none, so iOS rubber-banding survives) - 16px font-size floor for form fields on coarse pointers: iOS Safari stops zooming into focused inputs; desktop keeps text-sm - min-h-screen -> min-h-dvh everywhere: correct height under collapsing mobile browser chrome, identical on desktop - active: variants mirror hover: on Button: Tailwind 4 gates hover: behind (hover: hover), so touch devices previously got zero pointer feedback - theme-color now tracks the app: default was a leftover blue #304D83; SSR emits white and ThemeColorSync mirrors the computed --background into the meta tag across dark mode and palette switches Hover-stuck-after-tap and viewport-fit/safe-area were already covered (Tailwind 4 hover gating; existing viewportFit: cover + safe-area utilities). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: log monogram and overscroll decisions Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
111 lines
4.8 KiB
TypeScript
111 lines
4.8 KiB
TypeScript
/**
|
|
* Stripe-inspired two-column docs layout.
|
|
*
|
|
* ┌────────────────┬──────────────────────────────────────────┐
|
|
* │ │ │
|
|
* │ Sidebar │ Main content (max-w-4xl) │
|
|
* │ (sticky, │ │
|
|
* │ grouped) │ │
|
|
* │ │ │
|
|
* └────────────────┴──────────────────────────────────────────┘
|
|
*
|
|
* Aesthetic: paper-white surfaces, hairline borders, Hedvig display
|
|
* headlines, Geist body. Sidebar entries use the same warm-beige hover
|
|
* + active background as the dashboard sidebar so the docs feel like the
|
|
* same instrument as the app: not a separate marketing site.
|
|
*/
|
|
|
|
import Link from 'next/link'
|
|
import { DOCS_NAV } from '@/lib/docs/nav'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
interface DocsLayoutProps {
|
|
/** The pathname of the current page so the sidebar can highlight it. */
|
|
currentPath: string
|
|
children: React.ReactNode
|
|
}
|
|
|
|
export function DocsLayout({ currentPath, children }: DocsLayoutProps) {
|
|
return (
|
|
<div className="min-h-dvh bg-background">
|
|
<header className="sticky top-0 z-40 bg-background/95 backdrop-blur border-b border-border">
|
|
<div className="max-w-7xl mx-auto px-6 py-4 flex items-center justify-between">
|
|
<Link href="/docs/api" className="font-display text-xl tracking-tight" style={{ fontWeight: 700 }}>
|
|
accounted <span className="text-muted-foreground" style={{ fontWeight: 400 }}>/ docs</span>
|
|
</Link>
|
|
<nav className="flex items-center gap-6 text-sm">
|
|
<Link href="/docs/api/reference" className="text-foreground/80 hover:text-foreground transition-colors">
|
|
API reference
|
|
</Link>
|
|
<Link href="/docs/api/cookbook/quickstart" className="text-foreground/80 hover:text-foreground transition-colors">
|
|
Cookbooks
|
|
</Link>
|
|
<Link href="/docs/api/errors" className="text-foreground/80 hover:text-foreground transition-colors">
|
|
Errors
|
|
</Link>
|
|
<Link href="/docs/api/changelog" className="text-foreground/80 hover:text-foreground transition-colors">
|
|
Changelog
|
|
</Link>
|
|
<Link
|
|
href="/api/v1/openapi.json"
|
|
className="text-foreground/80 hover:text-foreground transition-colors font-mono text-xs"
|
|
>
|
|
openapi.json
|
|
</Link>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="max-w-7xl mx-auto px-6 grid grid-cols-1 md:grid-cols-[260px_1fr] gap-12 py-10">
|
|
<aside className="hidden md:block">
|
|
<div className="sticky top-24 space-y-8">
|
|
{DOCS_NAV.map((section) => (
|
|
<div key={section.label}>
|
|
<h3 className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground mb-2 px-3">
|
|
{section.label}
|
|
</h3>
|
|
<ul className="space-y-px">
|
|
{section.links.map((link) => {
|
|
const isActive = stripFragment(link.href) === currentPath
|
|
return (
|
|
<li key={link.href}>
|
|
<Link
|
|
href={link.href}
|
|
className={cn(
|
|
'block text-sm px-3 py-1.5 rounded-md transition-colors',
|
|
isActive
|
|
? 'bg-secondary text-foreground font-medium'
|
|
: 'text-foreground/75 hover:bg-secondary/60 hover:text-foreground',
|
|
)}
|
|
>
|
|
{link.label}
|
|
</Link>
|
|
</li>
|
|
)
|
|
})}
|
|
</ul>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</aside>
|
|
|
|
<main className="min-w-0 max-w-4xl">
|
|
{children}
|
|
</main>
|
|
</div>
|
|
|
|
<footer className="border-t border-border mt-20">
|
|
<div className="max-w-7xl mx-auto px-6 py-8 text-sm text-muted-foreground flex items-center justify-between">
|
|
<span>accounted REST API · Swedish bookkeeping for agents</span>
|
|
<span className="font-mono text-xs">AGPL-3.0-or-later</span>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function stripFragment(href: string): string {
|
|
const hashIdx = href.indexOf('#')
|
|
return hashIdx === -1 ? href : href.slice(0, hashIdx)
|
|
}
|