website: M3 part A - the controller's shell, and the home page inside it
gates / gates (push) Successful in 6m58s
gates / gates (push) Successful in 6m58s
The direction the operator chose: the controller's FRAME around the website's own
content. Staged at /preview/m3/, noindex, nothing live.
website/assets/shell.css - 117 rules COPIED VERBATIM from felhom-controller
style.css @ dcd89364a4 (sidebar, mobile top bar, off-canvas drawer, and the
component atoms the restyled pages use: btn, alert, app-info-card, launch-*,
stack-detail-card, form-*). Exactly ONE rule is not verbatim and says so:
body.shell { display:flex; min-height:100vh }, which lives in the controller's
base rather than in a component, scoped to .shell so other pages are untouched.
The generator NAMES every rule it copies and REFUSES to write the file if one has
disappeared upstream. That is not ceremony: it already caught two things this
session. It refused because .sidebar::-webkit-scrollbar does not exist (only the
-track override does), and because prefers-reduced-motion is split across FIVE
separate blocks in the controller - reading only the first would have silently
lost four rules. The M1 round lost a rule exactly this way.
The bare `body { flex-direction: column }` that broke M1's phone layout is copied
this time, by name, as are body.nav-open and the no-js/js pair.
Load order is deliberate: shell.css AFTER site.css. Thirteen selectors exist in
both files with different meanings (.nav-links, .page-header, .lang-globe*, .ico)
- a horizontal site nav there, a vertical sidebar here. Later wins, and a page
that does not load shell.css is completely unaffected.
website/preview/m3/index.html - the home page in the shell. Content is /preview/'s
cleaned text; body carries `shell page-index` so the existing .page-index content
rules (caps, flow, vs, band, who-mini) are reused rather than duplicated. Six
sections, left-aligned headers, the controller's cards. Head tags (title, meta
description, canonical, hreflang) are already the FINAL values, so the switch in
part D needs no head edit.
Four changes from the operator's mockup, each with its reason in the generator:
1. the active item follows the page (the mockups show Inditopult active on all)
2. Teszteles is ALSO a primary button at the top of the lower group - it is the
one action we want and the mockup buries it at the bottom
3. the Alkalmazasok categories are anchors on /alkalmazasok: real URLs, no
JS-only state
4. ADDED GYIK. It is in today's nav; dropping it silently would take a page out
of navigation, which is not a change a restyle gets to make.
scripts/site_gates.py - gate 3 extended rather than duplicated, as asked: a SHELL
set whose pages must carry an IDENTICAL <nav class="sidebar"> after the active
marker is normalised. RED-PROOFED: a one-character change to one menu label on a
second shell page convicts. It also prints "DIFFER" rather than a reassuring
"identical" count when it fails - a false reassurance printed beside a conviction
is the exact defect this repo files rows about.
documentation/design/design-system.md - new "Shell" section: what is shared (tokens
+ shell + atoms), what each side owns, how a change flows (controller first, the
website's copy the same week), and that the cross-repo gate is deliberately NOT
built yet.
This commit is contained in:
+40
-2
@@ -115,9 +115,16 @@ MOCKUPS = {os.path.join("preview", "m1", "index.html"),
|
||||
os.path.join("preview", "m1", "kapcsolat.html"),
|
||||
os.path.join("preview", "m2", "index.html")}
|
||||
|
||||
PAGES = list(TWINS) + list(TWINS.values()) + sorted(NO_TWIN) + sorted(MOCKUPS)
|
||||
# SHELL (2026-10-11, M3) — pages that wear the controller's frame instead of the website's
|
||||
# <nav>/<footer>. They are staged under /preview/m3/ until the operator's go, and at the switch
|
||||
# every live page becomes one of these. They keep every other check; what changes for them is
|
||||
# WHICH block has to be identical across the set: the sidebar, not the nav and footer. Gate 3
|
||||
# below does both, so there is one identity gate rather than two.
|
||||
SHELL = {os.path.join("preview", "m3", "index.html")}
|
||||
|
||||
PAGES = list(TWINS) + list(TWINS.values()) + sorted(NO_TWIN) + sorted(MOCKUPS) + sorted(SHELL)
|
||||
EN_PAGES = set(TWINS.values())
|
||||
HU_PAGES = set(PAGES) - EN_PAGES - MOCKUPS
|
||||
HU_PAGES = set(PAGES) - EN_PAGES - MOCKUPS - SHELL
|
||||
ANALYTICS_EXEMPT = {"szolgaltatasok-nonpublic.html"} | MOCKUPS
|
||||
ANALYTICS_MARK = "https://stats.felhom.eu/script.js"
|
||||
SITE = "https://felhom.eu"
|
||||
@@ -225,6 +232,37 @@ for lang, members, ref in (("hu", HU_PAGES, "index.html"), ("en", EN_PAGES, os.p
|
||||
fail("%s: <nav> differs from %s (after active-marker normalization)" % (p, ref))
|
||||
if foot != rfoot:
|
||||
fail("%s: <footer> differs from %s" % (p, ref))
|
||||
# gate 3b (2026-10-11, M3): the SHELL set carries a sidebar instead of the nav+footer, and that
|
||||
# sidebar is duplicated into every page because the site is static with no build step. The thing
|
||||
# that keeps the duplication honest is this check: every shell page's <nav class="sidebar"> block
|
||||
# must be identical once the active marker and the globe's current item are normalised away —
|
||||
# exactly the normalisation norm_block already does for the old chrome.
|
||||
_shell_by_lang = {}
|
||||
for p in sorted(SHELL):
|
||||
s = pages.get(p)
|
||||
if s is None:
|
||||
continue
|
||||
m = re.search(r'<nav class="sidebar" id="sidebar">.*?</nav>', s, re.DOTALL)
|
||||
if not m:
|
||||
fail("%s: no <nav class=\"sidebar\"> block — a shell page carries the shell" % p)
|
||||
continue
|
||||
_shell_by_lang.setdefault("en" if p.startswith("en" + os.sep) else "hu", []).append((p, norm_block(m.group(0))))
|
||||
for _lang, _members in sorted(_shell_by_lang.items()):
|
||||
_ref_p, _ref = _members[0]
|
||||
_bad = 0
|
||||
for _p, _blk in _members[1:]:
|
||||
if _blk != _ref:
|
||||
_bad += 1
|
||||
fail("%s: <nav class=\"sidebar\"> differs from %s (after active-marker normalization) — "
|
||||
"the shell is duplicated into every page, so it must be identical" % (_p, _ref_p))
|
||||
# say "identical" ONLY when they are. A reassuring count printed next to a conviction is the
|
||||
# same defect this repo files rows about.
|
||||
if _bad:
|
||||
print(" shell sidebar: %d of %d %s page(s) DIFFER from %s"
|
||||
% (_bad, len(_members) - 1, _lang, _ref_p))
|
||||
else:
|
||||
print(" shell sidebar: %d %s page(s), all identical to %s" % (len(_members), _lang, _ref_p))
|
||||
|
||||
if os.path.join("en", "index.html") in pages:
|
||||
_f = re.search(r"<footer>.*?</footer>", pages[os.path.join("en", "index.html")], re.DOTALL)
|
||||
if not _f or "households in Hungary" not in _f.group(0):
|
||||
|
||||
Reference in New Issue
Block a user