a band lists its blocks, and selection is the URL

A fourth level under the open band only — a page of six bands with four blocks
each is thirty rows, and the nav stops being somewhere you can find anything.

Blocks are named by the same list the picker offers, so a thing is called the
same word wherever it appears.

Clicking a block in the PAGE now writes that address too, rather than calling the
handler directly. Both ways of picking a block are the same act, so neither can
disagree with the other about what is selected — and closing it is the band row.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-01 09:49:44 +01:00
co-authored by Claude Opus 5
parent 7c4c3f48a8
commit 949d61efc6
5 changed files with 117 additions and 24 deletions
+39 -11
View File
@@ -6,6 +6,7 @@ import { SECTIONS, sectionOpen } from './sections';
import { href, useNav } from './routes';
import { useReady } from './useReady';
import { pageParam, usePages, useSections, type Page } from './usePages';
import { CHOICES } from './sections/AddComponentDialog';
import { useFofosChanged } from './channel';
/**
@@ -54,7 +55,7 @@ const rowClass = (active: boolean) =>
export const NavPanel = () => {
const { pages, announce } = usePages();
const { section: active, item, part } = useNav();
const { section: active, item, part, piece } = useNav();
const { sections } = useSections();
const { ready, rootSet } = useReady();
@@ -265,16 +266,43 @@ export const NavPanel = () => {
*/}
{current &&
sections?.map((band) => (
<Link
key={band.id}
to={href('pages', pageParam(page), String(band.id))}
replace
className={`flex items-baseline border-b border-border py-1.5 pr-3 pl-14 text-left transition-colors ${
part === String(band.id) ? 'bg-muted' : 'hover:bg-muted/50'
}`}
>
<span className="min-w-0 flex-1 truncate text-xs text-muted-foreground">{band.name}</span>
</Link>
<div key={band.id} className="flex flex-col">
<Link
to={href('pages', pageParam(page), String(band.id))}
replace
className={`flex items-baseline border-b border-border py-1.5 pr-3 pl-14 text-left transition-colors ${
part === String(band.id) && !piece ? 'bg-muted' : 'hover:bg-muted/50'
}`}
>
<span className="min-w-0 flex-1 truncate text-xs text-muted-foreground">{band.name}</span>
</Link>
{/*
The band's blocks, one level further in again.
Under the OPEN band only, for the same reason the bands are under the open page:
a page of six bands with four blocks each is thirty rows, and the nav stops being
a place you can find anything.
Named by kind, using the same list the block picker offers — so a thing is called
the same word wherever it appears.
*/}
{part === String(band.id) &&
band.components.map((block) => (
<Link
key={block.id}
to={href('pages', pageParam(page), String(band.id), String(block.id))}
replace
className={`flex items-baseline border-b border-border py-1 pr-3 pl-20 text-left transition-colors ${
piece === String(block.id) ? 'bg-muted' : 'hover:bg-muted/50'
}`}
>
<span className="min-w-0 flex-1 truncate text-[11px] text-muted-foreground/80">
{CHOICES.find((choice) => choice.kind === block.kind)?.label ?? block.kind}
</span>
</Link>
))}
</div>
))}
</div>
);