ui(badges): layout & fit-text tweaks; improve template form controls; remove badge modals from event settings; add documentation for passcode security
This commit is contained in:
@@ -342,10 +342,10 @@ let fit_heights = $derived.by(() => {
|
||||
grp_name_title: '1.6in',
|
||||
grp_name_title_flex: 'around',
|
||||
name: '1.4in',
|
||||
title: '0.4in',
|
||||
grp_aff_loc: '.4in',
|
||||
title: '0.9in',
|
||||
grp_aff_loc: '1.0in',
|
||||
grp_aff_loc_flex: 'end',
|
||||
affiliations: '0.4in',
|
||||
affiliations: '1.0in',
|
||||
location: '0.0in'
|
||||
};
|
||||
|
||||
@@ -602,19 +602,19 @@ const code_to_icon: {
|
||||
<!-- *** badge_front section start *** -->
|
||||
<section
|
||||
class="badge_front badge_type__{effective_badge_type_code.toLowerCase()}
|
||||
group relative m-0
|
||||
flex max-h-[6.0in]
|
||||
min-h-[6.0in]
|
||||
min-w-3.5
|
||||
w-[4in]
|
||||
max-w-fit
|
||||
flex-col
|
||||
items-end justify-end gap-0
|
||||
overflow-visible
|
||||
p-0
|
||||
text-center hover:outline-2 hover:outline-red-500/75
|
||||
hover:outline-dashed
|
||||
"
|
||||
group relative m-0
|
||||
flex max-h-[6.0in]
|
||||
min-h-[6.0in]
|
||||
min-w-3.5
|
||||
w-[4in]
|
||||
max-w-fit
|
||||
flex-col
|
||||
items-end justify-end gap-0
|
||||
overflow-visible
|
||||
p-0
|
||||
text-center hover:outline-2 hover:outline-red-500/75
|
||||
hover:outline-dashed
|
||||
"
|
||||
style="{bg_image_path
|
||||
? `background-image: url('${bg_image_path}'); background-size: cover; background-position: top center; background-repeat: no-repeat;`
|
||||
: ''}{demo_bg_style ? ` ${demo_bg_style}` : ''}">
|
||||
@@ -669,15 +669,17 @@ const code_to_icon: {
|
||||
|
||||
<div
|
||||
class="badge_body
|
||||
m-0
|
||||
flex grow
|
||||
flex-col
|
||||
items-center
|
||||
justify-end overflow-clip
|
||||
p-0 px-8 pb-1
|
||||
text-black
|
||||
gap-0
|
||||
"
|
||||
m-0 grow
|
||||
min-w-full w-full max-w-fit
|
||||
flex
|
||||
flex-col
|
||||
items-center
|
||||
justify-evenly overflow-clip
|
||||
mt-54
|
||||
p-0 px-8 pb-1
|
||||
text-black
|
||||
gap-0
|
||||
"
|
||||
style="{body_text_color_style}">
|
||||
<!--
|
||||
person_name container: explicit height from fit_heights so Element_fit_text
|
||||
@@ -686,12 +688,14 @@ const code_to_icon: {
|
||||
-->
|
||||
<div
|
||||
class="person_name
|
||||
m-0 flex
|
||||
flex-col
|
||||
gap-2
|
||||
overflow-hidden p-0
|
||||
hover:outline-2 hover:outline-gray-500/75 hover:outline-dashed
|
||||
"
|
||||
grow
|
||||
w-full
|
||||
m-0 flex
|
||||
flex-col items-start justify-center
|
||||
gap-2
|
||||
overflow-hidden p-0
|
||||
hover:outline-2 hover:outline-gray-500/75 hover:outline-dashed
|
||||
"
|
||||
style="height: {fit_heights.grp_name_title}; justify-content: {flex_justify(
|
||||
fit_heights.grp_name_title_flex
|
||||
)}">
|
||||
@@ -703,16 +707,23 @@ const code_to_icon: {
|
||||
max=80 (fills badge width for short names like "Bob")
|
||||
-->
|
||||
<Element_fit_text
|
||||
min={36}
|
||||
min={34}
|
||||
max={80}
|
||||
manual_size={font_size_name ?? null}
|
||||
height={fit_heights.name}
|
||||
class="full_name_override_all leading-none hover:bg-pink-100/50">
|
||||
class="full_name_override_all
|
||||
grow
|
||||
leading-none hover:bg-pink-100/50
|
||||
"
|
||||
>
|
||||
<!-- class:name_pad_short
|
||||
class:name_pad_mid
|
||||
class:name_pad_long -->
|
||||
<div
|
||||
class="full_name_override"
|
||||
class:name_pad_short
|
||||
class:name_pad_mid
|
||||
class:name_pad_long
|
||||
|
||||
style="text-align: {align_name};">
|
||||
{#if display_name}
|
||||
@@ -733,7 +744,12 @@ const code_to_icon: {
|
||||
max={38}
|
||||
manual_size={font_size_title ?? null}
|
||||
height={fit_heights.title}
|
||||
class="professional_title leading-none hover:bg-pink-100/50">
|
||||
class="professional_title
|
||||
grow
|
||||
leading-none
|
||||
hover:bg-pink-100/50
|
||||
"
|
||||
>
|
||||
<div style="text-align: {align_title};">{@html display_title}</div>
|
||||
</Element_fit_text>
|
||||
{/if}
|
||||
@@ -1285,16 +1301,16 @@ const code_to_icon: {
|
||||
* correctly regardless of badge template or font size.
|
||||
*/
|
||||
.name_pad_short {
|
||||
padding-left: 18%;
|
||||
/* padding-left: 18%; */
|
||||
padding-right: 18%;
|
||||
}
|
||||
.name_pad_mid {
|
||||
padding-left: 8%;
|
||||
padding-right: 8%;
|
||||
/* padding-left: 8%; */
|
||||
padding-right: 10%;
|
||||
}
|
||||
.name_pad_long {
|
||||
padding-left: 2%;
|
||||
padding-right: 2%;
|
||||
/* padding-left: 2%; */
|
||||
/* padding-right: 0%; */
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from 'svelte';
|
||||
import { Loader2 } from '@lucide/svelte';
|
||||
import { ChevronDown, ChevronUp, Loader2 } from '@lucide/svelte';
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||
import { ae_api } from '$lib/stores/ae_stores';
|
||||
@@ -296,12 +296,13 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
||||
<form onsubmit={prevent_default(handle_submit)} class="space-y-4 p-4">
|
||||
<h3 class="h3">{template_id ? 'Edit' : 'Create New'} Badge Template</h3>
|
||||
|
||||
<section class="border-t pt-3">
|
||||
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.general = !sections_open.general)}>
|
||||
General {sections_open.general ? '▲' : '▼'}
|
||||
<section class="border-surface-200-800 rounded-xl border">
|
||||
<button type="button" class="flex w-full items-center justify-between px-4 py-3 text-left font-semibold" onclick={() => (sections_open.general = !sections_open.general)}>
|
||||
<span>General</span>
|
||||
{#if sections_open.general}<ChevronUp size="1em" />{:else}<ChevronDown size="1em" />{/if}
|
||||
</button>
|
||||
{#if sections_open.general}
|
||||
<div class="space-y-3 pt-2">
|
||||
<div class="border-surface-200-800 space-y-3 border-t px-4 py-3">
|
||||
<label class="label">
|
||||
<span>Template Name</span>
|
||||
<input type="text" bind:value={name} class="input" required />
|
||||
@@ -319,12 +320,13 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<section class="border-t pt-3">
|
||||
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.branding = !sections_open.branding)}>
|
||||
Header & Branding {sections_open.branding ? '▲' : '▼'}
|
||||
<section class="border-surface-200-800 rounded-xl border">
|
||||
<button type="button" class="flex w-full items-center justify-between px-4 py-3 text-left font-semibold" onclick={() => (sections_open.branding = !sections_open.branding)}>
|
||||
<span>Header & Branding</span>
|
||||
{#if sections_open.branding}<ChevronUp size="1em" />{:else}<ChevronDown size="1em" />{/if}
|
||||
</button>
|
||||
{#if sections_open.branding}
|
||||
<div class="space-y-3 pt-2">
|
||||
<div class="border-surface-200-800 space-y-3 border-t px-4 py-3">
|
||||
<label class="label">
|
||||
<span>Header Path (URL) — top banner image (used when no background image)</span>
|
||||
<input type="text" bind:value={header_path} class="input" />
|
||||
@@ -349,12 +351,13 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<section class="border-t pt-3">
|
||||
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.footer = !sections_open.footer)}>
|
||||
Footer {sections_open.footer ? '▲' : '▼'}
|
||||
<section class="border-surface-200-800 rounded-xl border">
|
||||
<button type="button" class="flex w-full items-center justify-between px-4 py-3 text-left font-semibold" onclick={() => (sections_open.footer = !sections_open.footer)}>
|
||||
<span>Footer</span>
|
||||
{#if sections_open.footer}<ChevronUp size="1em" />{:else}<ChevronDown size="1em" />{/if}
|
||||
</button>
|
||||
{#if sections_open.footer}
|
||||
<div class="space-y-3 pt-2">
|
||||
<div class="border-surface-200-800 space-y-3 border-t px-4 py-3">
|
||||
<label class="label">
|
||||
<span>Footer Text (HTML allowed)</span>
|
||||
<textarea bind:value={footer_text} class="textarea" rows="2"></textarea>
|
||||
@@ -363,12 +366,13 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<section class="border-t pt-3">
|
||||
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.qr = !sections_open.qr)}>
|
||||
QR & Wireless {sections_open.qr ? '▲' : '▼'}
|
||||
<section class="border-surface-200-800 rounded-xl border">
|
||||
<button type="button" class="flex w-full items-center justify-between px-4 py-3 text-left font-semibold" onclick={() => (sections_open.qr = !sections_open.qr)}>
|
||||
<span>QR & Wireless</span>
|
||||
{#if sections_open.qr}<ChevronUp size="1em" />{:else}<ChevronDown size="1em" />{/if}
|
||||
</button>
|
||||
{#if sections_open.qr}
|
||||
<div class="space-y-3 pt-2">
|
||||
<div class="border-surface-200-800 space-y-3 border-t px-4 py-3">
|
||||
<label class="label flex items-center gap-2">
|
||||
<input type="checkbox" bind:checked={cfg_show_qr_front} class="checkbox" />
|
||||
<span>Show QR Code on Front</span>
|
||||
@@ -389,12 +393,13 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<section class="border-t pt-3">
|
||||
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.tickets = !sections_open.tickets)}>
|
||||
Tickets {sections_open.tickets ? '▲' : '▼'}
|
||||
<section class="border-surface-200-800 rounded-xl border">
|
||||
<button type="button" class="flex w-full items-center justify-between px-4 py-3 text-left font-semibold" onclick={() => (sections_open.tickets = !sections_open.tickets)}>
|
||||
<span>Tickets</span>
|
||||
{#if sections_open.tickets}<ChevronUp size="1em" />{:else}<ChevronDown size="1em" />{/if}
|
||||
</button>
|
||||
{#if sections_open.tickets}
|
||||
<div class="space-y-3 pt-2">
|
||||
<div class="border-surface-200-800 space-y-3 border-t px-4 py-3">
|
||||
<label class="label">
|
||||
<span>Ticket 1 Text (HTML allowed)</span>
|
||||
<textarea bind:value={ticket_1_text} class="textarea" rows="2"></textarea>
|
||||
@@ -411,12 +416,13 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<section class="border-t pt-3">
|
||||
<button type="button" class="text-sm text-surface-500" onclick={() => (advanced_open = !advanced_open)}>
|
||||
Advanced (cfg_json) {advanced_open ? '▲' : '▼'}
|
||||
<section class="border-surface-200-800 rounded-xl border">
|
||||
<button type="button" class="flex w-full items-center justify-between px-4 py-3 text-left font-semibold" onclick={() => (advanced_open = !advanced_open)}>
|
||||
<span>Advanced (cfg_json)</span>
|
||||
{#if advanced_open}<ChevronUp size="1em" />{:else}<ChevronDown size="1em" />{/if}
|
||||
</button>
|
||||
{#if advanced_open}
|
||||
<div class="space-y-4 pt-2">
|
||||
<div class="border-surface-200-800 space-y-4 border-t px-4 py-3">
|
||||
|
||||
<!-- Visibility -->
|
||||
<div>
|
||||
@@ -590,7 +596,7 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
||||
disabled={submit_status === 'loading'}>Cancel</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn preset-filled-primary"
|
||||
class="btn preset-filled-primary-500"
|
||||
disabled={submit_status === 'loading'}>
|
||||
{#if submit_status === 'loading'}
|
||||
<Loader2 size="1em" class="animate-spin" aria-hidden="true" />
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { goto } from '$app/navigation';
|
||||
import {
|
||||
Lock,
|
||||
Printer,
|
||||
Plus,
|
||||
Upload,
|
||||
FileText,
|
||||
BarChart2
|
||||
} from '@lucide/svelte';
|
||||
import { Lock, Printer } from '@lucide/svelte';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db_events, type Event } from '$lib/ae_events/db_events';
|
||||
import { onMount } from 'svelte';
|
||||
@@ -19,9 +12,6 @@ import AE_Comp_Editor_CodeMirror from '$lib/elements/element_editor_codemirror.s
|
||||
import Ae_comp_event_settings_form from './ae_comp__event_settings_form.svelte';
|
||||
import Ae_comp_event_settings_basic_form from './ae_comp__event_settings_basic_form.svelte';
|
||||
import Ae_comp_event_settings_abstracts_form from './ae_comp__event_settings_abstracts_form.svelte';
|
||||
import { Modal } from 'flowbite-svelte';
|
||||
import Comp_badge_create_form from '../(badges)/badges/ae_comp__badge_create_form.svelte';
|
||||
import Comp_badge_upload_form from '../(badges)/badges/ae_comp__badge_upload_form.svelte';
|
||||
|
||||
let event_id = page.params.event_id as string;
|
||||
let event_obj: Event | undefined | null = $state(null);
|
||||
@@ -38,9 +28,6 @@ let tmp_abstracts_json_str = $state('');
|
||||
let tmp_exhibits_json_str = $state('');
|
||||
let tmp_meetings_json_str = $state('');
|
||||
|
||||
let show_create_badge_modal: boolean = $state(false);
|
||||
let show_upload_badge_modal: boolean = $state(false);
|
||||
|
||||
onMount(() => {
|
||||
// Guard: administrator access required. 500ms grace delay matches the /core
|
||||
// layout pattern — allows the persisted store to hydrate before redirecting.
|
||||
@@ -130,33 +117,6 @@ async function handle_save(field_name: string, data: any) {
|
||||
<summary class="summary text-error-500 font-bold"
|
||||
>Admin Tools</summary>
|
||||
<div class="space-y-4 p-4">
|
||||
{#if (badges_loc.current.enable_add_badge_btn ?? true) || (badges_loc.current.enable_upload_badge_li_btn ?? true)}
|
||||
<div class="card rounded-md border p-4 text-center">
|
||||
<h4 class="h4">Badge Operations</h4>
|
||||
<div class="mt-2 flex flex-wrap justify-center gap-2">
|
||||
{#if badges_loc.current.enable_add_badge_btn ?? true}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
onclick={() =>
|
||||
(show_create_badge_modal = true)}>
|
||||
<Plus size="1em" aria-hidden="true" /> Add New Badge
|
||||
</button>
|
||||
{/if}
|
||||
{#if badges_loc.current.enable_upload_badge_li_btn ?? true}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary ml-2"
|
||||
onclick={() =>
|
||||
(show_upload_badge_modal = true)}>
|
||||
<Upload size="1em" aria-hidden="true" /> Upload Badge
|
||||
List
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if badges_loc.current.enable_mass_print ?? true}
|
||||
<div class="card rounded-md border p-4 text-center">
|
||||
<h4 class="h4">Mass Print Options</h4>
|
||||
@@ -182,20 +142,6 @@ async function handle_save(field_name: string, data: any) {
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="mt-4 flex flex-wrap justify-center gap-4">
|
||||
<a
|
||||
href={`/events/${event_id}/templates`}
|
||||
class="btn btn-tertiary">
|
||||
<FileText size="1em" aria-hidden="true" /> Manage Badge
|
||||
Templates
|
||||
</a>
|
||||
<a
|
||||
href={`/events/${event_id}/badges/stats`}
|
||||
class="btn btn-tertiary">
|
||||
<BarChart2 size="1em" aria-hidden="true" /> Badge Printing
|
||||
Stats
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
@@ -444,33 +390,6 @@ async function handle_save(field_name: string, data: any) {
|
||||
<p>Loading event data...</p>
|
||||
{/if}
|
||||
|
||||
{#if show_create_badge_modal}
|
||||
<Modal bind:open={show_create_badge_modal}>
|
||||
<div class="card p-4">
|
||||
<h3 class="h3">Create New Badge</h3>
|
||||
<Comp_badge_create_form
|
||||
{event_id}
|
||||
onsuccess={() => {
|
||||
show_create_badge_modal = false;
|
||||
}}
|
||||
oncancel={() => (show_create_badge_modal = false)} />
|
||||
</div>
|
||||
</Modal>
|
||||
{/if}
|
||||
|
||||
{#if show_upload_badge_modal}
|
||||
<Modal bind:open={show_upload_badge_modal}>
|
||||
<div class="card p-4">
|
||||
<h3 class="h3">Upload Badges (CSV)</h3>
|
||||
<Comp_badge_upload_form
|
||||
{event_id}
|
||||
onsuccess={() => {
|
||||
show_upload_badge_modal = false;
|
||||
}}
|
||||
oncancel={() => (show_upload_badge_modal = false)} />
|
||||
</div>
|
||||
</Modal>
|
||||
{/if}
|
||||
{:else}
|
||||
<!-- Non-administrator landed here — show a brief message while the onMount redirect fires -->
|
||||
<section
|
||||
|
||||
Reference in New Issue
Block a user