Commit Graph

2 Commits

Author SHA1 Message Date
khannurien
3e03626cc1 v4: text is edited where it stands through one component, InlineEdit, and a dump's note and a playlist's title and description join its title, a profile's description and email — those three were written apart, each with its own state, keys, buttons, error and CSS, and the note and the playlist could only be changed in their full editors. InlineEdit (components/form) shows the text; a click on it, or the ✎ after it, opens a field holding it, with Save and Cancel under it. A one-line field takes the text's own type in every style, from the class it is handed (dump-title, playlist-detail-title), and sits on the faint plate the text showed under the pointer, so that nothing moves but the buttons that come; a Markdown text opens the editor comments use. Enter saves a line, Ctrl+Enter a Markdown text, Escape backs out, a text left as it was closes without a request, a required one can't be emptied, a refused save says why in one line beside the buttons, and the focus goes back to the ✎. A click on a link in the text, or one that ends a selection, follows the link or keeps the selection. The ✎ is now a button with the action's name, where a div pretended to be one, and the text keeps its own role, a heading or Markdown. The plate is drawn under the text by a pseudo-element, tinted from its colour: the surface colour it had was the card's own, and showed nothing on the dump page. On a playlist's page the title edits in place beside Follow and Edit, which go to the row's end, and the description too; an empty note or description says what goes there to whoever may write it. DescriptionEditor and EmailEditor go.
The GeoCities marquee stops only for a link the keyboard focused: a link pressed with the pointer took the focus as well, which put the line back at its start and scrolled it, so the link slipped from under the pointer before the button came up and the click was lost. The next page's marquee also carries on from the very point the last one had reached, with the loop it showed: it worked its place out from when the loop began, which ran on while the crawl was paused under the pointer, and showed the feed as it was by then, of another width.

The chat's message field rests on one line, as tall as the Send button: it rested on two, 54 to 62 pixels against the button's 38, and the button sat low beside it. Both take --chat-composer-height.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:08:53 +00:00
khannurien
69d9bf899b v3: the profile page is split by one rule, and what it re-invented is shared across the app — UserPublicProfile was 1,949 lines because it held its data, six tabs, seven subcomponents and hand-rolled copies of things the app already had or repeated elsewhere. The page now only picks the tab and puts the pieces together (253 lines); useProfile holds the user and the three lists with their live sync, cache and scroll; each tab and header piece is one file under components/profile/; the followed and invitees tabs load on first open through the new useFetchState, keyed by username, which keeps them across tab switches. Every piece taken out replaces its copies: DumpCardList, which reads the votes from WSContext, is every list of dump cards (the index feeds, followed, search, related dumps, UserDumps, UserUpvoted, the profile), so Index no longer threads vote props into the feeds; PlaylistCardList every list of playlist cards; FeedFooter the eight sentinel/loading-more/end blocks; ListState the loading/error/empty chains; Segmented the settings toggles, RoleSwitcher and the playlist edit form, with SegmentedField built on it; LoadMoreButton the three load-more buttons; NewDumpButton UserDumps' and the profile's; useScrollRestore four copies of the scroll restore, and the profile uses useScrollSave instead of saving its whole cache on every scroll. useFading takes an onFaded callback, which replaces PlaylistDetail's copy of its timers; useUpvotedList is the vote tracking UserUpvoted and the profile each had, and a withdrawn upvote now leaves the list and the cache once faded (it was only hidden, and came back after a tab switch). usePlaylistMemberships is the membership load and toggle AddToPlaylistModal and DumpCreateModal each had. pagedList.ts (PagedList, firstPage, restoredList, fetchFirstPage, withFirst), fetchPublicUser and dataOr are shared by the profile, UserPlaylists and useUserDumpFeed; a refused side list still shows empty, as documented, and only the user fails the page. FollowedFeed's two sections are one local hook, and its readPage is expectOk. A card is its owner's when the item is the signed-in user's, everywhere: the profile's upvoted column marked every dump as the owner's on one's own profile. No message changed; the catalogs only move their references. 643 frontend tests pass (11 new for useFetchState, useFading's onFaded and pagedList), and tsc, eslint, doc:lint, deno check and deno fmt are clean.
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 48s
Build and Deploy Static Documentation Site / build-and-push (push) Successful in 22s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 20:50:49 +00:00