pres_mgmt: redesign Session View, clean Presentation list, fix transitions
- session_view.svelte: replace flat <ul> with hero card layout - Name as <h1>, date/time chip (primary teal), room chip (tertiary indigo) - QR only rendered when URL is string (not true loading placeholder) - Skeleton pulse placeholders while LiveQuery resolves - Description in surface card with uppercase label - Accessible: aria labels, focus rings, aria-live on no-results section - ae_comp__event_session_obj_li.svelte: - variant-soft-warning (Skeleton v3) -> preset-tonal-warning (v4) - Add transition-colors duration-200 to <tr> rows and session <a> links - ae_comp__event_presentation_obj_li.svelte: - Remove debug breakpoint border colors (red/yellow/gray) - overflow-x-scroll -> overflow-x-auto - Remove heavy preset-filled-surface-400-600 from <ul> container - <li> cards: surface tokens, rounded-xl, shadow-sm, transition - <h4> title bar: bg-surface-100-900 with flex wrap layout - Code badge: hardcoded yellow -> preset-tonal-warning - Description <pre>: hardcoded bg-gray-100 -> bg-surface-100-900 - pres_mgmt/+page.svelte: 'no results' section - bg-yellow-100 + text-yellow-500 -> preset-tonal-warning - Search icon, aria-live, cleaner list in surface card - [session_id]/+page.svelte: rounded-container-token (v3) -> rounded-xl
This commit is contained in:
@@ -552,29 +552,25 @@
|
||||
</div>
|
||||
{:else}
|
||||
<section
|
||||
class="text-center text-2xl bg-yellow-100 p-4 rounded-md lg:max-w-lg space-y-2 mx-auto"
|
||||
class="preset-tonal-warning p-6 rounded-xl lg:max-w-lg space-y-4 mx-auto shadow-sm"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
<div>
|
||||
<span
|
||||
class="fas fa-exclamation-triangle text-2xl text-yellow-500"
|
||||
></span>
|
||||
<strong>No results to show</strong>
|
||||
<span
|
||||
class="fas fa-exclamation-triangle text-2xl text-yellow-500"
|
||||
></span>
|
||||
<br />
|
||||
<div class="text-lg">
|
||||
Please use the search above to find your session.
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-2 text-center">
|
||||
<span class="fas fa-search text-3xl opacity-50" aria-hidden="true"></span>
|
||||
<strong class="text-xl">No sessions found</strong>
|
||||
<p class="text-base opacity-80">
|
||||
Use the search bar above to find your session.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Search by:</strong>
|
||||
<ul class="list-disc list-inside text-lg text-left">
|
||||
<li>Session name</li>
|
||||
<li>Session description</li>
|
||||
<li>Presentation name</li>
|
||||
<li>Presenter names</li>
|
||||
<li>Presenter ID (member ID)</li>
|
||||
<div class="bg-surface-50-900/60 rounded-lg p-3">
|
||||
<span class="text-xs font-bold uppercase tracking-wide opacity-50 block mb-2">Search by any of:</span>
|
||||
<ul class="space-y-1 text-sm">
|
||||
<li class="flex items-center gap-1.5"><span class="fas fa-angle-right text-xs opacity-50" aria-hidden="true"></span> Session name</li>
|
||||
<li class="flex items-center gap-1.5"><span class="fas fa-angle-right text-xs opacity-50" aria-hidden="true"></span> Session description</li>
|
||||
<li class="flex items-center gap-1.5"><span class="fas fa-angle-right text-xs opacity-50" aria-hidden="true"></span> Presentation name</li>
|
||||
<li class="flex items-center gap-1.5"><span class="fas fa-angle-right text-xs opacity-50" aria-hidden="true"></span> Presenter names</li>
|
||||
<li class="flex items-center gap-1.5"><span class="fas fa-angle-right text-xs opacity-50" aria-hidden="true"></span> Presenter ID (member ID)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -101,8 +101,8 @@
|
||||
<!-- Pass observable STORES to child components (they use $) -->
|
||||
<Session_page_menu {data} {lq__event_session_obj} {lq__auth__event_presenter_obj} />
|
||||
|
||||
<!-- Metadata Section -->
|
||||
<div class="bg-surface-50-950 p-4 rounded-container-token shadow-sm border border-surface-200-800">
|
||||
<!-- Metadata Section: Session identity card — name, time, room, host, description -->
|
||||
<div class="bg-surface-50-950 p-4 rounded-xl shadow-sm border border-surface-200-800">
|
||||
<Session_view
|
||||
{lq__event_presenter_obj}
|
||||
{lq__event_session_obj}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
if ($lq__event_session_obj?.id && $events_loc.pres_mgmt.show_content__session_qr && !$events_sess.pres_mgmt.session_qr_url[$lq__event_session_obj.id]) {
|
||||
$events_sess.pres_mgmt.session_qr_url[$lq__event_session_obj.id] = true;
|
||||
let url_str = encodeURI(`${$ae_loc.url_origin}/events/${$lq__event_session_obj.event_id}/session/${$lq__event_session_obj.id}`);
|
||||
|
||||
|
||||
core_func.generate_qr_code({
|
||||
api_cfg: $ae_api,
|
||||
account_id: $slct.account_id,
|
||||
@@ -59,106 +59,132 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- STABLE LAYOUT: No top-level #if gate. Children mount immediately. -->
|
||||
<section class="p-2 space-y-4">
|
||||
{#if $lq__event_session_obj && $events_sess.pres_mgmt.session_qr_url[$lq__event_session_obj.id]}
|
||||
<div class="float-right m-1 p-1 flex flex-col items-center outline outline-gray-200 group transition-all">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => $events_sess.pres_mgmt.qr_bigger = !$events_sess.pres_mgmt.qr_bigger}
|
||||
class="qr_code_btn"
|
||||
title="Toggle QR Code size"
|
||||
>
|
||||
<img
|
||||
src={$events_sess.pres_mgmt.session_qr_url[$lq__event_session_obj.id]}
|
||||
class="qr_code h-32 w-32 transition-all duration-500"
|
||||
class:h-48={$events_sess.pres_mgmt.qr_bigger}
|
||||
alt="URL QR code"
|
||||
/>
|
||||
</button>
|
||||
<MyClipboard
|
||||
value={encodeURI(`${$ae_loc.url_origin}/events/${$lq__event_session_obj.event_id}/session/${$lq__event_session_obj.id}`)}
|
||||
btn_class="m-1 btn btn-sm preset-tonal-warning"
|
||||
hide_icon={true}
|
||||
hide_text={true}
|
||||
>
|
||||
<span class="fas fa-link"></span>
|
||||
</MyClipboard>
|
||||
<!--
|
||||
SESSION VIEW — Speaker Ready Room & Remote Upload
|
||||
Primary users: Presenters uploading files (remote) + Staff helping presenters (onsite).
|
||||
Design intent: "Is this the right session?" must be answerable in <3 seconds.
|
||||
Show: name, time, room, host, description. Hide admin noise unless edit_mode.
|
||||
Section 508: all interactive elements labelled, focus rings, sufficient contrast.
|
||||
-->
|
||||
<section class="space-y-3">
|
||||
|
||||
<!-- SESSION HERO: Name + Schedule + Room -->
|
||||
<div class="rounded-xl border border-surface-200-800 bg-surface-50-900 shadow-sm overflow-hidden">
|
||||
<div class="px-4 pt-4 pb-3 flex flex-col gap-3">
|
||||
|
||||
<!-- QR code: floats top-right, compact by default, toggle to enlarge.
|
||||
Only rendered once the async URL is resolved (string), never while
|
||||
it is still the boolean `true` loading placeholder. -->
|
||||
{#if $lq__event_session_obj && typeof $events_sess.pres_mgmt.session_qr_url?.[$lq__event_session_obj.id] === 'string'}
|
||||
<div class="float-right ml-3 mb-1 flex flex-col items-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => $events_sess.pres_mgmt.qr_bigger = !$events_sess.pres_mgmt.qr_bigger}
|
||||
class="rounded focus-visible:ring-2 focus-visible:ring-primary-500"
|
||||
title="Toggle QR code size"
|
||||
aria-label="Toggle QR code size"
|
||||
>
|
||||
<img
|
||||
src={$events_sess.pres_mgmt.session_qr_url[$lq__event_session_obj.id]}
|
||||
class="transition-all duration-500 rounded border border-surface-200-800"
|
||||
class:h-20={!$events_sess.pres_mgmt.qr_bigger}
|
||||
class:w-20={!$events_sess.pres_mgmt.qr_bigger}
|
||||
class:h-40={$events_sess.pres_mgmt.qr_bigger}
|
||||
class:w-40={$events_sess.pres_mgmt.qr_bigger}
|
||||
alt="QR code link to this session page"
|
||||
/>
|
||||
</button>
|
||||
<MyClipboard
|
||||
value={encodeURI(`${$ae_loc.url_origin}/events/${$lq__event_session_obj.event_id}/session/${$lq__event_session_obj.id}`)}
|
||||
btn_class="btn btn-sm preset-tonal-surface text-xs"
|
||||
hide_icon={false}
|
||||
hide_text={true}
|
||||
>
|
||||
<span class="fas fa-link" aria-hidden="true"></span>
|
||||
</MyClipboard>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Session Name: the primary identity check -->
|
||||
{#if $lq__event_session_obj}
|
||||
<div>
|
||||
<Element_ae_obj_field_editor_v3
|
||||
object_type={'event_session'}
|
||||
object_id={$lq__event_session_obj.id}
|
||||
field_name={'name'}
|
||||
field_type={'text'}
|
||||
current_value={$lq__event_session_obj.name}
|
||||
on_success={() => events_func.load_ae_obj_id__event_session({api_cfg: $ae_api, event_session_id: $lq__event_session_obj.id})}
|
||||
>
|
||||
<h1 class="text-2xl font-bold leading-snug">{$lq__event_session_obj.name}</h1>
|
||||
</Element_ae_obj_field_editor_v3>
|
||||
{#if $ae_loc.edit_mode}
|
||||
<span class="badge preset-tonal-surface text-xs mt-1">code: {$lq__event_session_obj.code}</span>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Skeleton placeholder while LiveQuery resolves -->
|
||||
<div class="h-7 w-2/3 bg-surface-200-800 animate-pulse rounded"></div>
|
||||
{/if}
|
||||
|
||||
<!-- Date/Time + Room as info chips -->
|
||||
{#if $lq__event_session_obj}
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
<span class="inline-flex items-center gap-1.5 text-sm font-semibold px-3 py-1 rounded-full bg-primary-500/10 text-primary-700 dark:text-primary-300 transition-colors duration-200">
|
||||
<span class="fas fa-clock text-xs" aria-hidden="true"></span>
|
||||
{ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, 'dddd')},
|
||||
{ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, $events_loc.pres_mgmt.datetime_format)}
|
||||
–
|
||||
{ae_util.iso_datetime_formatter($lq__event_session_obj.end_datetime, $events_loc.pres_mgmt.time_format)}
|
||||
</span>
|
||||
{#if $lq__event_session_obj.event_location_name}
|
||||
<span class="inline-flex items-center gap-1.5 text-sm font-semibold px-3 py-1 rounded-full bg-tertiary-500/10 text-tertiary-700 dark:text-tertiary-300 transition-colors duration-200">
|
||||
<span class="fas fa-map-marker-alt text-xs" aria-hidden="true"></span>
|
||||
{$lq__event_session_obj.event_location_name}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="h-5 w-1/2 bg-surface-200-800 animate-pulse rounded-full"></div>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Host / POC: visible when assigned and layout config allows -->
|
||||
<div class:hidden={$events_loc.pres_mgmt?.hide__session_poc}>
|
||||
{#if $lq__event_session_obj?.poc_person_id}
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm font-semibold opacity-60">Host:</span>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm preset-tonal-primary transition-colors duration-200"
|
||||
onclick={() => $events_sess.pres_mgmt.show__session_poc_profile = true}
|
||||
aria-haspopup="dialog"
|
||||
>
|
||||
<span class="fas fa-id-card mr-1" aria-hidden="true"></span>
|
||||
{$lq__event_session_obj.poc_person_full_name}
|
||||
</button>
|
||||
|
||||
<Modal title="Host Profile" bind:open={$events_sess.pres_mgmt.show__session_poc_profile}>
|
||||
<Comp_event_session_poc_profile lq__event_session_obj={$lq__event_session_obj} />
|
||||
{#snippet footer()}
|
||||
<button onclick={() => $events_sess.pres_mgmt.show__session_poc_profile = false} class="btn preset-tonal-warning">Close</button>
|
||||
{/snippet}
|
||||
</Modal>
|
||||
</div>
|
||||
{:else if $lq__event_session_obj && !$events_loc.pres_mgmt?.hide__session_poc}
|
||||
<span class="text-sm opacity-40 italic">No host assigned</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Description: shown only when present —
|
||||
long descriptions are scrollable via the parent container -->
|
||||
{#if $lq__event_session_obj?.description}
|
||||
<div class="rounded-lg border border-surface-200-800 bg-surface-50-900 px-4 py-3">
|
||||
<span class="text-xs font-bold uppercase tracking-wide opacity-40 block mb-1">Description</span>
|
||||
<p class="whitespace-pre-wrap text-sm leading-relaxed">{$lq__event_session_obj.description}</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<ul class="space-y-2 px-4">
|
||||
<!-- Name & Code -->
|
||||
<li>
|
||||
{#if $lq__event_session_obj}
|
||||
<Element_ae_obj_field_editor_v3
|
||||
object_type={'event_session'}
|
||||
object_id={$lq__event_session_obj.id}
|
||||
field_name={'name'}
|
||||
field_type={'text'}
|
||||
current_value={$lq__event_session_obj.name}
|
||||
on_success={() => events_func.load_ae_obj_id__event_session({api_cfg: $ae_api, event_session_id: $lq__event_session_obj.id})}
|
||||
>
|
||||
<span class="font-bold text-xl">{$lq__event_session_obj.name}</span>
|
||||
</Element_ae_obj_field_editor_v3>
|
||||
{#if $ae_loc.edit_mode}
|
||||
<span class="badge preset-tonal-surface">code: {$lq__event_session_obj.code}</span>
|
||||
{/if}
|
||||
{/if}
|
||||
</li>
|
||||
|
||||
<!-- Date & Time -->
|
||||
<li>
|
||||
{#if $lq__event_session_obj}
|
||||
<span class="text-sm font-semibold opacity-70">Date & Time:</span>
|
||||
<span class="fas fa-calendar-alt opacity-50 ml-1"></span>
|
||||
<span class="font-medium">
|
||||
{ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, 'dddd')},
|
||||
{ae_util.iso_datetime_formatter($lq__event_session_obj.start_datetime, $events_loc.pres_mgmt.datetime_format)}
|
||||
-
|
||||
{ae_util.iso_datetime_formatter($lq__event_session_obj.end_datetime, $events_loc.pres_mgmt.time_format)}
|
||||
</span>
|
||||
{/if}
|
||||
</li>
|
||||
|
||||
<!-- Host / POC -->
|
||||
<li class:hidden={$events_loc.pres_mgmt?.hide__session_poc}>
|
||||
{#if $lq__event_session_obj}
|
||||
<span class="text-sm font-semibold opacity-70">Host:</span>
|
||||
{#if $lq__event_session_obj.poc_person_id}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm preset-tonal-primary"
|
||||
onclick={() => $events_sess.pres_mgmt.show__session_poc_profile = true}
|
||||
>
|
||||
<span class="fas fa-id-card mr-1"></span>
|
||||
{$lq__event_session_obj.poc_person_full_name}
|
||||
</button>
|
||||
|
||||
<Modal title="Host Profile" bind:open={$events_sess.pres_mgmt.show__session_poc_profile}>
|
||||
<Comp_event_session_poc_profile lq__event_session_obj={$lq__event_session_obj} />
|
||||
{#snippet footer()}
|
||||
<button onclick={() => $events_sess.pres_mgmt.show__session_poc_profile = false} class="btn preset-tonal-warning">Close</button>
|
||||
{/snippet}
|
||||
</Modal>
|
||||
{:else}
|
||||
<span class="italic opacity-50">Not assigned</span>
|
||||
{/if}
|
||||
{/if}
|
||||
</li>
|
||||
|
||||
<!-- Description -->
|
||||
<li>
|
||||
{#if $lq__event_session_obj}
|
||||
<div class="mt-2">
|
||||
<span class="text-sm font-semibold opacity-70">Description:</span>
|
||||
{#if $lq__event_session_obj.description}
|
||||
<pre class="whitespace-pre-wrap p-3 bg-neutral-100 dark:bg-neutral-800 rounded-md mt-1 text-sm">{$lq__event_session_obj.description}</pre>
|
||||
{:else}
|
||||
<span class="italic opacity-50 ml-1">No description provided</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -53,16 +53,7 @@
|
||||
</script>
|
||||
|
||||
<section
|
||||
class="
|
||||
ae_comp event_presentation_obj_li
|
||||
border-dashed border-y-transparent border-r-transparent
|
||||
sm:border-l-red-400 md:border-l-yellow-400 lg:border-l-gray-100
|
||||
sm:dark:border-l-red-600 md:dark:border-l-yellow-600 lg:dark:border-l-gray-700
|
||||
px-0.5 py-2 space-y-2
|
||||
min-w-full
|
||||
w-full
|
||||
container overflow-x-scroll {container_class_li}
|
||||
"
|
||||
class="ae_comp event_presentation_obj_li px-0.5 py-2 space-y-2 min-w-full w-full container overflow-x-auto {container_class_li}"
|
||||
>
|
||||
<div class="float-right flex flex-row items-center">
|
||||
{#if $ae_loc.trusted_access && $ae_loc.edit_mode}
|
||||
@@ -126,9 +117,9 @@
|
||||
</h3>
|
||||
|
||||
<!-- Show presentations for this LiveQuery -->
|
||||
<ul class="space-y-4 p-4 m-2 rounded-md preset-filled-surface-400-600">
|
||||
<ul class="space-y-4">
|
||||
{#each lq__event_presentation_obj_li ?? [] as event_presentation_obj (event_presentation_obj.event_presentation_id)}
|
||||
<li class="space-y-2 border border-gray-200 p-2 rounded-md">
|
||||
<li class="space-y-3 border border-surface-200-800 bg-surface-50-900 p-4 rounded-xl shadow-sm transition-colors duration-200">
|
||||
<div class="float-right space-2 flex flex-row items-center">
|
||||
{#if $ae_loc.trusted_access && $ae_loc.edit_mode}
|
||||
<button
|
||||
@@ -169,7 +160,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<h4 class="h5 rounded-md p-2 preset-filled-surface-300-700">
|
||||
<h4 class="text-lg font-bold rounded-lg px-3 py-2 bg-surface-100-900 flex flex-wrap items-center gap-2">
|
||||
<span
|
||||
class:hidden={!event_presentation_obj.start_datetime ||
|
||||
$events_loc.pres_mgmt
|
||||
@@ -215,7 +206,7 @@
|
||||
>
|
||||
{#if (event_presentation_obj?.code || event_presentation_obj?.abstract_code) && !$events_loc.pres_mgmt.hide__presentation_code}
|
||||
<span
|
||||
class="text-sm text-gray-500 bg-yellow-100 p-1 rounded-md border border-yellow-200"
|
||||
class="text-xs preset-tonal-warning px-2 py-0.5 rounded-md leading-none"
|
||||
title="Presentation code {event_presentation_obj?.code} and abstract code {event_presentation_obj?.abstract_code}"
|
||||
>
|
||||
<span class="fas fa-barcode"></span>
|
||||
@@ -370,7 +361,7 @@
|
||||
</button>
|
||||
|
||||
<pre
|
||||
class="whitespace-pre-wrap p-2 bg-gray-100 rounded-md"
|
||||
class="whitespace-pre-wrap p-3 bg-surface-100-900 rounded-lg text-sm"
|
||||
class:hidden={$events_sess.pres_mgmt
|
||||
.show_content__presentation_description !==
|
||||
event_presentation_obj.event_presentation_id}>{event_presentation_obj.description}</pre>
|
||||
|
||||
@@ -141,9 +141,9 @@
|
||||
<tbody>
|
||||
{#each visible_session_obj_li as session_obj, index (session_obj.id || session_obj.event_session_id || session_obj.event_session_id_random || index)}
|
||||
<tr
|
||||
class="relative"
|
||||
class="relative transition-colors duration-200"
|
||||
class:opacity-50={session_obj?.hide}
|
||||
class:variant-soft-warning={!session_obj?.enable}
|
||||
class:preset-tonal-warning={!session_obj?.enable}
|
||||
>
|
||||
<td>
|
||||
{#if session_obj?.alert && $ae_loc.trusted_access}
|
||||
@@ -157,7 +157,7 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<a
|
||||
href="/events/{session_obj?.event_id}/session/{session_obj?.event_session_id}"
|
||||
class="flex flex-row gap-2 items-center font-bold text-lg hover:text-primary-500 text-left"
|
||||
class="flex flex-row gap-2 items-center font-bold text-lg hover:text-primary-500 text-left transition-colors duration-200"
|
||||
>
|
||||
{#if session_obj?.hide}
|
||||
<EyeOff
|
||||
|
||||
Reference in New Issue
Block a user