Files
fofos-admin/web/AdministrationPanel.tsx
T
pastilhasandClaude Opus 5 e87e19ee46 derived/ is built from originals/, and you can watch it happen
The mapping: derived/ mirrors originals/ directory for directory, and where
originals holds a FILE, derived holds a DIRECTORY of the same name — extension
included — with the renditions inside it. Keeping the extension is what makes it
total: a.jpg and a.png are different originals and must not share a folder. The
inverse is pure string work, so the filesystem is the record and there is no
second copy of the truth.

Images get a WebP ladder at 320/640/960/1280/1920/2560 plus full.webp, and
nothing is ever upscaled — a rung wider than the original would be a soft file
that srcset then confidently prefers over the sharp one. full.webp always
exists because for a HEIC it is the only browser-readable copy of the picture
there is.

Video gets av-club's web-1080 and web-720 presets by name, plus a poster. Images
are named by width because srcset descriptors are widths; video by height
because that is av-club's vocabulary and nobody misreads 1080.mp4.

The ladder is fixed here and the SITE chooses from it. This never reads
website/src/media/slots.ts — a plugin that knows a website's layout is a plugin
for one website, and that boundary is the difference between a template and
something fofos-shaped.

Each derived folder carries a manifest naming the size and mtime it was built
from, so the sync is idempotent and resumable: a run that died halfway is
finished by running it again. That is what makes an in-memory job acceptable
rather than merely convenient. It builds into <name>.partial and renames, so an
interruption can never leave a folder that looks finished.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 11:13:56 +01:00

29 lines
1.2 KiB
TypeScript

import { RootLocationBlock } from './RootLocationBlock';
import { MediaSyncBlock } from './MediaSyncBlock';
import { DatabaseBlock } from './DatabaseBlock';
/**
* Administration — this plugin's own machinery, not the client's site.
*
* A list of blocks, and nothing else. Each one owns its own heading, its own state and its own status
* message; this file decides only which of them exist and in what order.
*
* The order is the order things are needed in: where the site is on this machine, then turning what
* was uploaded into what the site serves, then how to read its data.
*
* ── What used to be here ──
*
* An address and a token: where fofos is, over HTTP. That is gone from the screen. The server half is
* untouched — `/_config` still stores a URL and a token, and the proxy in `api/router.ts` still reads
* them — but nothing can set them, which is why `useReady` stays hardcoded false and every other
* section stays locked. The two are the same unfinished change.
*/
export const AdministrationPanel = () => (
<div className="flex size-full flex-col gap-4 overflow-auto p-5">
<RootLocationBlock />
<MediaSyncBlock />
<DatabaseBlock />
</div>
);