Commit Graph

1880 Commits

Author SHA1 Message Date
Scott Idem
8ed766bbca fix(sys-bar): fix hover bounce, horizontal overflow, add collapsible sections
- Hover info strip is now absolute-positioned above the bar (opacity fade
  with delay-500) so it never shifts the bar layout — fixes the bounce
- Panel widened to w-80 with overflow-x-hidden — fixes horizontal scroll
  caused by sub-components hardcoding w-72 inside the padded panel
- All panel sections are now collapsible (Access open by default, others
  closed) — reduces vertical crowding; matches launcher_cfg pattern
- Section headers show current state inline (access level, theme name/mode)
- Admin section groups cfg + debug trigger together cleanly
- Bar transitions use duration-200 for snappier feel without bounce

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 15:45:35 -04:00
Scott Idem
c3c3e1cbcb feat(sys-menu): replace sys_menu with new e_app_sys_bar component
New compact bar + expandable panel design:
- Compact strip (bottom-right): auth shield, font cycler, dark/light toggle,
  edit mode toggle (authenticated+), menu expand — icon-only by default,
  labels reveal on hover
- Hover info strip shows person name + access level when logged in
- Expanded panel: sign in/out, access/passcode, appearance (theme), admin
  (config + URL builder + debug trigger) — all gated same as before
- Debug overlay trigger moved into admin section (edit mode only)
- All business logic preserved via existing sub-components (unchanged)
- e_app_sys_menu.svelte retained but no longer mounted (import commented out)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 15:31:21 -04:00
Scott Idem
a3de95629a feat(sys-menu): add URL param builder to app config panel
New e_app_url_builder.svelte component lets admins construct and copy
shareable URLs with any combination of core global params (iframe, theme,
theme_mode, key). Outputs full URL by default; toggleable to params-only
string for pasting onto existing links. Integrated into e_app_cfg Utilities
section (visible in edit mode).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 15:27:19 -04:00
Scott Idem
456674cc3e fix(launcher): remove ghost Flowbite close btn; add working Close btn in footer
The Flowbite Dialog component (which Drawer wraps internally) renders a
<CloseButton type='submit'> by default when dismissable=true. Since the
Drawer does not use the form/dialog mechanism, that button appeared at the
bottom of the drawer but did nothing. Fix: dismissable={false} on the cfg
Drawer suppresses it.

launcher_cfg.svelte footer redesigned:
- Lower-left: Close button (always visible) — mirrors top-right X, useful
  when the user has scrolled down through long config sections
- Lower-right: Reload (always visible, shorter label)
- Full-width Debug Panel button (edit_mode only, below the row)

Click-outside behavior unchanged — Flowbite Dialog outsideclose defaults
to true, so tapping outside the drawer still closes it.
2026-03-13 15:07:46 -04:00
Scott Idem
bf22b4a512 fix(launcher): fix cfg drawer medium-width wrapping; rename Hardware→Device tab; native OS in edit_mode
- launcher_cfg_section.svelte: Remove md:grid-cols-2 from content wrapper.
  Root cause of the middle-width layout issue: at md breakpoint the drawer
  is only 384px wide but the section body switched to 2-column, cramming
  full-width content blocks into ~170px each. Always grid-cols-1 now.

- launcher_cfg.svelte: Rename Hardware tab to Device (neutral — applies
  even in browser). Reorder Device tab content: Sync Timers first (relevant
  to all devices), then native sections behind $ae_loc.is_native || edit_mode.
  Updates still hidden behind is_native only (no useful preview).

- launcher_cfg_native_os.svelte: Add dev-preview banner when edit_mode is
  on but not running in Electron. electron_relay.ts guards all calls with
  'if (!native) return null' so there are no import errors or crashes —
  controls simply show with a warning indicator. Removes stale placeholder
  comment left by a previous agent.
