- 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.
- 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.
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.
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
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
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
- 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>
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)
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
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>
- 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
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.
- 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>
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>
- 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.
- 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)
- Add ae_auth_error writable store to ae_stores.ts
- Wire api_get_object, api_post_object, api_patch_object to set
ae_auth_error on 401/403 (browser-only guard, never fires SSR)
- Root layout watches ae_auth_error; only raises flag_expired when
a JWT is present (prevents false trigger on unauthenticated loads)
- Dismissible amber banner added to root layout (non-blocking, above content)
- Tested via debug menu trigger; banner fires and clears correctly
state_referenced_locally warnings in ae_idaa_comp__event_obj_id_edit_v2.svelte:
- lu_country_list and lu_country_subdivision_list $state runes were read in
top-level synchronous if/else blocks; moved into onMount
- Add onMount to Svelte imports
- Remove unused .field-richtext CSS selector
Remaining 32 warnings in 2 files are either:
- CSS @apply / @reference warnings from the CSS language service not understanding
Tailwind v4 at-rules (harmless, build works fine)
- Warnings in the legacy v1 edit form (no code references it)
Two state_referenced_locally warnings on data prop in
recovery_meetings/[event_id]/+page.svelte: reading a $props()
rune synchronously in a top-level if (browser) block only captures
the initial value.
Move the postMessage block into onMount (browser-only by nature);
remove the now-redundant 'browser' import.
- Update stale comment in menu_location_list.svelte: prop is already
$bindable(null), comment incorrectly said it was not
- Confirm cleanup_tmp_files is wired in launcher_background_sync.svelte
- Mark both items done in TODO__Agents.md
- Remove vestigial try_cache param from generate_qr_code (never used in body)
- Remove vestigial try_cache from ae_core_functions: load_ae_obj_id__site_domain,
update_ae_obj_id_crud, update_ae_obj_id_crud_v2 (none referenced it in body)
- Add proper SWR pattern to load_ae_obj_id__sponsorship_cfg and
load_ae_obj_id__sponsorship; change defaults from false to true
- Change load_ae_obj_id__event_file default try_cache from false to true
(consistent with load_ae_obj_li__event_file)
- Change load_ae_obj_id__hosted_file default try_cache from false to true
(consistent with load_ae_obj_li__hosted_file)
- Remove stale try_cache arg from element_ae_crud.svelte caller
element_manage_event_file_li_all.svelte — also derives context_session_type_code
via Dexie chain (event_presentation → session, or event_presenter → presentation →
session) and passes it to element_manage_event_file_li. Fixes the button not showing
when viewing a presenter's files from the session view.
element_manage_event_file_li_direct.svelte — extends the Dexie chain to also handle
event_session (direct lookup) and event_presentation, not just event_presenter.
Both: correct API URL to /v3/hosted_file/ per backend agent's examples.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>