Write docs/style-guideline.md: codify the UI design language with canonical references + AGENTS.md amendment making it mandatory for all UI work #537
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub#537
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What's requested
The app now has a large, de-facto design language that lives only in
web/src/ui.csscomments, per-page JSX, scattered AGENTS.md working rules, and a chain of filed tickets (#232, #243, #244, #273, #274, #276, #278, #319, #34, #405, #465, #495, #506, #512, #521, #533, …). Every UI ticket currently re-derives the same decisions, and divergent markup for the same pattern is the recurring failure mode. This ticket asks for a documentation deliverable only:docs/style-guideline.md— a written style guideline that interrogates the app's current design decisions into a normative document, each rule backed by a canonical reference (the file and ticket that established it).This is a plan/docs ticket: no code changes anywhere — the only deliverables are the new doc and the AGENTS.md amendment.
Method
Read the design decisions out of the tree, not out of anyone's head. Every rule in the guideline cites its canonical implementation, and every cited ticket names the decision it settled. Where a decision is encoded in
docs/go/12_web_ui.mdor AGENTS.md already, the guideline references it rather than restating (one source of truth, restatements drift).Canonical references (seed list — the guideline author verifies each against the current tree and extends it)
Foundations (already normative elsewhere)
solid-js+@solidjs/router+marked+dompurify; Tailwind v4 CSS-first, dark mode by default — AGENTS.md law 1 (D-WEB-6/D-WEB-7 amendments) anddocs/go/12_web_ui.mdheader note.web/src/ui.css(#405 opaque-popover precedent). AGENTS.md working rule (Forgejo #533).web/src/ui.css@layer base:focus-visible.<html class="dark">,lib/store.jstoggles); light is the base layer,dark:variants carry dark. Colors are theme tokens in both themes, never a hardcoded palette (graph vars precedent,ui.css--graph-*; ToggleSwitch.jsx).Shared vocabulary —
web/src/ui.csscomponent classes (each is the ONE idiom; new UI composes them instead of re-deciding).card,.card-meta(#277 — flex+gap meta rows, never concatenated spans),.card-header(#521 — the one title treatment for sidebar/conversation cards),.site-header,.site-nav/.nav-link(#238),.brand..site-nav(#273),.repo-tabs(#274),.owner-tabs(#437, vertical variant)..btn/.btn.primary(emerald = primary action; exactly one primary CTA per page — issues list toolbar is the reference) /.btn.danger,.btn-active,.pill,.tab-badge(#319 — count badges white-on-emerald, hidden at 0 client-side),.input(text-field utilities never on non-text controls — #533; non-text controls use dedicated components, e.g.ToggleSwitch.jsxpeer-pattern switch,role="switch"+aria-checked),.icon(#465 —1em/currentColor, no per-icon CSS, spacing stays with the caller's gap)..chip-open/closed/merged/draft/prerelease— state color mapping is fixed (emerald/red/purple/amber/sky); new states extend the family, never inline colors..side-nav-*(#123, #276) — sections,aria-current="page"selected style, Danger Zone in its own danger section..setup-row/.setup-label/.setup-examples/.setup-note/.setup-callout— label column left, control right, stacks on phones; native<details>for collapsible groups (#168)..data-table,.tree-table(#223 — no header row, content-hugging columns, name absorbs spare width),.blob-table(#243 — per-line<tr>so gutter/code never desync),.diff-num(#244)..muted,.tabular,.err-line,.warn-line;.markdown-body(#182 — designed prose, covers everything marked emits)..empty-state/.empty-state-compact(#34, #35) — icon/title/hint composition, dashed panel; zero-data renders "No X configured" + setup guidance, never a machine-internal catch-all..card(#405 structural rule —.card.absolute/.card.fixed); viewport boundmax-width: calc(100vw - 1rem)on every absolute/fixed panel (#278); every popover carries the outside-click close (document listener, removed inonCleanup) copied fromRefPicker/TasksOverlay;.scroll-slimfor popover lists (#115)..gl-Nclasses only, lane colors live in--graph-*vars both themes, rail hidden ≤480px, rows margin-free with padding-only separation while graph-on (#506, #512 — the continuous-gutter rule: no per-row margins or divide-y borders over a continuous visual).Page anatomy (the issues list is the canonical reference implementation)
text-xl font-semibold tracking-tight+ toolbar row: primary CTA right-aligned viaml-auto, secondary.btnlinks, feature-gated CTAs hidden via the summary flag failing CLOSED (summary && !flag) (Issues.jsx #495 toolbar).2-upon phones → 4+action wide (#232); selects bound to URL params, deep links to deleted values stay visible, never silently dropped.Interaction/state conventions
TypeErrorstrings in toasts.web/src/lib/danger.js#39).e.currentTargetafter an await; never call a data hook inside acreateEffectbody.web/src/lib/icons.jsx); tab icons belong to the TAB's identity, never the viewed page.Drafted AGENTS.md amendment (verbatim, for the implementer to append as a working rule in §2, directly after the "Tailwind is the only styling language" rule)
Acceptance criteria
docs/style-guideline.mdexists, is normative in tone, and every rule carries a canonical reference (file path, and the ticket/doc that established it) verified against the current tree.ui.cssvocabulary, page anatomy (issues list named as reference implementation), popover/empty-state/state-chip conventions, form/table idioms, the continuous-gutter rule, and the interaction/state conventions listed above — extended with anything the author finds in the tree that belongs there.docs/go/12_web_ui.md.docs/style-guideline.md; law 12's documents-change-together rule is honored (single change, doc + amendment together).PR #543 addresses this: docs/style-guideline.md + verbatim AGENTS.md §2 amendment, docs-only. #543
Review of PR #543 (branch fix/issue-537, commit
0c76227) against issue #537's 6 acceptance criteria. Verified read-only via git show origin/fix/issue-537 + spot-checks from main checkout; no worktree modifications, no browser/docker.CRITERION 1 — guideline exists, normative, every rule has canonical ref: PASS. docs/style-guideline.md (359 lines) opens with an explicit normative-status block ('normative, not advisory... binding via AGENTS.md §2'), uses normative language throughout (never/MUST/rejected/ONLY). Every rule cites file + ticket/doc.
CRITERION 2 — coverage of the seed list: PASS. All seed items present: foundations (F1 dark-default html.dark + store.js toggle, F2 theme tokens + graph vars, F3 :focus-visible a11y floor, F4 ~390px no-pan); full ui.css vocabulary (.card/.card-meta #277/.card-header #521/.site-header/.nav-link #238/.brand, nav strips #273/#274/#437, .btn/.primary one-CTA/.danger/.btn-active/.pill/.tab-badge #319/.input #533 + ToggleSwitch/.icon #465, chips §6, .side-nav-* #123/#276, setup rows + details #168, tables #223/#243/#244 + .markdown-body #182, empty states #34/#35, popovers #405/#278/.scroll-slim #115, graph .gl-N/--graph-* #506/#512); page anatomy names Issues.jsx as reference (heading/toolbar #495, filter grid #232, deep-link honesty #416); interaction/state (law 7 tasks/SSE, human-readable errors + tolerateMissing/tolerateDegraded, danger.js #39, SolidJS lifecycle #270, icons per-surface). Extended beyond seed (clone honesty #37/#124, head pill #252, writeGate #502, listing sources #247, DateTime #133/#312) per the 'extended with anything found' clause.
CRITERION 3 — references, doesn't restate: PASS. §0 'What lives where' points at AGENTS.md law 1 / 12_web_ui.md §§2.4-2.6/2.9/2.10/§8/§6 + AGENTS.md §2 rules by section number instead of duplicating them; guideline states the restatement-drift rule explicitly.
CRITERION 4 — AGENTS.md amendment verbatim + placement: PASS. Added line 53 is word-for-word the issue's drafted text (compared token-by-token; earlier 2-char diff in my check script was a shell-quoting artifact of my own harness, not the patch). Placed in §2 working rules directly after the Tailwind-only rule (line 52) and before Performance-claims, i.e. exactly 'appended in §2 directly after the Tailwind rule'. Law-12 single-change honored (doc + amendment in one commit).
CRITERION 5 — maintenance rule in guideline: PASS. §11 states a pattern becomes canonical ONLY via shared implementation (ui.css class / components/ / lib/ helper) PLUS a guideline entry in the SAME change, with reject-unless-extended-or-amended enforcement and law-1/Tailwind supremacy.
CRITERION 6 — docs-only: PASS. git diff --name-only main...origin/fix/issue-537 = AGENTS.md (1-line add) + docs/style-guideline.md (new) only; name-status M + A, no code/markup/CSS touched.
REFERENCE SPOT-CHECKS (main tree): all cited files exist (36/36: index.html, store.js, ui.css, Issues.jsx, data.js, danger.js, icons.jsx, Repo.jsx, ToggleSwitch.jsx, ref-pill.js, clone.js, Empty.jsx, pull-state.js, Commits.jsx, DateTime.jsx, writeGate.js, mirror.js, blob-lines.js, diff-lines.js, DiffTable.jsx, render-md.js, milestones.js, repoFeatures.js, Setup.jsx, Tree.jsx, Blob.jsx, ActivityStamp.jsx, StarCount.jsx, format.js, releases.js, IssueNew.jsx, Settings.jsx, App.jsx, Repos.jsx, Pull.jsx, Issue.jsx, Releases.jsx). Sampled content claims all hold: index.html ships <html class=dark>; store.js THEME_KEY dark-default; ui.css :focus-visible/.card/.card-meta/.card-header/chips/graph vars/opaque-popover/viewport-bound; Issues.jsx toolbar/filter/#416 binding/empty-gate; Repo.jsx ref-stream debounce + tab-badge + IDLE_MS; data.js tolerateMissing/tolerateDegraded; icons.jsx #465 header; ToggleSwitch peer/role=switch; danger.js exact-match; writeGate #502; ref-pill/clone helpers; DateTime single renderer. Line numbers drift slightly in places (expected) — guideline explicitly disclaims line numbers ('the cited file + ticket is the reference, not the line number'), so no finding.
NORMATIVE TONE: holds throughout; Decisions & deviations entry for #537 present (law 12).
No blocking issues found. MERGE RECOMMENDATION: ready to merge.
Fixed by PR #543 (review clean — all 6 criteria pass, 36/36 references verified, amendment verbatim), merged. Closing.