When a passcode matched, entered_passcode was cleared and the trigger
was set, but show_passcode_input was never set to false. This left the
input visible so users could keep typing after access was granted.
Set show_passcode_input = false immediately after clearing entered_passcode
on a successful match, consistent with the intent described in the
handle_clear_access() function which resets it to true on clear.
Export button now only renders when event_exhibit.leads_api_access === true,
preventing a 403 that would always fire otherwise. Endpoint confirmed live on
backend. TODO updated to reflect export + allow_tracking gate both resolved.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Updated download_export__event_exhibit_tracking to call
/v3/action/event_exhibit/{exhibit_id}/tracking_export instead of the
legacy /event/exhibit/{exhibit_id}/tracking/export (V1 path).
Added doc comment listing the expected export columns so the backend
agent has the full field spec when implementing the endpoint.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- QR scanner: after badge loads, blocks add with 'Tracking Opt-Out' warning
card if allow_tracking !== true; replaced deprecated CheckCircle → CircleCheck
- Manual search: shows ShieldOff 'Opt-Out' label per row for blocked badges;
add_as_lead() also guards against programmatic bypass
- Fix: ae_comp__exhibit_tracking_obj_li — Loader2 from wrong package
@lucide/svelte → LoaderCircle from lucide-svelte
- ae_types.ts: added allow_tracking and agree_to_tc to ae_EventBadge interface
- README.md (leads): full rewrite reflecting actual current state and known gaps
- TODO__Agents.md: updated Leads entry from stale 'NEXT MAJOR FEATURE' to
accurate in-progress status with remaining checklist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ae_stores.ts
- Extract auth/identity section (~80 lines) into ae_stores__auth_loc_defaults.ts
- Spread auth_loc_defaults into ae_app_local_data_defaults (zero consumer changes)
ae_events_stores.ts (both loc and sess structs)
- badges → ae_events_stores__badges_defaults.ts
- launcher → ae_events_stores__launcher_defaults.ts
- leads → ae_events_stores__leads_defaults.ts
- pres_mgmt → ae_events_stores__pres_mgmt_defaults.ts
Each new file exports *_loc_defaults and *_sess_defaults. The store files
now reference these by name instead of embedding inline objects. All
$ae_loc.* and $events_loc.* consumer paths are unchanged.
svelte-check: 0 errors, 0 warnings
- Remove unused `import { offset } from '@floating-ui/dom'`
- Remove ver_idb constant and field (same as ae_stores / ae_events_stores)
- Remove commented-out personal Novi UUIDs (security hygiene — these belong
in site_cfg_json on the server, not in source; idaa layout already reads
them from $ae_loc.site_cfg_json and writes to idaa_loc at mount)
- Add comment explaining novi_admin/trusted/jitsi_mod_li are server-driven
- Remove dead writable/persisted alternatives and console.log lines
- Remove stale 'Updated 20xx-xx-xx' date comments
- Condense redundant tracking comments to single-line form
Verified all FA spans and variant-* patterns in launcher files are inside
HTML comment blocks — no live FA or legacy variant classes remain.
The freeze was precautionary; the actual migration was already done.
Phase 3 for Launcher is now limited to UX/card styling polish only.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Marked all non-frozen, non-IDAA style migration work as done:
- FA→Lucide across events, pres_mgmt, core, badges, leads, hosted_files
- variant-* → preset-* across all modules
- badge code_to_icon refactor, FA CDN scoped to IDAA layout
- global svg.lucide inline fix in app.css
Phase 3 deferred: Launcher (post-April 2026) and IDAA (last priority).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lucide renders <svg> elements which default to inline-block in browsers,
causing icons to break onto their own line when mixed with text — unlike
FA spans which were display:inline.
Added svg.lucide { display: inline; vertical-align: middle; } to app.css
so all Lucide icons flow inline with adjacent text globally, matching the
FA icon behavior without needing class="inline" on every icon instance.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move the FA 5.15.4 CDN <link> from app.html (global) into
src/routes/idaa/+layout.svelte <svelte:head> so it only loads
on /idaa/* routes. All other modules now use Lucide exclusively.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Convert 6 template-level FA spans to Lucide components (Star, Biohazard,
Asterisk, Wifi). The code_to_html JS string dict (dietary symbols used
with {@html}) retains FA spans since they are raw HTML strings, not
Svelte template markup — FontAwesome CSS (app.html CDN) renders them.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ae_idaa_comp__event_obj_id_edit.svelte: the component <style> block used
@reference + @apply for ~10 local classes (.section-card, .field-label,
.toggle-chip, .day-chip, etc.). svelte-check's CSS language service does
not understand Tailwind v4 @reference/@apply directives and emitted 23
'Unknown at rule' warnings.
Fix: all local class usages inlined as Tailwind utility strings directly
on each element (~80 template sites). The <style> block is removed.
Conditional classes on toggle-chip/day-chip converted to ternary expressions.
svelte-check now reports 0 errors and 0 warnings across all files.
Svelte 5 does not support <style> or conditional {#if} blocks wrapping
<style> tags inside <svelte:head>. The parser treats them as raw-text
elements and reports '<script> was left open' at EOF.
Fix:
- Print media CSS moved to static/ae-print-badge.css (plain static file,
no framework magic needed — all selectors target global elements).
- svelte:head now uses a simple <link> to that file.
- $effect injects the @page size dynamically per template layout field,
avoiding the Svelte 5 parser limitation for conditional style injection.
- Badge_template interface in db_events.ts: added cfg_json / data_json
(standard Aether object fields that were missing from the type).
Replaces all FontAwesome <span class="fas/fab fa-*"> with Lucide Svelte
components across 20 launcher files. launcher_cfg_section.svelte icon prop
changed from FA string to AnyComponent (svelte:component for dynamic render).
Dynamic file-extension icon now uses ae_util.file_extension_icon_lucide().
Fixes class: directives on components (invalid in Svelte 5) → ternary class.
Removes title prop from Lucide components → wrapping <span title="...">.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Defaults to true (authenticated_access required) — no change to existing consumers
- Launcher file buttons set require_auth=false to allow unauthenticated downloads
Replaces all alert() calls in the user/pass auth flow with reactive state.
Button shows: Verifying… (disabled) → Failed — retry? (red) →
Enter credentials first (amber) → Username/User ID Sign In (default).
Error messages (wrong password, no person record, no server response)
appear as small text below the button on failure.
Clicking the button resets to default so retry is clean.
Also removes dead commented-out alert and cleans up the promise chains.
No type="button" issues found — all non-submit buttons were already typed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes the debug alert() calls from the email magic-link flow.
Button now shows live feedback inline:
- 'Sending…' while the lookup is in flight (disabled + cursor-wait)
- 'Email sent ✓' on success (green fill)
- 'No account found' if no user matches the email
- 'Error — retry?' on network/API failure
- 'Enter an email first' if submitted empty
Clicking the button while showing a result resets it to the default label.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign In/Out (e_app_sign_in_out.svelte):
- Remove redundant internal header (sr-only was broken by :global CSS override)
- Full-width form inputs and buttons with 'or' divider between the two methods
- Signed-in state shows centered username and full-width action buttons
Access/Passcode (e_app_access_type.svelte):
- Fix 'Locked' button: was running trigger=true (no-op permission reprocess);
now correctly toggles show_passcode_input so the input shows/hides on click
System bar (e_app_sys_bar.svelte):
- Dynamic section headers: Sign In/Out shows username when signed in;
Access/Passcode shows ShieldEllipsis/ShieldMinus/ShieldUser based on state
- Fix passcode input not showing on re-open via menu button:
onDestroy resets show_element__passcode_input=false; toggle_expand now
restores it to true for anonymous/no-access state (matches handle_shield_click)
- Broaden anonymous check from === 'anonymous' to !access_type || === 'anonymous'
- Remove dead getElementById focus call (DOM not ready at that point;
focus_input binding in Element_access_type handles it correctly)
- Appearance section: mode/font buttons at top, dark mode gets amber tint
in light mode for visual context, theme select uses text-sm
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- [journal_id]/+page.svelte was rendering a second Journal_obj_id_edit
alongside the one already in ae_comp__journal_obj_id_view.svelte,
causing the modal to open twice simultaneously.
- ae_comp__journal_obj_id_view: changed show={} to bind:show={} so that
closing the modal properly writes back to journals_sess, preventing the
store from fighting the close and re-opening it.
Flowbite's built-in outsideclose was unreliable for this side-drawer setup.
Root cause: Flowbite's _onclick handler uses dlg.getBoundingClientRect() to
detect backdrop clicks. This works in theory for showModal() dialogs, but
something in the Svelte transition / stacking context prevented it firing.
Fix: bypass Flowbite's detection entirely.
- onclick prop on <Drawer> is spread through Flowbite's restProps chain
to the native <dialog> element, overriding the broken _onclick handler.
Handler: just closes the drawer unconditionally.
- A stopPropagation wrapper div around all visual panel content ensures
that clicks INSIDE the panel never bubble up to the dialog element.
Only genuine backdrop clicks (outside the visual panel area) reach
the dialog and trigger the close handler.
ESC key is unaffected — it fires oncancel not onclick.
- Hover info strip is always in DOM (opacity-only toggle, no {#if} mount)
so first hover no longer triggers a layout recalc/flash
- Bar strip gets fixed h-9 height so inline label text appearing on
group-hover can never shift the bar vertically
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
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>
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>
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.
- 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