Tawny

Navigation

Headers

Tawny, Art, and Dev in one frame. Open a header in the sidebar for its own source.

components/headers
Tawny
DarkBrowse designs
Hugo Lin
lin hugo
aboutblogprojects

Source

Copy the files below into your project.

apps/web/components/landing/showcases/headers-demo.tsx
import { ArtHeaderDemo, ArtHeaderDetail } from '@/components/landing/showcases/art-header-demo'
import { DevHeaderDemo, DevHeaderDetail } from '@/components/landing/showcases/dev-header-demo'
import { TawnyHeaderDemo, TawnyHeaderDetail } from '@/components/landing/showcases/tawny-header-demo'

/**
 * Tawny, Art, and Dev in one frame. Each band keeps its own desktop canvas
 * and clips to the bar, so the three headers share a single 16:9 card.
 */
export function HeadersDemo() {
  return (
    <div className="flex h-full flex-col">
      <div className="min-h-0 flex-1 overflow-hidden border-b border-border">
        <TawnyHeaderDemo />
      </div>
      <div className="min-h-0 flex-1 overflow-hidden border-b border-border">
        <ArtHeaderDemo />
      </div>
      <div className="min-h-0 flex-1 overflow-hidden">
        <DevHeaderDemo />
      </div>
    </div>
  )
}

/** Detail page: the three bars at a readable size, still one frame. */
export function HeadersDetail() {
  return (
    <div className="flex h-full flex-col">
      <div className="min-h-0 flex-1 overflow-hidden border-b border-border">
        <TawnyHeaderDetail />
      </div>
      <div className="min-h-0 flex-1 overflow-hidden border-b border-border">
        <ArtHeaderDetail />
      </div>
      <div className="min-h-0 flex-1 overflow-hidden">
        <DevHeaderDetail />
      </div>
    </div>
  )
}
apps/web/components/landing/showcases/tawny-header-demo.tsx
import { Logo } from '@/components/logo'
import { ScaledDesignCanvas } from '@/components/landing/scaled-design-canvas'
import { cn } from '@tawny/ui/lib/utils'

/**
 * Desktop-fidelity Tawny navbar twin — fixed canvas scaled into the frame.
 * Inert visual twin; no mobile menu.
 */
export function TawnyHeaderDemo({ className }: { className?: string }) {
  return (
    <div
      role="img"
      aria-label="Tawny navigation bar preview"
      inert
      className={cn('h-full select-none', className)}
    >
        <ScaledDesignCanvas height={240}>
        <div className="flex h-full flex-col bg-background">
          <header className="shrink-0 border-b border-border bg-background/80 backdrop-blur-xl">
            {/*
              Static twin of the live math:
              side ≈ max(logo, theme+cta) + gap → ~268px at this canvas.
              nav band = total − 2 × side, flex-centered.
            */}
            <div className="relative mx-auto flex h-14 max-w-340 items-center px-6">
              <div className="relative z-10 flex items-center gap-2.5">
                <Logo className="size-8 rounded-md" />
                <span className="font-serif text-xl italic tracking-tight text-foreground">
                  Tawny
                </span>
              </div>
              <nav
                className="absolute inset-y-0 flex items-center justify-center"
                style={{ left: 268, right: 268 }}
                aria-hidden="true"
              >
                <div className="flex items-center gap-1">
                  {['Designs', 'Components', 'Writeups'].map((label, i) => (
                    <span
                      key={label}
                      className={cn(
                        'rounded-md px-3 py-1.5 text-sm',
                        i === 0
                          ? 'bg-muted text-foreground'
                          : 'text-muted-foreground',
                      )}
                    >
                      {label}
                    </span>
                  ))}
                </div>
              </nav>
              <div className="relative z-10 ml-auto flex items-center gap-2">
                <span className="inline-flex h-8 items-center rounded-full border border-border bg-muted/40 px-3 text-sm font-medium text-muted-foreground">
                  Dark
                </span>
                <span className="inline-flex items-center gap-1.5 rounded-full bg-foreground px-4 py-1.5 text-sm font-medium text-background">
                  Browse designs
                </span>
              </div>
            </div>
          </header>
          <div
            aria-hidden="true"
            className="min-h-0 flex-1 bg-linear-to-b from-muted/30 to-background"
          />
        </div>
      </ScaledDesignCanvas>
    </div>
  )
}

