screentinker/frontend
ScreenTinker 803f4ec26d Portrait templates, a canvas that matches the layout, and a playlist mockup
Three related pieces. Zones were already stored as percentages and layouts
already carried their own width/height, so this is mostly design work rather
than plumbing.

SIX PORTRAIT TEMPLATES at 1080x1920. Deliberately not the landscape set turned
sideways: "Three Column" at 33% each becomes three tall slivers, and a 15% ticker
that reads well across 1080px is a 288px band on a 1920px-tall panel, so the
portrait ticker is 12% and the PiP window is wider than tall (a 30x30 box is
square on 16:9 and 324x576 in portrait). Seeded in schema.sql for fresh installs
AND as a migration, because schema.sql never runs on an existing database — and
upgraded instances are exactly the ones with portrait panels already deployed.

THE EDITOR CANVAS followed a hardcoded padding-top:56.25% — the 16:9 ratio trick.
Authoring a portrait layout meant dragging zones on a landscape canvas: the
percentages landed correctly on the panel and looked wrong everywhere you
designed them. It now derives from the layout's own height/width, clamped so a
pathological row cannot produce an unusable editor.

THE PLAYLIST PAGE now draws where content actually lands. A playlist has no
intrinsic layout, so the server reuses #104's derivation from the items' own zone
bindings and returns it. Previously an item could be tagged "Bottom Ticker" with
nothing to say the ticker is a thin strip along the bottom — people assigned by
zone name and found out by looking at a screen. Empty zones are dimmed, because
an empty zone shows its background colour on a real panel and that is worth
seeing before publishing rather than after.

Verified against a copy of prod: 6 templates and 12 zones created, the 7
landscape templates untouched, no errors at boot, and a second boot changes
nothing. Each stacked template's zone heights sum to exactly 100%.

1074 pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
2026-08-05 13:23:15 -05:00
..
assets Landing: replace iframe mock with dashboard screenshot 2026-04-21 19:47:13 -05:00
compare feat(seo): strengthen integrations internal linking + drop public status link (#178) 2026-07-13 12:11:30 -05:00
css Say Teams is switched off instead of showing an empty list 2026-07-28 19:46:26 -05:00
guides feat(seo): strengthen integrations internal linking + drop public status link (#178) 2026-07-13 12:11:30 -05:00
integrations feat(seo): strengthen integrations internal linking + drop public status link (#178) 2026-07-13 12:11:30 -05:00
js Portrait templates, a canvas that matches the layout, and a playlist mockup 2026-08-05 13:23:15 -05:00
legal docs(privacy): disclose error and diagnostic telemetry from players 2026-05-15 15:31:21 -05:00
vendor test(api): fix spec scope drift + guard it in CI; Redoc provenance 2026-06-12 18:45:09 -05:00
41498e6c84045d9d187f4504c122e54f.txt feat(seo): IndexNow + landing-page optimization (schema, FAQ, CWV, content) (#177) 2026-07-13 11:22:37 -05:00
agency.html feat(agency): per-token upload folder — auto-created, subtree-confined (#158) (#171) 2026-07-12 21:23:25 -05:00
api-docs.html docs(api): OpenAPI spec, Redoc at /docs, CI spec-lint 2026-06-12 18:45:09 -05:00
index.html Put Members in the nav, reveal titles on touch, and stop a stale heartbeat killing a socket 2026-07-28 20:00:35 -05:00
landing.html feat(seo): strengthen integrations internal linking + drop public status link (#178) 2026-07-13 12:11:30 -05:00
manifest.json Initial open source release 2026-04-08 12:14:53 -05:00
robots.txt SEO: add meta tags, sitemap, robots.txt, comparison pages, guides, internal linking 2026-04-28 20:54:32 -05:00
sitemap.xml feat(seo): IndexNow + landing-page optimization (schema, FAQ, CWV, content) (#177) 2026-07-13 11:22:37 -05:00
sw-admin.js fix(sw): stop the admin service worker from breaking video playback 2026-06-08 23:08:13 -05:00