2026-03-13 14:54:28 -04:00
Scott Idem
71795461dd feat(launcher): reorganize cfg drawer into Setup/Hardware/Dev tabs
- Setup (default): Oral/Poster preset, WS Controller, Screen Saver
- Hardware: Electron health/OS/updates (native only) + Sync control
- Dev: Local reset/debug tools — tab hidden until Edit Mode is on

Edit Mode toggle added as subtle pencil icon in the cfg drawer header
(low opacity when off, primary-colored when active). This is intentional
— onsite kiosk operators should not stumble on it, but admins doing
setup can find and toggle it without leaving the drawer.

Dev tab visibility and the Debug Panel button both gate on edit_mode,
keeping the default view clean for non-technical operators.
2026-03-13 14:28:23 -04:00
Scott Idem
ce0c8b03c9 feat(launcher): Oral/Poster Kiosk mode preset toggle + ae_mode WS command
Adds a two-button Session Mode Preset toggle in Display & App Modes cfg:
- 'Oral / Default' restores all menus/headers/iframe off
- 'Poster Kiosk'   sets iframe=true + hides menu, header, footer

When WS is connected (local_push or remote controller), tapping a preset
sends ae_mode:poster / ae_mode:oral to all connected devices so an operator
can reconfigure the whole room from one device.

ae_mode:{poster|oral} command handler added to handle_ws_recv() in
+layout.svelte — receives and applies the same preset on remote devices.
2026-03-13 13:58:37 -04:00
Scott Idem
1417fafcd3 feat(launcher): auto-apply kiosk URL params on Launcher link for poster sessions
When on a Poster Session in Pres Mgmt, the Launcher nav link now appends
?iframe=true&launcher_menu=hide so the recipient opens a clean kiosk view
without the site header or left session panel.

- ae_comp__events_menu_nav: add events__launcher_extra_params prop; update
  launcher_sess_qry to merge extra params after session_id
- session_page_menu: derive is_poster from type_code and pass the kiosk
  params into the Launcher link
2026-03-13 13:41:49 -04:00
Scott Idem
a5a5022143 fix(launcher): remove wasted top space in iframe/menu-hidden mode; vh bottom buffer
events/+layout.svelte:
  the events nav is actually rendered. Adds pt-0 for the launcher case
  (nav never rendered there; launcher manages its own header offset).
- pb-48 (fixed 12rem) → pb-[25vh] — scrolls ~25% of viewport below
  last card on any screen size, scales properly on phone/tablet/desktop.

launcher/+layout.svelte outer wrapper:
- Static mt-4 replaced with conditional:
    mt-12 when launcher header is visible (matches h-12 header height,
           keeps content clear of the absolute overlay)
    mt-2  when launcher header is hidden (minimal breathing room only)
- Result: iframe mode + launcher_header=hide → near-zero top dead space
2026-03-13 13:24:03 -04:00
Scott Idem
e3e81226a0 feat(launcher): URL params to control iframe/menu/header/footer visibility
Allows sharing a clean link that auto-configures display state on any
device — no manual setup required, ideal for tablet PWA kiosk deployment.

All four params are optional and independent. Values persist in
localStorage so they survive reloads; the URL param always wins when
present. Read inside the existing reactive URL-sync $effect, which
fires on every SPA navigation (unlike the root onMount which only
fires once on initial load).

Supported params:
  ?iframe=true/false          — hide/show global sys & debug menus
  ?launcher_menu=hide/show    — hide/show left session/location panel
  ?launcher_header=hide/show  — hide/show 'Æ Launcher v3' header bar
  ?launcher_footer=hide/show  — hide/show the status footer

Example clean poster-kiosk link:
  /events/{id}/launcher/{loc_id}?session_id={sess_id}
    &iframe=true&launcher_menu=hide&launcher_header=hide
2026-03-13 13:16:26 -04:00
Scott Idem
0c18eea31c refactor(pres_mgmt): consistent layout, menu structure, and centering
- Add (pres_mgmt)/+layout.svelte with shared section wrapper (max-w-7xl mx-auto)
  so all child pages center correctly on wide viewports
- Strip per-page outer <section> tags from session, presenter, location pages;
  replace with inner <div max-w-7xl mx-auto> for detail constraint
