Commit graph

8 commits

Author SHA1 Message Date
ScreenTinker 0c91390e56 fix(frontend): workspace switcher (Phase 3 MVP) + SW network-first migration + platform_admin accessible_workspaces expansion + static render CSS cleanup. The switcher adds a sidebar dropdown for users who are members of multiple workspaces, renders as static text with a 'Workspace' label for single-workspace users, and muted 'No workspace' for zero. Uses existing /api/auth/me's accessible_workspaces and POST /api/auth/switch-workspace endpoints. Platform admin / superadmin users now see all workspaces in accessible_workspaces (closing the known regression from 88d91b1) via a LEFT JOIN that preserves workspace_role semantics (null = acting-as, role string = direct member). No cap on the list - deliberate for now, revisit at 50+ workspaces. SW fix bumps rd-admin-v1 -> rd-admin-v2 and switches fetch strategy from cache-first to network-first so the server's existing Cache-Control: no-cache + ETag headers actually get respected; preserves offline fallback. Static render CSS drops the bordered-box chrome that was making single-workspace users think the static text was clickable. Includes test fixture user switcher-test@local.test (credentials in fixture SQL header). Surfaced by semetra22 / Discord report about 'screens jumbled up' post-migration; root cause was the missing workspace switcher UI making devices in non-active workspaces appear missing. 2026-05-12 10:55:09 -05:00
ScreenTinker 2068bc8833 Video walls: free-form canvas editor, leader-driven sync, group dissolve, progress bars
Wall editor: replaces the small grid with a Figma-style pan/zoom canvas. Each
display is a rectangle that can be dragged/resized to match its physical
arrangement; a separate semi-transparent player rect overlays the screens and
defines what content plays where. Drag empty space to pan, wheel to zoom,
"Center" button auto-fits content. Per-rect numeric x/y/w/h panel; arrow keys
nudge by 1px (10px with shift). Negative coordinates supported for screens
offset above/left of the origin. Coords rounded to integers on save.

Wall rendering: each device receives screen_rect + player_rect, maps the
player into its viewport with vw/vh and object-fit:fill so vertical position
of every source pixel is identical across devices that share viewport height.
Leader emits wall:sync at 4Hz with sent_at timestamp; followers apply
latency-adjusted target and use playbackRate ±3% for sub-300ms drift,
hard-seek for >300ms. Followers stay muted; leader unmutes via gesture with
AudioContext priming and pause+play retry to bypass Firefox autoplay.
"Tap to enable audio" overlay as a final fallback.

Reconnect handling: server re-evaluates leader on device:register so the
top-left tile reclaims leadership when it returns. Followers emit
wall:sync-request on entering wall mode (incl. reconnect) so they snap to
position immediately instead of drifting until the next periodic tick.

Group dissolve: removing a device from its last group clears its playlist
to mirror wall-leave semantics. Leaving a group with playlists on remaining
groups inherits the next group's playlist.

Dashboard: walls render as their own card section (hidden the device cards
they contain). Multi-select checkboxes on cards + "Create Video Wall" toolbar
action that creates the wall, removes devices from groups, and opens the
editor. dashboard:wall-changed broadcast triggers live re-render. Per-card
playback progress bar driven by play_start events forwarded from devices.

Security: PUT /walls/:id/devices verifies caller owns each device (or has
team-owner access via the widgets pattern), preventing cross-tenant device
takeover. wall:sync and wall:sync-request validate that the sending device
is a member of the named wall; relay re-stamps device_id with currentDeviceId
so clients can't spoof or shadow-exclude peers.

Schema: video_walls += player_x/y/width/height, playlist_id;
video_wall_devices += canvas_x/y/width/height. All idempotent migrations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 23:11:16 -05:00
ScreenTinker 0bd34544e5 QA fixes: toast aria-live + scope playlist flex-wrap to mobile
- Toast now announces via role="status"/aria-live="polite" by default,
  and role="alert"/aria-live="assertive" for errors. Screen readers
  previously got nothing when notifications appeared.
- Move playlist-item flex-wrap:wrap from inline style into the
  @media (max-width: 768px) block so desktop rows don't wrap controls
  when the viewport is intermediate-narrow.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 16:00:41 -05:00
ScreenTinker 06d3e93e21 Mobile: horizontal-scroll tables + tab fade (Commit 4/4)
- Wrap wide tables (admin, settings, reports) in .table-wrap with
  min-width on the table so they scroll horizontally on narrow screens
  instead of collapsing rows.
- Add global .table-wrap { overflow-x: auto } utility.
- Mobile: add mask-image fade on .tabs right edge to hint scrollability
  when tabs overflow; flex-shrink:0 on .tab keeps labels intact.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 15:56:01 -05:00
ScreenTinker b45d81cfaa Mobile: modals, forms, tap targets, toast (Commit 3/4)
- Buttons: min-height 44px (36px for .btn-sm, 40px for .btn-icon) on mobile
- Inputs/selects/textarea: font-size 16px (prevents iOS focus zoom), min-height 44px
- Pairing input: scaled letter-spacing down so 6 digits fit at 375px width
- Modals at 95vw: tighter header/body/footer padding so content breathes
- Toast container: bar-style full-width (left/right:12px) instead of
  fixed-right 280px that clipped below 400px viewports

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 15:51:12 -05:00
ScreenTinker 7c8504d593 Mobile: grid + layout reflow (Commit 2/4)
- Dashboard stats row (.dash-stats-row): flex column on mobile
- Content-library toolbar: stack upload area + remote URL + YouTube boxes vertically
- Info grid: 1 col on mobile (was 2 col); device detail metadata reads cleaner
- Content grid: drop to 1 col below 480px (iPhone SE)
- Schedule controls: wrap, device select fills row
- Schedule calendar: already wrapped in overflow-x:auto, kept horizontal-scroll
  approach (future: dedicated mobile day-view)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 15:50:56 -05:00
ScreenTinker 09dbb4b199 Mobile: sidebar polish (Commit 1/4)
- Move hamburger click + backdrop click out of inline onclick into app.js
- Add aria-label/aria-expanded/aria-controls to hamburger button
- Close drawer on Escape keypress
- Bump hamburger button to 44px, nav-link min-height to 44px (tap targets)
- Bump .content top padding to 68px on mobile to match 44px hamburger

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 15:49:49 -05:00
ScreenTinker 1594a9d4a4 Initial open source release
ScreenTinker - open source digital signage management software.
MIT License, all features included, no license gates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 12:14:53 -05:00