/** * Gallery pieces, drops and collabs, as configurations of one panel. * * ── Why a configuration and not three screens ── * * The site's API already made this decision. `src/servers/api/admin/records.ts` is a factory and * these three sections are configurations of it, because each is a titled record with an ordered list * of media hanging off it and the only real differences are what the title is called and which extra * fields the record carries. * * The htmx admin did have three screens — `src/apps/admin/{gallery,drops,collabs}/routes.tsx` are * three copies of one file with the words changed — and that was defensible there, because each also * carried its own markup. There is no markup to differ here either, so three panels would be three * places to fix the same ordering bug. * * ── `fields` mirrors the server's allowlist, and only mirrors it ── * * What may actually be written is decided by `valuesFrom` in the site's `sections.ts`, per section, * as an allowlist. This list is the FORM for those fields, not a second authority over them: adding a * key here that the server does not accept produces an input that silently saves nothing. When they * disagree, the server is right. */ export type FieldSpec = { /** The wire name, snake_case, exactly as the server's allowlist spells it. */ key: string; label: string; /** A textarea rather than a single line. For prose that runs to a paragraph. */ long?: boolean; /** Placeholder text, where the label alone leaves the intent unclear. */ hint?: string; }; export type RecordsConfig = { /** The plugin route, which the catch-all forwards to the site's `/api/admin/`. */ path: string; /** "piece", used in buttons and empty states. Lower case; the UI capitalises where it needs to. */ singular: string; /** What this section calls its title. Collabs say "Project name" and that is the client's word. */ titleLabel: string; fields: FieldSpec[]; }; export const GALLERY_CONFIG: RecordsConfig = { path: '/fofos-admin/gallery', singular: 'piece', titleLabel: 'Title', fields: [ { key: 'descriptive_text', label: 'Description', long: true }, { key: 'measurement', label: 'Measurements', hint: '120 × 80 cm' }, { key: 'material', label: 'Material', hint: 'Wool, cotton backing' }, { key: 'colors', label: 'Colours' }, { key: 'production_notes', label: 'Production notes', long: true }, { key: 'shipping_notes', label: 'Shipping notes', long: true }, ], }; export const DROPS_CONFIG: RecordsConfig = { path: '/fofos-admin/drops', singular: 'drop', titleLabel: 'Title', fields: [{ key: 'description', label: 'Description', long: true }], }; /** * Collabs call their title `project_name`, and it stays that way. * * The server publishes it under `title` as well so a generic client can read one field, and accepts * `title` as an alias when creating. So this panel writes `title` like the other two and the column * written is still project_name — see the note in the site's sections.ts. */ export const COLLABS_CONFIG: RecordsConfig = { path: '/fofos-admin/collabs', singular: 'collab', titleLabel: 'Project name', fields: [{ key: 'project_description', label: 'Description', long: true }], };