Media moves to the foot, and each section asks its own question

TWO REPORTS, AND THE SECOND ONE WAS A DESIGN MISTAKE RATHER THAN A SETTING.

Media is pinned now, beside Administration. it sat at the end of the scrolling list,
which is the bottom of the LIST and not the bottom of the panel. it belongs in the
foot for the same reason Administration does: both are about this machine, while
everything above them is about the site's pages.

and it was LOCKED BEHIND A CONNECTION IT NEVER USES. `ready` was one global flag —
"can anything be opened" — and Media is a folder on this disk that never speaks to
fofos. so sections now declare what they need:

  'connection'  the site's pages, which read fofos
  'root'        Media, which needs a folder and nothing else
  'nothing'     Administration, because locking the door you fix things through is
                locking somebody out entirely

`sectionOpen` is one function, used by the nav to decide whether to offer a link and
by the detail panel to decide what to render — so the two cannot disagree about a
section. that was already the rule with one flag; it matters more now that each
section asks a different question.

`/status` gained `rootSet`, a BOOLEAN, and stays not-owner-only. the nav needs the
answer for every account that can see the section; the path itself stays behind
`/_config`, which is owner-only. whether a root has been chosen reveals nothing
about the machine — where it is would.

the empty-state line follows too: "set a root location below to begin" before there
is one, "connect fofos to open the rest" after — rather than one sentence naming a
step that is not the next one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-29 08:44:11 +01:00
co-authored by Claude Opus 5
parent 944d3d9c5b
commit c38d269faf
6 changed files with 97 additions and 14 deletions
+9 -3
View File
@@ -1,5 +1,5 @@
import { useSearchParams } from 'react-router';
import { DEFAULT_SECTION, isSectionKey, sectionFor, type SectionKey } from './sections';
import { DEFAULT_SECTION, isSectionKey, sectionFor, sectionOpen, type SectionKey } from './sections';
import { AdministrationPanel } from './AdministrationPanel';
import { MediaPanel } from './MediaPanel';
import { MessagesPanel } from './MessagesPanel';
@@ -48,7 +48,7 @@ export const DetailPanel = () => {
const raw = params.get('section');
const selected: SectionKey = isSectionKey(raw) ? raw : DEFAULT_SECTION;
const { ready, loading } = useReady();
const { ready, rootSet, loading } = useReady();
if (loading) {
return <div className="flex size-full items-center justify-center p-6 text-sm text-muted-foreground">Loading…</div>;
@@ -59,7 +59,13 @@ export const DetailPanel = () => {
is the part the old overlay could not do: the form used to appear under whichever row happened to
be highlighted, so it read as that section being broken rather than as one step not done yet.
*/
const current = sectionFor(ready ? selected : 'administration');
/*
A section that cannot be opened sends you to Administration, because that is where every requirement
is satisfied. Asked per section rather than by one flag: Media is reachable the moment a root
location exists, long before fofos is connected.
*/
const wanted = sectionFor(selected);
const current = sectionOpen(wanted, { ready, rootSet }) ? wanted : sectionFor('administration');
const Panel = current.built ? PANELS[current.key] : undefined;