- Restructure all page menus from flex-row to flex-col so nav bar occupies its
  own row and options/actions sit in a separate justified row below — prevents
  unwanted wrapping when nav is w-full
- Standardize Æ Core button visibility to edit_mode && manager_access across all
  menus; update button style to ae_btn_warning for visual distinction
- Add w-full + justify-between to ae_comp__events_menu_nav outer div

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 13:11:23 -04:00
Scott Idem
752dca290a feat(launcher): dedicated Digital Poster session card-grid view
Create launcher_session_view_posters.svelte — a touch-first card-grid
layout for Digital Poster sessions, designed for tablet/phone PWA use.

Layout:
- 1 column on mobile, 2 on sm, 3 on xl
- Each poster card: title (line-clamp-3) + presenter name/affiliation +
  'Open Poster' action button at card bottom
- Poster code (or 1-based index fallback) badge in top-right corner
- Card active:scale-[0.98] for tactile touch press feedback
- Sticky compact session header strip with name, code, and poster count
- Optional 'Session Resources' strip for rare session-level files
- overflow-y-auto + grow so the grid scrolls; header strip stays fixed

Integration:
- launcher_session_view.svelte: import + delegate when type_code==='poster'
- launcher_file_cont.svelte: min-w-96 → w-full on poster button so it
  fills its container (card or list row) without overflow on small screens
- WS open/close/zoom command pipeline unchanged (all in launcher_file_cont
  and +layout.svelte which were not modified for the WS paths)
2026-03-13 12:42:12 -04:00
Scott Idem
5f1169bb4c fix(launcher): use parent type_code for session_type, not per-file field
The event_session_type_code field on file objects is often null, causing
poster-mode files to fall back to 'oral' and render as download buttons
instead of modal openers.

- launcher_session_view: session-level files now use derived type_code
- launcher_presenter_view: add session_type prop (default 'oral'); parent passes type_code
- launcher_presenter_view_posters: hardcode poster/modal (only ever rendered in poster context)
- launcher_menu event/location files unchanged: no session context, field is the only signal
2026-03-13 11:46:17 -04:00
Scott Idem
c29ac9f9f5 fix(pres_mgmt): use w-full on Session and Presenter page sections
Session ID page: replace `container mx-auto` with `w-full` — removes the
Tailwind breakpoint max-width cap that was narrower than the outer layout's
max-w-7xl on smaller desktop viewports, and eliminates the double-padding
from nested container classes.

Presenter ID page: replace the conflicting `md:container items-center mx-auto
h-full min-w-full max-w-max` with a clean `w-full`. The `items-center` was
the main bug — in flex-col context it horizontally centered children (presenter
details, file upload form, file list) at their content width instead of
stretching them to fill the available space. Removes all of the conflicting
min/max width overrides.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 11:05:55 -04:00
Scott Idem
633930f65a refactor(pres_mgmt): menu consistency — modal pattern, prop cleanup, styling
All 6 *_page_menu.svelte files now consistently use:
- Flowbite Modal (not expandable panels) with matching header/close pattern
- interface Props (no export keyword) with only props actually used
- flex flex-row flex-wrap gap-0.5 on ae_menu__object_options span

Removed unused props and their call-site bindings:
- location_page_menu: removed data prop; +page.svelte drops data={data}
- locations_page_menu: removed unused log_lvl prop
- presenter_page_menu: removed data prop; +page.svelte drops {data}
- event_reports_page_menu: removed data prop; +page.svelte drops {lq__event_obj} data pass

event_page_menu: fixed interface export keyword (was export interface)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 11:05:02 -04:00
Scott Idem
26dbe57b22 fix(pres_mgmt): migrate QR generation from API to js_generate_qr_code
The API-based generate_qr_code was returning 404 (backend endpoint broken),
causing TypeError crashes on the Presenter, Session, and Location views.
Switch all three to the pure-JS js_generate_qr_code('str', { str: url_str })
which uses the qrcode npm library client-side — consistent with badge views.

