refactor(projects): the project page was a wall of text — mostly a layout bug - #468
Merged
Merged
Conversation
…yout bug Reported as ugly with terrible hierarchy, and as "there is no widget" on a project that has had a live widget the whole time. Both were true from where the operator was standing. Measured on the live page before changing anything: 2,698 words · 17 sections · 8 h2s Visitor feedback 1,054w · Activity 847w · Report 844w Agent context: 37 buttons in 397 words But the biggest cause was not the word count. On a 1680px window the header was a `justify-between` row whose links column was `shrink-0`, so six ghost links to ELSEWHERE took 607px of 960px — 63% — and squeezed the project's own name and description into 333px. A 202-word description then wrapped into a twenty-line ribbon with two thirds of the screen empty beside it. That ribbon is what reads as a wall of text. Three changes, in the order they matter: 1. Identity outranks navigation. Destinations move to a quiet row BELOW the name and description, which now get the full measure. 2. The description is clamped to three lines with a toggle. A description should say what a project IS; these have grown into whole briefs (fleetcrown's names every route, integration and monetisation rail), and printing all of it under the title pushed every control below the fold. Only offered when there is actually enough text to hide. 3. Seventeen sections become six tabs. Ten of those sections answered variations of one question — Overview, Status quo, What happens next, Purpose, Product, Reach, Build contract, Resources, Plan and finish line, Next action, Completion contract. A jump-nav already existed and indexed 6 of the 17, which its own comment named as the failure mode: a nav that knows about some sections teaches the reader the others are not there. Anchors could not fix that — scrolling into a wall leaves the other 2,400 words underneath. A tab removes them. Why the widget looked missing: its setup sits inside the 1,054-word feedback section, behind an unlabelled "Widget" toggle. Someone looking for it did not find it and concluded the feature did not exist. It has its own tab now. Tabs preserve existing deep links (#feedback is what ControlInbox links to), are arrow-key navigable as a real tablist, and keep every panel MOUNTED while hidden — these panels hold unsaved drafts and poll while work is in flight, so unmounting would discard a half-typed brief the moment someone looked at another tab. Verified with a real `next build`, not just verify: this moves JSX across a server/client boundary and `npm run verify` deliberately excludes the build, so it could not have caught an RSC serialization fault. (Note for anyone repeating that: use `npx next build`. `npm run build` has a postbuild hook that deploys.)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported: the project page is ugly, a wall of text, terrible hierarchy — and "I went there to place the widget on FleetCrown itself, but there is no widget."
Both were true from where the operator was standing. Measured on the live page before changing anything:
The biggest cause was layout, not word count
On a 1680px window the header was a
justify-betweenrow whose links column wasshrink-0:Navigation to elsewhere outranked the project's own identity. A 202-word description then wrapped into a twenty-line ribbon with two thirds of the screen empty beside it. That ribbon is what reads as a wall of text.
Three changes, in the order they matter
1. Identity outranks navigation. Destinations move to a quiet row below the name and description, which now get the full measure.
2. The description is clamped to three lines, with a toggle, and only when there is enough text to be worth hiding. A description should say what a project is; these have grown into whole briefs — fleetcrown's names every route, integration and monetisation rail — and printing all of it under the title pushed every control below the fold.
3. Seventeen sections become six tabs. Ten of those sections answered variations of one question: Overview, Status quo, What happens next, Purpose, Product, Reach, Build contract, Resources, Plan and finish line, Next action, Completion contract.
A jump-nav already existed and indexed 6 of the 17 — which its own comment named as the failure mode: a nav that knows about some sections teaches the reader the others are not there. Anchors could not fix it either; scrolling into a wall leaves the other 2,400 words underneath. A tab removes them.
Why the widget looked missing
It wasn't. FleetCrown's project has had an active token the whole time, and the page reads
Live · fleetcrown.orangecat.ch— but only after you click an unlabelled "Widget" toggle buried inside the 1,054-word feedback section. Someone looking for it did not find it and concluded the feature did not exist.It has its own tab now.
The controls were verified end-to-end through the real UI on the live site during this investigation: clicked Bottom left → Save position, confirmed
{"corner":"bottom-left"}from/api/widget-boot, then set it back tobottom-right. Adding and positioning genuinely works — it was undiscoverable, which for product purposes is nearly as bad.Tab behaviour worth knowing
#feedbackis what ControlInbox links to; the tablist reads the hash on mount and onhashchange, so every existing link still lands correctly.role=tablist/tab/tabpanel, roving tabindex, arrow-key navigation.hiddenkeeps them out of the a11y tree without destroying state.replaceState, notlocation.hash— assigning the hash would scroll to a now-nonexistent anchor and stack a history entry per tab click, so Back would walk tabs instead of leaving the page.Verification
npm run verifyexits 0.Also verified with a real
npx next build(exit 0), because this moves JSX across a server/client boundary andverifydeliberately excludes the build — it could not have caught an RSC serialization fault. An earlier red build turned out to be the missing local database, not this change: rebuilding with a placeholderDATABASE_URLsucceeds, which is the discriminating test.