UX-13 P5: Dutch text, STYLE check, DOCS screenshots, period editor
- app/ui_text/nl.json and app/uitext.py: every page word in Dutch, English fallback per key; the page picks by browser language. Home's sentences move into ui_text `home_words`, so /status?lang=nl builds them in Dutch. - test_ui_text.py: EN/NL key and placeholder parity, STYLE limits, jargon lists for both languages, no inline details, untranslated Dutch caught. Shared rules moved unchanged to tools/style_rules.py. - tools/ux13_screenshots.sh/.py: DOCS screenshots from the demo fixtures in headless Chromium; docs/img/ux13/. Battery modes (P3): no screenshot. - "Other time windows": a list editor (ui.periods) that builds static_profile and names bad times, empty prices, overlaps and gaps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""UX-13 P5: the DOCS screenshots of the new screens, taken from the real page.
|
||||
|
||||
Run by tools/ux13_screenshots.sh, which serves tools/ux13_demo.py fixtures and
|
||||
runs this inside the Playwright image. Each shot fails the run on a page
|
||||
error, so a broken screen is never pictured.
|
||||
|
||||
python3 ux13_screenshots.py OUT_DIR # DEMO_<STATE> = the fixture's URL
|
||||
|
||||
The battery-mode screens (P3) are not built, so there is no shot of them:
|
||||
DOCS.md says so instead of showing a mock-up.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
OUT = sys.argv[1]
|
||||
DESKTOP = {"width": 1000, "height": 900}
|
||||
PHONE = {"width": 390, "height": 844}
|
||||
|
||||
|
||||
def url(state):
|
||||
return os.environ[f"DEMO_{state.upper()}"]
|
||||
|
||||
|
||||
def shot(browser, name, state, route, *, lang="en-GB", size=DESKTOP,
|
||||
full=True, act=None, only=None):
|
||||
ctx = browser.new_context(locale=lang, viewport=size,
|
||||
color_scheme="light", reduced_motion="reduce")
|
||||
page = ctx.new_page()
|
||||
errors = []
|
||||
page.on("pageerror", lambda e: errors.append(str(e)))
|
||||
page.goto(url(state) + route)
|
||||
page.wait_for_load_state("networkidle")
|
||||
page.wait_for_timeout(1500) # the first /status and checks
|
||||
if act:
|
||||
act(page)
|
||||
page.wait_for_timeout(1500) # the debounced start checks
|
||||
path = os.path.join(OUT, name + ".png")
|
||||
if only:
|
||||
page.locator(only).screenshot(path=path)
|
||||
else:
|
||||
page.screenshot(path=path, full_page=full)
|
||||
ctx.close()
|
||||
if errors:
|
||||
raise SystemExit(f"{name}: page errors {errors}")
|
||||
print(f" {name}.png")
|
||||
|
||||
|
||||
def open_tariff(page):
|
||||
page.locator("details.grp[data-g=tariff] > summary").click()
|
||||
page.locator("details.grp[data-g=meter] > summary").click() # close it
|
||||
# The fixture site is on a dynamic contract: its fallback gets windows.
|
||||
page.get_by_role("radiogroup", name="Price when the feed is down") \
|
||||
.get_by_role("radio", name="Other time windows").click()
|
||||
|
||||
|
||||
def windows(page, overlap=False):
|
||||
open_tariff(page)
|
||||
add = page.get_by_role("button", name="+ Add a time window")
|
||||
rows = (("07:00", "23:00" if overlap else "22:00", "mon-fri", "0.34"),
|
||||
("22:00", "07:00", "mon-fri", "0.26"),
|
||||
("00:00", "24:00", "sat,sun", "0.24"))
|
||||
for i, (a, b, days, price) in enumerate(rows, start=1):
|
||||
add.click()
|
||||
page.get_by_label(f"Window {i}, From").fill(a)
|
||||
page.get_by_label(f"Window {i}, To").fill(b)
|
||||
page.get_by_label(f"Window {i}, Days").select_option(days)
|
||||
page.get_by_label(f"Window {i}, Price").fill(price)
|
||||
page.locator("[data-key='ui.periods']").scroll_into_view_if_needed()
|
||||
|
||||
|
||||
def main():
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
with sync_playwright() as p:
|
||||
b = p.chromium.launch()
|
||||
shot(b, "home-running", "running", "#home")
|
||||
shot(b, "home-running-nl", "running", "#home", lang="nl-BE")
|
||||
shot(b, "home-shadow", "shadow", "#home")
|
||||
shot(b, "home-phone", "running", "#home", size=PHONE)
|
||||
shot(b, "home-setup-only", "setup", "#home", full=False)
|
||||
shot(b, "settings-installer", "running", "#settings")
|
||||
shot(b, "settings-installer-nl", "running", "#settings", lang="nl-BE")
|
||||
tariff = "details.grp[data-g=tariff]"
|
||||
shot(b, "settings-time-windows", "running", "#settings",
|
||||
act=windows, only=tariff)
|
||||
shot(b, "settings-time-windows-overlap", "running", "#settings",
|
||||
act=lambda page: windows(page, overlap=True), only=tariff)
|
||||
shot(b, "setup-step-1", "new", "#setup")
|
||||
shot(b, "setup-step-1-nl", "new", "#setup", lang="nl-BE")
|
||||
b.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user