From ca94a716d8208d85d82d93942f2c4ace50717afc Mon Sep 17 00:00:00 2001 From: npeter83 Date: Wed, 30 Sep 2026 02:19:54 +0200 Subject: [PATCH] =?UTF-8?q?docs(design):=20composition=20and=20the=20reade?= =?UTF-8?q?r=20=E2=80=94=20a=20chapter=20and=20a=20Conformance=20step=20(E?= =?UTF-8?q?30=20S6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rules covered each piece; nothing asked whether a screen works as a whole, and the person page passed every rule with half its panel empty. New chapter: the space is used, one focal point, worst real data, where am I, a click answers at once (no outside service on open), zoom and text size first-class (the owner reads zoomed in). Conformance step 5 writes one composition line per screenshot and checks 200% zoom and the largest text size. Anti-patterns and a decision-log row to match. HU: the download worker setting reads "Párhuzamos letöltések" (a leftover from the S5 sweep). --- docs/DESIGN.md | 39 ++++++++++++++++++++++++ frontend/src/i18n/locales/hu/config.json | 4 +-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/DESIGN.md b/docs/DESIGN.md index f98d2aa3..2350d0d1 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -38,6 +38,11 @@ runs this check before it is called done (E28 S3g): which the measure cannot trace to a component) and the playlist table's own rows. 4. **Seen.** A screenshot of every changed state, thin edges at 1:1; the tablet widths (1024 × 768, a narrow split screen) when the layout can reflow. Phones are the E29 epic's, not this check's. +5. **Judged as a whole** (E30 S6). For each screenshot, one written line on its composition: where the empty + space is, what hugs one side, what the eye lands on first. Then the screen at 200% browser zoom and at + the largest text size. Both are held to [Composition and the reader](#composition-and-the-reader--decided-e30-s6). + A rule that holds is not the same as a screen that works: the person page passed every rule above with + half its panel empty. ## The design lab @@ -435,6 +440,36 @@ pick a density step; it never changes the anatomy or loses an action. [Nielsen # - **Reading measure.** Prose (a synopsis, a biography, a channel's description) is capped at ~65 characters a line (the `measure` utility) wherever its container can be wider. [WCAG 1.4.8] +## Composition and the reader — _Decided_ (E30 S6) + +The rules above say how each piece looks; these say whether the screen works as a whole, for the one +reader it is built for. Found when the person page passed every rule with its biography in the left half +of a full-width panel and nothing on the right. + +- **The space is used.** A narrow element in a wide container (prose at `measure`, a form, a short list) + comes with a decision about the rest of the width: a second column with related content (the person + page: facts and bio left, "Known for" right), a container sized to its content, or a layout that stacks. + A band of nothing wider than about a third of a panel, beside content that stops short, is a finding. + [Material layout, Gestalt proximity] +- **One focal point, then an order.** A screen has one thing the eye lands on first (the page heading, the + hero, the player), then the sections, then the metadata. A heading level keeps one look across screens; + a second focal point competing with the first is a finding. [Nielsen #8, HIG hierarchy] +- **Worst real data, not the demo row.** A screen is judged with the longest title, the Hungarian label, + zero items, the largest list, a missing picture and a missing field. None of them clips, overlaps or + leaves a hole where a value was. [Nielsen #9, WCAG 1.4.10] +- **Where am I.** The browser tab names the place and the object in it ("Nicolas Cage · Plex · Siftlode"), + the rail marks the place, and Back returns to the same view at the same scroll position with focus + where it was. [Nielsen #1, WCAG 2.4.2] +- **A click answers at once.** A control shows its pressed or changed state within ~100ms (an optimistic + update, a spinner in the control); what a screen opens with is the app's own data — an outside service + (TMDB, YouTube) is fetched ahead of time by a job, not on the click, so a page never waits on it. + Late content keeps its place (B8). [Nielsen #1, RAIL] +- **Zoom and text size are first-class.** The owner reads with the browser zoomed and a large text size. + Every screen holds at 200% browser zoom on a desktop window and at the largest Settings text size at + 1024 wide: nothing clipped or overlapping, no sideways page scroll, every control reachable and at + least its rung, text wrapping rather than cut. Measured, not assumed, on every UI change. [WCAG 1.4.4, + 1.4.10, 1.4.12] + ## Interaction rules — _Decided_ - **Keyboard:** everything works by keyboard, in visual order, with no traps. A shortcut is a row in @@ -561,6 +596,9 @@ pick a density step; it never changes the anatomy or loses an action. [Nielsen # - A click handler on text that swallows the user's text selection. - A colour literal, a px font size, a px-frozen box. - An empty state shown for an error. +- Half a panel left empty beside content that stops short. +- A page that waits on an outside service when the user opens it. +- A screen checked only at 100% zoom and the default text size. ## Decision log @@ -635,6 +673,7 @@ pick a density step; it never changes the anatomy or loses an action. [Nielsen # | 2026-09-27 | C4 as built | `initialFocus` required on every `Modal`; the commit row in `ModalFooter`, portalled under the body from any depth; the fades driven by the body's scroll timeline; `interactive-widget=resizes-content` | An optional prop defaulting to the ✕; a `footer` prop (the issue composer's buttons live three components down); always-on fades | A default is how 21 dialogs came to open on the ✕; lifting the composer's state to reach a prop is the larger change; a resting fade dimmed the first line | | 2026-09-27 | C3 + C5 as built | A tap toggles the bar through `pointerType` from `pointerdown`; a double-tap takes back its first tap's toggle; the card's pair is the video card's `MediaResumeButtons` (Continue / Restart), a sibling over the picture; the YT description is an ⓘ click popover | A delayed single tap (wait out the double-tap window); new "Resume / From the start" words for Plex; the pair inside the picture's button | A delayed tap feels dead; one media card says one pair of words; a button inside a button is invalid and the hover row already sits beside the picture | | 2026-09-27 | C2 as built | The side panel's drawer is `ui/Modal` `drawer-start`; drawer = a coarse pointer or below 768; the pin offered in its header ≥ 1024 | A drawer of its own inside `SidePanel` | Esc, Back, the scrim, the trap and the scroll lock are the dialog's; a second implementation is how two shells drift | +| 2026-09-30 | Composition and the reader (E30 S6) | A chapter and a Conformance step: the space is used, one focal point, worst real data, where am I, a click answers at once, zoom and text size first-class; the person page as two columns (facts and bio left, "Known for" right) | Rules for pieces only; the bio in a full-width panel; a narrower panel | The person page passed every piece rule with half its panel empty; the owner reads zoomed in, so zoom is a requirement, not a nicety | | 2026-09-30 | Hungarian words (E30 S5) | The D3 list: Feed, Shorts, Admin, Token, Port stay; stream, Prio, Job, Audit, Demo, Auto, Info, Frontend/Backend, Backfill, transcode get the Hungarian word; one name per thing (kérelem, behúzás, one "Test connection") | Keep every loanword; translate Feed/Shorts too | The owner chose the list (D3); the final sweep found the same feature under two names in three places | | 2026-09-29 | Numbers and order in the UI language (E30 S3) | Every number through `lib/format.ts` in the UI language (decimal mark, grouping, compact, units); A→Z by the shown name in the UI language's alphabet, client and server alike; the language comes off `useTranslation`, never the singleton | `toFixed`, hand-built "1.2K", `localeCompare` in the browser's locale, byte-order server sorts | A Hungarian reader saw "8.3", "1.2K", "Életrajzi" after "Z"; the singleton read also left values in the old language after a switch (React Compiler) | | 2026-09-27 | Narrow rows by container | The download row, the playlist table and the Channels tag row stack by a container query; a fact line never wraps | Breakpoints on the window | The iPad zoomed in, split screen and a column beside a rail are narrow while the window is not; the zoomed download row broke "18.9 / MB" apart | diff --git a/frontend/src/i18n/locales/hu/config.json b/frontend/src/i18n/locales/hu/config.json index b1b8448a..8f6d4344 100644 --- a/frontend/src/i18n/locales/hu/config.json +++ b/frontend/src/i18n/locales/hu/config.json @@ -149,8 +149,8 @@ "hint": "„Plex” = Csatorna/Évad ÉÉÉÉ/… fastruktúra .nfo + poszter fájlokkal (Plexben indexelhető); „Egy mappa” = minden egyetlen mappában." }, "download_worker_concurrency": { - "label": "Worker párhuzamosság", - "hint": "Hány letöltést dolgoz fel a worker párhuzamosan." + "label": "Párhuzamos letöltések", + "hint": "Hány letöltést dolgoz fel egyszerre a letöltő folyamat." }, "sponsorblock_default": { "label": "SponsorBlock alapból",