Commit Graph
10 Commits
Author SHA1 Message Date
pastilhasandClaude Opus 5 9cbbc28c82 "Saved" is a moment, top-right, and gone in five seconds
it was a permanent line under the controls saying "Saved." — which said nothing,
because everything on this screen has been saved, all the time. it looked exactly
like feedback, so the one moment it actually meant something was indistinguishable
from every moment it did not.

now it appears when a save LANDS and clears itself. top-right of the block, beside
the title rather than in the flow: it is a remark about the block, not part of what
you are doing, and inline it pushes everything below down a line and then pulls it
back up — a layout that jumps every time somebody saves.

"Not set yet" stays. that IS a state, and it is the one worth knowing; it goes when
it stops being true rather than being replaced by a line that never changes.

the timer is a ref and is cleared before each new one. without that, saving twice
in quick succession leaves the first timeout running and it fires against the
second save — the confirmation vanishing a moment after appearing, which reads as
the second save failing.

Block moved to its own file and each setting now renders its own. the status belongs
to the setting that produced it, and lifting one block's timer into the panel would
put it in a component with nothing to do with it. that is also what made the
top-right slot possible without absolutely positioning anything.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:44:46 +01:00
pastilhasandClaude Opus 5 df52045eaa the path gets the row, the actions get their own
Root location is two states now. reading, it is a path and one Edit. editing, it
is a field and the things you can do to it.

the actions moved to the block's BOTTOM row, off the value's line. an absolute
path is long, and it was being truncated to make room for buttons that are not
needed most of the time — the thing somebody opened this to read was the thing
squeezed. shown, it wraps with `break-all` rather than truncating, because a path
is read from both ends: the machine at the front, the folder at the back, and
hiding either is worse than two lines.

Edit is a mode and not an always-live field. this is looked at far more often than
it is changed, and a live input invites a stray keystroke into a path everything
else will depend on. Cancel restores what is stored, so leaving the mode cannot
leave half a path on screen looking like the setting.

"back to the default" is gone, as asked — and `clearRootPath` and its DELETE route
with it, since that button was the only caller. an unreferenced endpoint is the
same rot as an unreferenced component, and this one was a second, quieter Save
that wrote a value nobody chose.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:41:50 +01:00
pastilhasandClaude Opus 5 d5f2d8f370 Root location: an absolute path, with a picker that can make folders
defaults to `<owner home>/fofos`, and stores the FULL path — never the tilde. a
tilde means "whoever is asking", and the people asking will not all be the same
person: this plugin is grantable, and the site is in one place regardless of who
is looking at it. stored as `~/fofos` it would give every user a different answer
to a question that has one.

THE DEFAULT IS COMPUTED, NOT WRITTEN. no row means the default is worked out on
every read, so it follows the machine. writing it in at install freezes whichever
home existed on install day, and a restore onto a different machine then points at
a directory that is not there while looking deliberately chosen. a saved path is a
decision and is stored exactly as given; only its absence is derived. the form
says which of the two it is showing, because "not set" reading identically to "set
to the default" is how somebody comes to believe they configured something they
did not.

THE PICKER USES THE PLATFORM'S FILE API — /file-browser/ls and /mkdir — not routes
of this plugin's own. they already refuse to leave home, and they already tell a
missing directory from a forbidden one, which is a distinction that cost somebody
an afternoon and would have been re-guessed here. shipping a second listing and
mkdir would be a second filesystem surface to audit for the sake of one form.

that API is an execution capability and never grantable, so for anybody but the
owner it 403s — said in a sentence rather than shown as an empty tree, because an
empty listing is data and must never be how a refusal looks. it also browses the
owner's home and nothing above it; a path outside home is still reachable by
typing, since the picker fills the field and the FIELD is what saves. one value on
screen, one Save, and picking a folder commits nothing by itself.

"Use this folder" takes the one that is OPEN rather than one highlighted in the
list. that makes looking inside and choosing one gesture, and it is the only way
to choose a folder with nothing in it — which a freshly made one always is.

a SECOND table, not a column on fofos_admin_connection, whose url and token are
both notNull: a root path could not be saved there without also having an HTTP
connection, and that connection is being replaced rather than extended. when it
goes, its table is a clean drop instead of surgery on columns that outlived it.
the rule against tables in this plugin is unbent — what it forbids is the CLIENT'S
work, and this row holds a path somebody can retype.

needs `bun db:push`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:35:16 +01:00
pastilhasandClaude Opus 5 ae9c30e53d Root location, above Database
empty like the one below it, and for the same reason: the block settles the shape
and says what is coming, while what goes in it is not decided.

the order is the order things are needed in — where the site is on this machine,
then how to read its data.

this is the block list paying for itself. adding the second setting was one entry
and moved nothing, which is what the previous commit chose it for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:29:49 +01:00
pastilhasandClaude Opus 5 fcc7436965 Administration is emptied, and starts again with a Database block
the address-and-token form is gone from the screen and ConnectionPanel.tsx with
it. leaving an unreferenced component behind would have been worse than deleting
it: it is in the history, and a file nothing renders rots without anyone noticing.

in its place, Administration is a LIST OF BLOCKS rather than one form. it will
hold several unrelated settings, and giving each a titled block now means the
second one moves nothing — a single form would have to be broken up the first time
anything joined it.

the first block is Database, and it is empty on purpose. it says "nothing to set
yet" rather than rendering nothing, because a section that draws blank reads as
one somebody abandoned. what goes in it is not decided, and inventing fields to
fill the space would be deciding it in the wrong place.

