From f943deb2e88eb3fc0f21d9c87b291319413ec412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9A=A9=EC=9D=80?= Date: Mon, 27 Jul 2026 00:04:46 +0900 Subject: [PATCH] fix(docs): make the landing stylesheets direction-aware (#146) Markleaf lays out right-to-left note content correctly since v2.28.0, but the site around it was written in physical directions: `left` on the skip link and the file-receipt card, `border-left` on the trust-ledger dividers, `padding-left` on the feature-point bullets and their dash, `text-align: right` on the channel-row status. Each of those is identical under LTR and visibly broken under RTL. Swap them for logical properties, and add `[dir="rtl"]` rules for the three things direction alone does not carry: an Arabic-script system font stack (no webfont is fetched, the pages still request nothing), normal letter-spacing in place of the negative Latin display tracking, and a mirrored hover nudge with its :active reset. No page changes here - the six landing pages, six privacy pages and six READMEs are untouched. Measuring every element on 14 pages at four widths, old CSS against new, the real pages come out box-identical; the only computed-style difference anywhere is `text-align` reporting `start` instead of `left`. A throwaway dir="rtl" copy of index.html and privacy.html mirrors correctly and clears the overflow gate at 320px. That gate only fired on `docs/**.html`, so a stylesheet change - the one most able to overflow a page - could reach main untested. `docs/**.css` joins both path filters. Co-Authored-By: Claude Opus 5 --- .github/workflows/landing-check.yml | 6 ++- HISTORY.md | 8 ++++ docs/landing.css | 59 ++++++++++++++++++++++------- docs/style.css | 8 +++- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/.github/workflows/landing-check.yml b/.github/workflows/landing-check.yml index bf1d786..c83920e 100644 --- a/.github/workflows/landing-check.yml +++ b/.github/workflows/landing-check.yml @@ -7,7 +7,9 @@ # privacy page at a range of widths and fails on horizontal overflow. # # Kept out of android-build.yml so it does not tangle with the required "build" -# check and only runs when the docs actually change. +# check and only runs when the docs actually change. The stylesheets are in that +# set too: layout lives in the CSS, so a markup-only filter would let exactly the +# change most able to overflow a page through untested. name: Landing check on: @@ -15,11 +17,13 @@ on: branches: [main] paths: - 'docs/**.html' + - 'docs/**.css' - 'scripts/check-landing-overflow.mjs' - '.github/workflows/landing-check.yml' pull_request: paths: - 'docs/**.html' + - 'docs/**.css' - 'scripts/check-landing-overflow.mjs' - '.github/workflows/landing-check.yml' workflow_dispatch: diff --git a/HISTORY.md b/HISTORY.md index 99c54df..676cd2c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,11 @@ +## 2026-07-27 - Landing stylesheets made direction-aware (#146) + +- Trigger: looking back at #146 — the Persian reader whose right-to-left note content laid out left-to-right, fixed in v2.28.0 — the same question one level up: the app handles RTL, the site around it never had to. The work started as a Persian README plus landing page; the maintainer cut that mid-flight, leaving only the part that has to exist before any RTL page can. +- Analysis: both stylesheets were written in physical directions — `left` on the skip link and the file-receipt card, `border-left` on the trust-ledger dividers, `padding-left` on the feature-point bullets and their `::before` dash, `margin-left` in the file-browser bar, `text-align: right` on the channel-row status, `padding-left` on the privacy page's lists. Each is a no-op to swap under LTR and a visible break under RTL. Three things do not follow from direction at all: the font stacks name Latin/CJK faces only, the display tracking is negative (which closes up a joined script), and `translateX` on the channel-row hover has no logical form. +- Contract/scope: physical offsets become logical (`inset-inline-start`, `padding-inline-start`, `border-inline-start`, `text-align: start/end`); the three exceptions get `[dir="rtl"]` rules — an Arabic-script *system* stack (no webfont, the pages fetch nothing), `letter-spacing: normal`, and a mirrored hover nudge with its `:active` reset. No new page and no content change: the six landing pages, six privacy pages and six READMEs are untouched. +- Verification: geometry diff of every element on 14 pages x 4 widths, old CSS vs new. The twelve real pages come out box-identical; the only computed-style change anywhere is `text-align` reporting `start` instead of `left` on three `.channel-row em`. Two throwaway `dir="rtl"` copies of `index.html` and `privacy.html` moved 20 elements and picked up the new stack, and screenshots confirm the mirror by eye — the file-receipt card and its accent border swap to the inline-start edge. `check-landing-overflow.mjs` passes 14 pages x 6 widths with both probes included. Pixel diffing was tried first and abandoned: the animated tablet GIFs and the `loading="lazy"` webps make the *same* tree screenshot differently twice, which read as four to nine phantom regressions per run. +- Gate: `landing-check` only fired on `docs/**.html`, so a stylesheet change — the one most able to overflow a page — reached `main` untested. `docs/**.css` added to both path filters, which is what makes this change itself gated. + ## 2026-07-25 - Notes grid, first-line titles, and v2.32.0 (#279, #280) - Trigger: two feature requests filed the same afternoon by one external reporter — a grid view for the notes list (#279), and a title field for each note (#280), the second reported as "what is set as the title is not necessarily the first line". diff --git a/docs/landing.css b/docs/landing.css index fa89db7..5e7cdab 100644 --- a/docs/landing.css +++ b/docs/landing.css @@ -141,6 +141,29 @@ li { word-break: keep-all; } +/* Right-to-left pages. The layout itself mirrors on its own — every offset in + this file is a logical property — but typography does not follow from + direction. Arabic-script text needs a face the Latin/CJK stack above does not + carry; no webfont is fetched, so this is a system stack. Groundwork from + #146, where a Persian reader ran into the app's own right-to-left handling. */ +[dir="rtl"] { + --font-display: Vazirmatn, "Noto Naskh Arabic", "Noto Sans Arabic", "Segoe UI", Tahoma, system-ui, sans-serif; + --font-body: Vazirmatn, "Noto Naskh Arabic", "Noto Sans Arabic", "Segoe UI", Tahoma, system-ui, sans-serif; +} + +/* Tight negative tracking is a Latin display trick; in a joined script it pulls + letters into each other. */ +[dir="rtl"] :is(h1, h2, h3) { + letter-spacing: normal; +} + +/* Mono + wide tracking + uppercase reads as a Latin small-label device, and + Arabic script has no equivalent — keep the scale, drop the Latin styling. */ +[dir="rtl"] :is(.kicker, .story-step, .channel-status, .release-line) { + font-family: var(--font-body); + letter-spacing: normal; +} + :focus-visible { outline: 0.1875rem solid var(--color-focus); outline-offset: var(--space-1); @@ -157,7 +180,7 @@ li { background: var(--color-primary-ink); color: var(--color-surface); font-weight: 700; - left: var(--space-4); + inset-inline-start: var(--space-4); padding: var(--space-3) var(--space-4); position: fixed; text-decoration: none; @@ -417,12 +440,12 @@ li { .file-receipt { background: var(--color-surface); - border-left: var(--space-1) solid var(--color-primary); + border-inline-start: var(--space-1) solid var(--color-primary); bottom: 0; box-shadow: 0 var(--space-2) var(--space-6) var(--color-shadow-soft); display: grid; gap: var(--space-1); - left: calc(-1 * var(--space-6)); + inset-inline-start: calc(-1 * var(--space-6)); max-width: 18rem; padding: var(--space-4) var(--space-6); position: absolute; @@ -448,7 +471,7 @@ li { } .hero-product > figcaption { - padding-left: var(--space-4); + padding-inline-start: var(--space-4); } .trust-ledger { @@ -466,7 +489,7 @@ li { } .proof-item + .proof-item { - border-left: 0.0625rem solid var(--color-white-line); + border-inline-start: 0.0625rem solid var(--color-white-line); } .proof-item p { @@ -546,7 +569,7 @@ li { .feature-points li { color: var(--color-ink); - padding-left: var(--space-6); + padding-inline-start: var(--space-6); position: relative; } @@ -554,7 +577,7 @@ li { color: var(--color-primary); content: "—"; font-weight: 800; - left: 0; + inset-inline-start: 0; position: absolute; } @@ -606,7 +629,7 @@ li { .file-browser-bar strong { font-size: var(--text-caption); - margin-left: var(--space-2); + margin-inline-start: var(--space-2); } .ownership-demo pre { @@ -808,6 +831,16 @@ li { transform: translateX(0); } +/* The nudge should follow the reading direction; translateX has no logical + form, so right-to-left gets its own pair (order matters — :active resets). */ +[dir="rtl"] .channel-row:hover { + transform: translateX(calc(-1 * var(--space-1))); +} + +[dir="rtl"] .channel-row:active { + transform: translateX(0); +} + .channel-row strong, .channel-row small { display: block; @@ -828,7 +861,7 @@ li { font-size: var(--text-caption); font-style: normal; font-weight: 750; - text-align: right; + text-align: end; } .channel-paused em { @@ -943,7 +976,7 @@ li { } .file-receipt { - left: var(--space-4); + inset-inline-start: var(--space-4); } .trust-grid { @@ -955,7 +988,7 @@ li { } .proof-item + .proof-item { - border-left: 0; + border-inline-start: 0; border-top: 0.0625rem solid var(--color-white-line); } @@ -1028,7 +1061,7 @@ li { .file-receipt { bottom: var(--space-2); - left: var(--space-3); + inset-inline-start: var(--space-3); max-width: calc(100% - var(--space-6)); padding: var(--space-3) var(--space-4); } @@ -1054,7 +1087,7 @@ li { } .channel-row em { - text-align: left; + text-align: start; } } diff --git a/docs/style.css b/docs/style.css index c633d47..b7f2f33 100644 --- a/docs/style.css +++ b/docs/style.css @@ -27,6 +27,12 @@ body { line-height: 1.65; } +/* Arabic-script text has no face in the stack above; a right-to-left page needs + one. No webfont is fetched — see the same note in landing.css. */ +[dir="rtl"] body { + font-family: Vazirmatn, "Noto Naskh Arabic", "Noto Sans Arabic", "Segoe UI", Tahoma, system-ui, sans-serif; +} + a { color: inherit; } @@ -336,7 +342,7 @@ footer a { } .content ul { - padding-left: 1.3rem; + padding-inline-start: 1.3rem; } .content pre {