Gallery shell - brutalist index
shell-brutalist.tsx
shellskill: emil-design-enggallerybrutalistdense
Variants of gallery-shell: shell-contact-sheet, shell-editorial
Brief
The prompt that produced this. Re-run it to generate more in the same taste.
- Aesthetic
- brutalist index - table-first, monospace throughout, hard borders, zero radius, zero decoration, information density over comfort
- Reference
- https://theguyshetoldyounottoworryabout.com
- Intent
- scanning 100+ entries fast; a table beats a card grid once the library outgrows one screen, and the preview is on demand rather than always-on
- Guardrails
- always monospace type, square corners, preview only on hover or focusnever card grids, border radius, transitions longer than 0ms
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 { useMemo, useState } from 'react'
import { ScaledPreview } from '@/components/preview-frame'
const COLUMNS = ['#', 'id', 'title', 'kind', 'skill', 'set', 'tags'] as const
export default function ShellBrutalist({ designs }: ShellProps) {
const [query, setQuery] = useState('')
const [hovered, setHovered] = useState<string | null>(null)
const visible = useMemo(() => {
const q = query.trim().toLowerCase()
if (!q) return designs
return designs.filter((d) =>
`${d.title} ${d.id} ${d.skill ?? ''} ${d.tags.join(' ')}`.toLowerCase().includes(q),
)
}, [designs, query])
const active = visible.find((d) => d.id === hovered) ?? visible[0]
return (
<div className="min-h-[100dvh] bg-background font-mono text-[13px]">
<div className="flex items-center gap-4 border-foreground border-b-2 px-4 py-2">
<span className="font-bold uppercase">INDEX</span>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="grep…"
className="flex-1 border-foreground border-b bg-transparent px-1 py-0.5 outline-none placeholder:text-muted-foreground focus:border-b-2"
/>
<span className="tabular-nums">
{String(visible.length).padStart(3, '0')}/{String(designs.length).padStart(3, '0')}
</span>
</div>
<div className="grid lg:grid-cols-[1fr_480px]">
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="border-foreground border-b-2 text-left uppercase">
{COLUMNS.map((col) => (
<th key={col} className="px-3 py-1.5 font-bold">
{col}
</th>
))}
</tr>
</thead>
<tbody>
{visible.map((design, i) => (
<tr
key={design.id}
onMouseEnter={() => setHovered(design.id)}
className={`border-foreground/20 border-b ${
active?.id === design.id ? 'bg-foreground text-background' : ''
}`}
>
<td className="px-3 py-1.5 tabular-nums">{String(i + 1).padStart(3, '0')}</td>
<td className="px-3 py-1.5">
<Link
to="/d/$id"
params={{ id: design.id }}
onFocus={() => setHovered(design.id)}
className="underline underline-offset-2"
>
{design.id}
</Link>
</td>
<td className="px-3 py-1.5">{design.title}</td>
<td className="px-3 py-1.5 uppercase">{design.kind}</td>
<td className="px-3 py-1.5">{design.skill ?? '-'}</td>
<td className="px-3 py-1.5">{design.variantOf ?? '-'}</td>
<td className="px-3 py-1.5">{design.tags.join(',') || '-'}</td>
</tr>
))}
</tbody>
</table>
{visible.length === 0 && <p className="px-3 py-8 uppercase">no match</p>}
</div>
<aside className="hidden border-foreground border-l-2 lg:block">
<div className="sticky top-0">
<div className="border-foreground border-b-2 px-3 py-1.5 font-bold uppercase">
{active ? active.id : 'preview'}
</div>
{active && (
<ScaledPreview
id={active.id}
designWidth={1280}
designHeight={900}
className="h-[340px]"
>
<active.Component designs={designs} />
</ScaledPreview>
)}
</div>
</aside>
</div>
</div>
)
}