/** Detail page: the bar at real size, with a page body under it. */
export function TawnyHeaderDetail({ className }: { className?: string }) {
  return (
    <div
      className={cn('flex h-full select-none flex-col bg-background', className)}
      inert
    >
      <header className="shrink-0 border-b border-border bg-background/80">
        <div className="flex h-16 items-center justify-between gap-4 px-6">
          <div className="flex items-center gap-2.5">
            <Logo className="size-8 rounded-md" />
            <span className="font-serif text-2xl italic tracking-tight text-foreground">
              Tawny
            </span>
          </div>
          <nav className="flex items-center gap-1" aria-hidden="true">
            {['Designs', 'Components', 'Writeups'].map((label, i) => (
              <span
                key={label}
                className={cn(
                  'rounded-md px-3 py-1.5 text-sm',
                  i === 0 ? 'bg-muted text-foreground' : 'text-muted-foreground',
                )}
              >
                {label}
              </span>
            ))}
          </nav>
          <div className="flex items-center gap-2">
            <span className="inline-flex h-8 items-center rounded-full border border-border bg-muted/40 px-3 text-sm font-medium text-muted-foreground">
              Dark
            </span>
            <span className="inline-flex items-center rounded-full bg-foreground px-4 py-1.5 text-sm font-medium text-background">
              Browse designs
            </span>
          </div>
        </div>
      </header>
      <div className="min-h-0 flex-1 bg-linear-to-b from-muted/30 to-background" />
    </div>
  )
}
apps/web/components/landing/showcases/art-header-demo.tsx
import { DM_Sans, JetBrains_Mono, Playfair_Display } from 'next/font/google'
import { ScaledDesignCanvas } from '@/components/landing/scaled-design-canvas'
import { cn } from '@tawny/ui/lib/utils'

const artDisplay = Playfair_Display({
  subsets: ['latin'],
  variable: '--font-art-serif-display',
})

const artSans = DM_Sans({
  subsets: ['latin'],
  variable: '--font-art-sans-body',
})

const artMono = JetBrains_Mono({
  subsets: ['latin'],
  variable: '--font-art-mono',
})

/**
 * Desktop-fidelity Art header twin — fixed canvas scaled into the frame.
 * Inert visual twin; no navigation.
 */
export function ArtHeaderDemo({ className }: { className?: string }) {
  return (
    <div
      className={cn(
        artDisplay.variable,
        artSans.variable,
        artMono.variable,
        artSans.className,
        'h-full font-(family-name:--font-art-sans-body)',
        className,
      )}
    >
      <div
        role="img"
        aria-label="Art navigation header preview"
        inert
        className="h-full select-none"
      >
        <ScaledDesignCanvas height={240}>
          <div className="art-root flex h-full flex-col overflow-hidden bg-black text-art-bento-ink antialiased">
            <header className="shrink-0 bg-art-bento-bg pt-3">
              <div className="relative flex items-center justify-between gap-4 px-6 pb-3">
                <span className="text-lg font-bold tracking-tight text-art-bento-ink">
                  Hugo Lin
                </span>
                <nav className="flex flex-wrap items-center justify-end gap-5">
                  <ul className="flex items-center gap-5 text-sm font-bold">
                    {['Notes', 'Projects', 'About'].map((label) => (
                      <li key={label}>
                        <span className="opacity-90">{label}</span>
                      </li>
                    ))}
                  </ul>
                  <span className="font-mono text-xs font-bold tracking-wide">
                    <span>EN</span>
                    <span className="mx-1 opacity-40">|</span>
                    <span className="opacity-40">中</span>
                  </span>
                </nav>
              </div>
            </header>
            <div aria-hidden="true" className="min-h-0 flex-1 bg-black" />
          </div>
        </ScaledDesignCanvas>
      </div>
    </div>
  )
}