- presenter_view.svelte: replace generate_qr_code, remove unused qr_id_url var
- session_view.svelte: replace generate_qr_code, remove unused slct import
- location_view.svelte: replace generate_qr_code, remove unused slct/slct_trigger imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 11:02:04 -04:00
Scott Idem
b18cda98b7 feat(launcher): poster modal zoom sync, clean close buttons
- Add modal_zoom_fit state (default: fit); resets on every new poster open
- Zoom/Fit toggle button + image double-tap on controller tablet
- Both zoom triggers send ae_zoom:fit/zoom over WS to remote display (local_push)
- ae_zoom: handler added to handle_ws_recv() for remote device
- Replace 3 scattered close buttons with single bottom control bar:
    - [Zoom/Fit] always visible on controller
    - [Close Both] sends ae_close WS + clears local modal (local_push only)
    - [Back to List] clears local modal only; remote keeps showing current poster
- Bottom bar hidden on controller=remote (kiosk display-screen mode)
- native pinch-to-zoom via touch-action: pinch-zoom on img (no JS library needed)
- pb-14 on modal bodyClass prevents buttons from overlapping poster content
2026-03-12 19:57:33 -04:00
Scott Idem
90615ad5cc docs(badges): update print behavior docs + Zebra test day plan
- MODULE__AE_Events_Badge_Templates: rewrite Print Layout Architecture
  section with accurate cross-browser behavior table and Chrome margin
  guidance
- PROJECT__AE_Events_Badges_Review_Print: add TASK 4.1 print CSS
  centering history; correct Chrome squish root cause explanation
- PROJECT__AE_Events_Zebra_Hardware_Test_Day: new — comprehensive
  pre-test and day-of checklists for ZC10L hardware test ~2026-03-16
- TODO__Agents: add [Badges] Zebra ZC10L Hardware Testing section
2026-03-12 19:23:47 -04:00
Scott Idem
cfa9e85d05 feat(badges): add demo background pattern toggle in edit mode
Adds a 🎨 button to the badge debug bar (edit-mode only) that cycles
through 5 SVG background patterns keyed by badge type color palette:
stripes, dots, diamonds, grid, swirls.

