Design Library

Gallery shell - editorial swiss

shell-editorial.tsx

shellskill: emil-design-enggalleryeditorialtypographic

Variants of gallery-shell: shell-brutalist, shell-contact-sheet

Brief

The prompt that produced this. Re-run it to generate more in the same taste.

Aesthetic
editorial swiss - restrained, typographic, high-contrast, hairline rules, monospace metadata, generous whitespace, single accent
Reference
https://antitype.studio/
Intent
the library should read as a printed type specimen, where the work is the content and the chrome is just typography
Guardrails
always one accent color, hairline 1px rules, monospace for all metadata
never drop shadows, rounded corners above 2px, filled buttons

Install

Shells are library-internal - they take the registry as props and are not published to the registry.

Source

Meta block and library type import stripped - this is what pastes cleanly elsewhere.

import { Link } from '@tanstack/react-router'
import type React from 'react'
import { useMemo, useState } from 'react'
import { ScaledPreview } from '@/components/preview-frame'

const ACCENT = '#e4442b'

export default function ShellEditorial({ designs }: ShellProps) {
  const [query, setQuery] = useState('')
  const [activeTag, setActiveTag] = useState<string | null>(null)

  const tags = useMemo(() => [...new Set(designs.flatMap((d) => d.tags))].sort(), [designs])

  const visible = useMemo(() => {
    const q = query.trim().toLowerCase()
    return designs.filter((d) => {
      if (activeTag && !d.tags.includes(activeTag)) return false
      if (!q) return true
      return `${d.title} ${d.id} ${d.skill ?? ''} ${d.tags.join(' ')}`.toLowerCase().includes(q)
    })
  }, [designs, query, activeTag])

  return (
    <div className="mx-auto max-w-[1100px] px-8 py-16">
      <header className="border-foreground border-b pb-6">
        <p className="font-mono text-[11px] uppercase tracking-[0.2em] text-muted-foreground">
          Index of generated work
        </p>
        <h1 className="mt-4 font-semibold text-6xl leading-[0.95] tracking-tighter">
          Design
          <br />
          Library
        </h1>
        <div className="mt-6 flex items-baseline justify-between font-mono text-[11px] uppercase tracking-[0.15em]">
          <span className="text-muted-foreground">
            {visible.length} / {designs.length} entries
          </span>
          <span style={{ color: ACCENT }}>2026</span>
        </div>
      </header>

      <div className="flex flex-wrap items-center gap-x-8 gap-y-4 border-b py-4">
        <input
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          placeholder="Search"
          className="min-w-[12rem] flex-1 border-0 bg-transparent font-mono text-sm outline-none placeholder:text-muted-foreground"
        />
        <div className="flex flex-wrap gap-x-4 gap-y-1 font-mono text-[11px] uppercase tracking-[0.15em]">
          <button
            type="button"
            onClick={() => setActiveTag(null)}
            className="pressable hover:opacity-60"
            style={{ color: activeTag === null ? ACCENT : undefined }}
          >
            All
          </button>
          {tags.map((tag) => (
            <button
              key={tag}
              type="button"
              onClick={() => setActiveTag(activeTag === tag ? null : tag)}
              className="pressable text-muted-foreground hover:opacity-60"
              style={{ color: activeTag === tag ? ACCENT : undefined }}
            >
              {tag}
            </button>
          ))}
        </div>
      </div>

      {visible.length === 0 && (
        <p className="py-24 text-center font-mono text-muted-foreground text-sm">
          No entries match.
        </p>
      )}

      <ol className="grid gap-x-10 gap-y-16 pt-16 md:grid-cols-2">
        {visible.map((design, i) => (
          // Stagger is capped at 8 steps: past that the last card would wait
          // half a second, and a grid that takes 500ms to appear reads as slow.
          <li
            key={design.id}
            className="stagger-in"
            style={{ '--i': Math.min(i, 8) } as React.CSSProperties}
          >
            <Link to="/d/$id" params={{ id: design.id }} className="group block">
              <div className="flex items-baseline justify-between font-mono text-[11px] uppercase tracking-[0.15em]">
                <span style={{ color: ACCENT }}>{String(i + 1).padStart(2, '0')}</span>
                <span className="text-muted-foreground">{design.kind}</span>
              </div>

              <div className="mt-3 border border-foreground/15 transition-[border-color] duration-200 ease-[var(--ease-out-strong)] group-hover:border-foreground/40">
                <ScaledPreview
                  id={design.id}
                  designWidth={1280}
                  designHeight={860}
                  className="h-[280px]"
                >
                  <design.Component designs={designs} />
                </ScaledPreview>
              </div>

              <h2 className="mt-4 font-medium text-xl tracking-tight">{design.title}</h2>

              <dl className="mt-2 space-y-1 font-mono text-[11px] text-muted-foreground uppercase tracking-[0.12em]">
                <div className="flex gap-3">
                  <dt className="w-16 shrink-0">File</dt>
                  <dd>{design.id}.tsx</dd>
                </div>
                {design.skill && (
                  <div className="flex gap-3">
                    <dt className="w-16 shrink-0">Skill</dt>
                    <dd>{design.skill}</dd>
                  </div>
                )}
                {design.variantOf && (
                  <div className="flex gap-3">
                    <dt className="w-16 shrink-0">Set</dt>
                    <dd style={{ color: ACCENT }}>{design.variantOf}</dd>
                  </div>
                )}
                {design.tags.length > 0 && (
                  <div className="flex gap-3">
                    <dt className="w-16 shrink-0">Tags</dt>
                    {/* Spacing separates these, not middle dots. A metadata
                        line strung together with `ยท` is an AI signature. */}
                    <dd className="flex flex-wrap gap-x-3">
                      {design.tags.map((tag) => (
                        <span key={tag}>{tag}</span>
                      ))}
                    </dd>
                  </div>
                )}
              </dl>
            </Link>
          </li>
        ))}
      </ol>
    </div>
  )
}