- 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>
97 lines
3.6 KiB
Python
97 lines
3.6 KiB
Python
"""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()
|