Scalable people directory #13

Merged
justin merged 1 commits from people-directory into main 2026-06-06 22:54:10 -04:00
+27 -14
View File
@@ -268,6 +268,7 @@ export default function FamilyViewPage() {
const matches = search
? sorted.filter((p) => (p.primary_name ?? "").toLowerCase().includes(search.toLowerCase()))
: sorted;
const shown = matches.slice(0, 200); // cap DOM nodes; refine search to narrow
return (
<div className="space-y-8">
@@ -325,32 +326,44 @@ export default function FamilyViewPage() {
</Card>
</div>
{/* Searchable index of everyone in the tree */}
{/* Scrollable, searchable people directory (scales to large trees) */}
<div className="space-y-3">
<div className="flex items-center justify-between gap-3">
<h2 className="font-serif text-base font-semibold">All people ({people.length})</h2>
<div className="flex flex-wrap items-center justify-between gap-3">
<h2 className="font-serif text-base font-semibold">People ({people.length})</h2>
<Input
className="w-56"
placeholder="Search…"
className="w-64"
placeholder="Search by name…"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</div>
<div className="flex flex-wrap gap-2">
{matches.map((p) => (
<Card className="overflow-hidden">
<div className="max-h-96 overflow-y-auto">
{shown.length === 0 ? (
<div className="px-4 py-6 text-sm text-[var(--muted)]">No matches.</div>
) : (
shown.map((p, i) => (
<button
key={p.id}
onClick={() => setFocusId(p.id)}
className={`rounded-full border px-3 py-1 text-sm transition-colors ${
p.id === focusId
? "border-bronze bg-bronze/[0.08] text-bronze"
: "border-[var(--border)] hover:border-bronze/60"
}`}
className={`flex w-full items-center justify-between gap-3 px-4 py-2.5 text-left text-sm transition-colors ${
i > 0 ? "border-t border-[var(--border)]" : ""
} ${p.id === focusId ? "bg-bronze/[0.08]" : "hover:bg-bronze/[0.05]"}`}
>
{p.primary_name ?? "Unnamed"}
<span className="truncate font-medium">{p.primary_name ?? "Unnamed"}</span>
<span className="shrink-0 text-xs text-[var(--muted)]">
{years.get(p.id) ?? ""}
</span>
</button>
))}
))
)}
</div>
{matches.length > shown.length && (
<div className="border-t border-[var(--border)] bg-[var(--surface)] px-4 py-2 text-xs text-[var(--muted)]">
Showing {shown.length} of {matches.length} refine your search to narrow.
</div>
)}
</Card>
</div>
</div>
);