export function ArtHeaderDetail({ className }: { className?: string }) {
  return (
    <div
      className={cn(
        artDisplay.variable,
        artSans.variable,
        artMono.variable,
        artSans.className,
        'flex h-full flex-col font-(family-name:--font-art-sans-body)',
        className,
      )}
      inert
    >
      <div className="art-root flex h-full flex-col bg-black text-art-bento-ink">
        <header className="shrink-0 bg-art-bento-bg pt-4">
          <div className="flex items-center justify-between gap-4 px-8 pb-4">
            <span className="text-2xl font-bold tracking-tight">Hugo Lin</span>
            <nav className="flex items-center gap-6 text-base font-bold">
              {['Notes', 'Projects', 'About'].map((label) => (
                <span key={label}>{label}</span>
              ))}
              <span className="font-mono text-sm">
                EN
                <span className="mx-1 opacity-40">|</span>
                <span className="opacity-40">中</span>
              </span>
            </nav>
          </div>
        </header>
        <div className="min-h-0 flex-1 bg-black" />
      </div>
    </div>
  )
}
apps/web/components/landing/showcases/dev-header-demo.tsx
import { JetBrains_Mono } from 'next/font/google'
import { ScaledDesignCanvas } from '@/components/landing/scaled-design-canvas'
import { cn } from '@tawny/ui/lib/utils'

const devMono = JetBrains_Mono({
  subsets: ['latin'],
  variable: '--font-dev-mono',
})

/**
 * Desktop-fidelity Dev header twin — fixed canvas scaled into the frame.
 * Inert visual twin; no navigation.
 */
export function DevHeaderDemo({ className }: { className?: string }) {
  return (
    <div
      className={cn(
        devMono.variable,
        devMono.className,
        'h-full font-mono',
        className,
      )}
    >
      <div
        role="img"
        aria-label="Dev navigation header preview"
        inert
        className="h-full select-none"
      >
        <ScaledDesignCanvas height={240}>
          <div
            className="dev-root flex h-full flex-col bg-(--dev-background,#09090b) text-(--dev-foreground,#e4e4e7) antialiased"
            data-theme="dark"
          >
            <div className="mx-auto w-full max-w-2xl px-10 pt-14">
              <nav>
                <div className="flex items-center justify-between font-extrabold">
                  <span className="inline-flex items-center text-2xl">
                    lin hugo
                    <span
                      aria-hidden="true"
                      className="ml-1 inline-block animate-pulse text-red-500"
                    >
                      _
                    </span>
                  </span>
                </div>
                <div className="mt-1.5 flex gap-4">
                  {(['about', 'blog', 'projects'] as const).map((label, i) => (
                    <span
                      key={label}
                      className={cn(
                        'text-lg',
                        i === 0
                          ? 'font-extrabold text-(--dev-foreground,#e4e4e7)'
                          : 'font-normal text-(--dev-muted,#a1a1aa)',
                      )}
                    >
                      {label}
                    </span>
                  ))}
                </div>
              </nav>
            </div>
            <div aria-hidden="true" className="min-h-0 flex-1" />
          </div>
        </ScaledDesignCanvas>
      </div>
    </div>
  )
}

export function DevHeaderDetail({ className }: { className?: string }) {
  return (
    <div
      className={cn(
        devMono.variable,
        devMono.className,
        'flex h-full flex-col font-mono',
        className,
      )}
      inert
    >
      <div
        className="dev-root flex h-full flex-col bg-(--dev-background,#09090b) text-(--dev-foreground,#e4e4e7)"
        data-theme="dark"
      >
        <div className="mx-auto w-full max-w-2xl px-10 pt-16">
          <div className="flex items-center text-4xl font-extrabold">
            lin hugo
            <span aria-hidden="true" className="ml-1 inline-block animate-pulse text-red-500">
              _
            </span>
          </div>
          <div className="mt-3 flex gap-6 text-xl">
            {(['about', 'blog', 'projects'] as const).map((label, i) => (
              <span
                key={label}
                className={
                  i === 0
                    ? 'font-extrabold text-(--dev-foreground,#e4e4e7)'
                    : 'font-normal text-(--dev-muted,#a1a1aa)'
                }
              >
                {label}
              </span>
            ))}
          </div>
        </div>
      </div>
    </div>
  )
}