WHAT THIS COSTS, plainly: there is now no way to configure this plugin from the
screen at all. 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.
that is consistent with the gate being hardcoded false rather than a second
breakage: both are the same unfinished change, and neither is worth half-fixing
while the shape of the connection is being replaced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:28:24 +01:00
pastilhasandClaude Opus 5 10b7bc34f7 nothing but Administration opens until the plugin is ready
every section was clickable and every one of them showed the same connection form,
because the panel forced it and the nav did not know. nine doors onto one message
taught nobody anything and made a setup step look like nine faults.

so there is now a gate, `useReady`, and both panels read it. that is the point of
putting it in a hook rather than in either panel: a nav that offers a row the
detail panel then refuses is worse than one that does not offer it.

the nav DECLINES TO OFFER — a locked section is a <div>, not a <Link>, so there is
no href to hover, no cmd-click into a new tab and nothing to focus. rendering a
link and swallowing the click leaves a row that looks navigable and behaves like
one everywhere except the click.

the detail panel HOLDS THE LOCK, and it has to, because `?section=gallery` typed
into the address bar or arriving from an old bookmark never passes through the
nav.

one line of copy in the foot rather than a badge on nine dimmed rows. without it a
locked nav reads as broken instead of as one step not done: the rows go grey and
nothing says why or what to do about it.

THE CONDITION IS HARDCODED FALSE, as asked. the plumbing around it is real — it
asks /status, re-asks when the connection changes, and reports while it is still
asking — so switching the gate on is one line. it returns a single boolean and not
its parts deliberately: "all the info needed in Administration" will grow past
`configured && lastProbeOk`, and callers must not start assembling their own
version of it out of the pieces.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:25:57 +01:00
pastilhasandClaude Opus 5 5e96274ebd Administration sits at the foot of the panel, not the end of the list
it was last in SECTIONS, so it rendered as the tenth row and then stopped —
directly under Messages, with empty panel beneath it. that is the bottom of the
LIST. what it wanted is the bottom of the PANEL, the way Update-all sits in the
plugins nav.

`mt-auto` on a second group, divided by the same border the rows already use. it
holds whether there are ten sections or two, and it does not need a spacer element
to push it down.

the split is a `pinned` flag on the section rather than the nav testing for the
key. which sections are the client's site and which are this plugin's own
machinery is a fact about the section, and the nav should be reading it, not
knowing it. one array still — `sectionFor` and `isSectionKey` have to resolve
every key, and a second exported list is a second place to forget one.

the row body came out into `renderRow` so both groups draw the same row. no
change to what a row looks like.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:20:39 +01:00
pastilhasandClaude Opus 5 7eec2ec51d Administration is a section, not an overlay
the connection form — where fofos is, and the token — was reached through
`?config=1` and a link in the detail header, because it was not one of the nine
sections. it is now the tenth, called Administration, last in the nav.

that removes the overlay and the second route to it. the two could disagree: the
form covered whatever section was selected underneath, so the nav highlighted one
thing while the panel showed another, and an unconfigured plugin rendered the form
with no header at all — which reads as the selected section being broken rather
than as one setup step not done yet. unconfigured now goes to Administration and
the header says so.

`site` and `administration` are deliberately separate and the file says why. Site
settings is the CLIENT's — partners, social links, contact details, all of it
public copy. Administration is Officer's end: how this plugin reaches fofos, and
whatever else it will need to know. nothing in it ever appears on the site, and
the people who touch the two are not the same people.

`path: null`, alone among the sections: it reads nothing from fofos, which is why
it keeps working when fofos is unreachable and the others do not.

the header's settings link is replaced by the section's own hint, so the row still
says what it is once you are in it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:18:13 +01:00
pastilhasandClaude Opus 5 fe77250aa4 the site's own wordmark, flattened onto white
the previous icon came from the bigcartel storefront. this one is the mark the
site itself serves — fofos-logo-black.webp — which is the one that will stay
current when the branding moves.

it is TRANSPARENT, black on nothing, so committing it unchanged would have put a
black mark on a dark dock and shown nothing at all. flattened onto opaque white
instead, and the white travels with the file rather than being something the
theme is trusted to supply: the icon is drawn over a dark tile, a light
marketplace card and the plugin's own header, and only one of those would have
saved it.

trimmed before padding, because the source has the artwork inset in a square and
centring the file centres the wrong thing. 86% inset — the lower line is fine
strokes and stops being readable at dock size with any more air than that.

assets/README.md records where it came from and how to redo it. a binary is the
one thing a diff cannot show, and the last icon arrived with no note about its
source, which is why this one needed replacing rather than updating.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:10:31 +01:00
pastilhasandClaude Opus 5 7da2640ce4 the fofos logo as the plugin's icon
`assets/icon.png` — presence is the declaration, so this takes over the dock tile
from the lucide `PenLine` name in the manifest. no manifest change: a file that
is there is the whole mechanism, and there is no field to keep in step with it.

256x256, matching every other plugin's icon rather than the source's 300.

TRANSPARENCY SURVIVED THE RESIZE, which is the part that needed care: the source
is half fully-transparent pixels, and a resize without `-background none`
composites them onto white — a black logo on a white square, on a dark dock.
checked after: alpha min 0, top-left srgba(0,0,0,0).

encoding chosen by measuring rather than by habit. straight PNG32 came out at
44 KB — LARGER than the 300px source — because a forced 32-bit RGBA gets no
palette. PNG8 is 7 KB and bands the anti-aliased edges (RMSE 404). pngquant at
quality 90-100 is 15.5 KB with RMSE 68, six times more faithful than PNG8 and a
third the size of full colour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 23:21:22 +01:00