Swirl tile is 64×64 with corner-to-corner cubic bezier S-curves so
edges align seamlessly when tiled. Off by default; never prints.
2026-03-12 19:23:21 -04:00
Scott Idem
c867795f4d Badges: use position:fixed for print centering — bypasses all ancestor layout issues 2026-03-12 18:25:31 -04:00
Scott Idem
5410bb4a8c Badges: switch to transform-based print centering — fixes Firefox physical printer shift 2026-03-12 18:08:27 -04:00
Scott Idem
bc23e8a399 Badges: fix Firefox print centering (overflow:auto+display:contents); add print layout Playwright tests 2026-03-12 17:58:33 -04:00
Scott Idem
5ef66af98d Badges: fix print centering — override overflow:hidden on body/html in print 2026-03-12 17:46:50 -04:00
Scott Idem
1e70271002 Badges: add temp print debug outlines — diagnose centering issue 2026-03-12 17:32:31 -04:00
Scott Idem
05aa0288cb Badges: fix print centering — dissolve .main_content; hide footer/scroll buttons from print; document print layout architecture 2026-03-12 17:28:25 -04:00
Scott Idem
f26416de22 Badges: print centering via display:contents — collapse wrappers, body as flex center 2026-03-12 17:21:56 -04:00
Scott Idem
11a6d5d35c Badges: center badge vertically + horizontally in print preview; scaffold print_margin_cfg 2026-03-12 17:05:41 -04:00
Scott Idem
c3a4ff45c7 Badges: clean print output — suppress outlines, hide app chrome, reset layout container 2026-03-12 16:52:17 -04:00
Scott Idem
25359f12b8 Badges: soft feathered glow around badge wrapper in dark mode 2026-03-12 16:43:11 -04:00
Scott Idem
dd2deb1ab1 Badges: fix debug pre dark mode colors; white ring shadow around badge in dark mode 2026-03-12 16:31:26 -04:00
Scott Idem
745067b228 Badges: force light-mode rendering on badge print area — ignore dark theme 2026-03-12 16:26:21 -04:00
Scott Idem
6e8f44b009 Badges: center badge wrapper via mx-auto so Edit Mode debug div doesn't shift layout 2026-03-12 16:15:55 -04:00
Scott Idem
b4ab60ebba Badges: PVC wrapper hugs card tightly; hide 'Front of badge' label when single-sided 2026-03-12 16:05:08 -04:00
Scott Idem
7b340de139 Badges: fix button layout \u2014 Revert/Save/X always in fixed positions 2026-03-12 15:54:06 -04:00
Scott Idem
23422c8f27 Badges: hide Save until field is dirty; warning style when unsaved changes 2026-03-12 15:48:26 -04:00
Scott Idem
f74fc593b0 Badges: allow_tracking auto-expands when true; TC modal on info button 2026-03-12 15:41:32 -04:00
Scott Idem
9888374d86 Badges: auto-focus input when field accordion opens; add Revert button to field forms 2026-03-12 15:28:37 -04:00
Scott Idem
9e64815d62 Badges: panel widens to w-80 while editing, font scaling on active card 2026-03-12 15:21:13 -04:00
Scott Idem
5f6f1b408b Badges: live preview while typing, accordion entrance animation, register tailwindcss-animate 2026-03-12 14:54:26 -04:00
Scott Idem
961b05c5e4 Badges: controls panel UX polish — remove identity card, elevate print btn, style buttons 2026-03-12 14:46:08 -04:00
Scott Idem
b92c0bdcf1 Badges: retire v1 render, badge print page kiosk UX improvements
- ae_comp__badge_obj_view.svelte (v1) removed — replaced by v2 everywhere
- print/+page.svelte: always uses v2, removed v1/v2 toggle
  Header redesigned for kiosk: name + Ready/Printed×N status chip,
  event title subtitle. Re-print shortcut only in trusted+edit_mode.
  Duplicate 'Print Now' header button removed (canonical is in right panel).
- ae_comp__badge_print_controls.svelte:
  Identity card added at top (name, badge type, badge ID).
  Pronouns moved to attendee-level section (was staff-only).
  'Staff adjustments' divider added before badge type section.
  Attendee info section header label added.
- ae_comp__badge_obj_view_v2.svelte: debug JSON blocks gated behind edit_mode.
- print_list/+page.svelte: updated import to v2.
2026-03-12 14:19:58 -04:00
Scott Idem
c7063806b7 refactor: v2 badge render display-only + print button to controls panel
- ae_comp__badge_obj_view_v2.svelte: removed all inline edit-mode logic
  (floating Edit/Save/Cancel panel, placeholder list, input fields, save/cancel
  functions). V2 is now purely a display component — editing happens in the right
  panel (ae_comp__badge_print_controls.svelte) via liveQuery reactivity.
  display_* values are now $derived directly from lq__event_badge_obj.
  Fixes effective_badge_type_code CSS class (was always empty in previous v2).

- ae_comp__badge_print_controls.svelte: added "Print Badge" button at the top of
  the panel. Increments print_count, fires window.print(), then navigates to badge
  search. This is now the canonical print action for v2; the header "Print Now"
  button is a shortcut that calls window.print() only (no count tracking).
  Clarified $ae_loc.edit_mode comment — global AE Edit Mode is not a badge-specific
  edit toggle; used here only to gate reprints.

- print/+page.svelte: added clarifying comments on is_edit_mode (global vs local)
  and the header "Print Now" button (shortcut only, no count tracking).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 13:48:08 -04:00
Scott Idem
2198c55e27 feat: badge v2 auto-scaling text with Element_fit_text
Adds binary-search font auto-scaling for badge text fields, replacing
the character-count heuristic in v1. New files:

- action_fit_text.ts: Svelte action using binary search + MutationObserver
  + ResizeObserver. Pass null to disable (manual override mode).
- element_fit_text.svelte: Component wrapper with min/max/manual_size/
  height/width props. height prop required for overflow detection to work.
- ae_comp__badge_obj_view_v2.svelte: Badge render using Element_fit_text
  for name/title/affiliations/location in display mode. font_size_* props
  default to undefined (auto-scale) instead of numeric defaults.
  fit_heights derived object provides layout-aware section heights for
  badge_3.5x5.5_pvc, badge_4x5_fanfold, and badge_4x6_fanfold layouts.
  flex_justify() maps shorthand ('around','between','even') to CSS values.
  Edit mode uses plain divs — inputs are never auto-scaled.

print/+page.svelte: Added v1/v2 toggle button in header. V1 preserved
as fallback. font_size_* passed as null (not ?? undefined) to v2 so
auto-scaling is active by default; manual override from print controls
still disables it per-field.

Docs: PROJECT__AE_Events_Badges_Review_Print.md updated with kiosk
workflow design intent, email address rule (always event_badge.email),
permission model alignment gap (TASK 4.0), and v2 implementation status.
TODO__Agents.md: completed items removed, badge polish tasks updated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 13:23:47 -04:00
Scott Idem
dfad2831d6 Updated documentation. 2026-03-11 19:06:37 -04:00
Scott Idem
0da5894529 fix: stable WS client ID + presentation name for poster modal title
- Generate and persist crypto.randomUUID() as controller_client_id on first
  launcher load (events_loc is persisted so it survives page reloads).
  Previously fell back to Date.now() on every reload.
- ae_open: handler now resolves presentation name via Dexie lookup chain:
  file.for_id -> presentation.name, falling back to file.filename.
  Remote modal now shows the presentation title instead of raw filename.
2026-03-11 19:01:21 -04:00
Scott Idem
3df09713d3 fix: poster WS remote control - push open and resolve file obj
- launcher_file_cont: poster 'Open Poster' click now sends ae_open:event_file
  command to remote display when controller=local_push and WS is connected
- +layout.svelte handle_ws_recv: ae_open: handler now looks up the file obj
  from Dexie after setting modal__open_event_file_id, so the remote modal
  has the hosted_file_id needed to render the poster image (was showing
  'No image selected' on remote device)
2026-03-11 18:54:40 -04:00
Scott Idem
5db66bc888 feat: upgrade launcher WebSocket to V3 protocol
- New element_websocket_v3.svelte:
  - URL path /v3/ws/group/{id}/client/{id}
  - Auth via ?api_key=...&jwt=... query params (browsers can't set WS headers)
  - Strict WS_Message_V3 schema: msg_type + target fields
  - 45s heartbeat to maintain Redis presence TTL
  - Self-echo detection via from_id (server-stamped)
  - Target 'group' (was 'all'), 'direct' (was 'dm')
- launcher/+layout.svelte:
  - Swap Element_websocket_v2 -> Element_websocket_v3
  - Add api_key and jwt props for V3 auth
  - Fix handle_ws_recv: type -> msg_type (V3 schema)
  - Remove unused 'type' prop passed to element
2026-03-11 17:50:08 -04:00
Scott Idem
3f5f554595 Now with websocket use instructions. :-) 2026-03-11 17:16:44 -04:00
Scott Idem
c73b5a09e4 feat: add element_access_denied.svelte; use in badge review page
- New reusable element_access_denied.svelte with title, message, action props
- Badge review page: swap inline 'Access Denied' card with the component
- Project doc: all 6 steps complete, status → Complete
2026-03-11 17:06:11 -04:00
Scott Idem
0c11cfb3e2 fix: replace alert() access guard in event settings with proper UX
- Remove blocking alert() + module-level browser guard
- Move access check to onMount with 500ms grace delay (matches /core pattern)
- Add {:else} block: Lock icon + 'Access Restricted' message + redirect link
- Remove now-unused 'browser' import; add Lock from lucide
2026-03-11 16:59:26 -04:00