Badges: template controls cfg, collapsible form sections, navigation polish
- badge_template_form: fix default field visibility (location off render, pronouns/leads excluded from controls); fix duplicate QR checkboxes by removing orphan show_qr_front/back state vars; reorganize Advanced cfg_json into labeled sub-groups; make all 5 non-Advanced sections collapsible (general starts open, rest collapsed) - print_controls: add DEFAULT_SHOWN constant so field_shown() uses explicit whitelist fallback instead of showing all fields when no controls_cfg is set - badges config +page: add Templates navigation button in header (FileText icon) - templates +page: add back-nav header with ArrowLeft to badges/config, Settings icon, page title Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -153,11 +153,16 @@ const DEFAULT_AUTH_EDITABLE = [
|
|||||||
'pronouns'
|
'pronouns'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Default shown fields in the controls panel when the template has no explicit controls_cfg.
|
||||||
|
// Pronouns and lead scanning are off by default — most events don't expose them.
|
||||||
|
// WHY: prevents clutter for attendees at the badge table; events that need them must opt in via template config.
|
||||||
|
const DEFAULT_SHOWN = ['name', 'title', 'affiliations', 'location'];
|
||||||
|
|
||||||
/** Is this field card shown in the panel at all? trusted+edit always sees all fields. */
|
/** Is this field card shown in the panel at all? trusted+edit always sees all fields. */
|
||||||
function field_shown(field: string): boolean {
|
function field_shown(field: string): boolean {
|
||||||
if (is_trusted && is_global_edit_mode) return true;
|
if (is_trusted && is_global_edit_mode) return true;
|
||||||
const cfg = template_controls_cfg;
|
const cfg = template_controls_cfg;
|
||||||
if (!cfg?.shown) return true;
|
if (!cfg?.shown) return DEFAULT_SHOWN.includes(field);
|
||||||
return cfg.shown.includes(field);
|
return cfg.shown.includes(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
Check,
|
Check,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ChevronUp,
|
ChevronUp,
|
||||||
|
FileText,
|
||||||
Lock,
|
Lock,
|
||||||
Save,
|
Save,
|
||||||
Settings
|
Settings
|
||||||
@@ -270,6 +271,11 @@ function toggle(key: string) {
|
|||||||
<Settings size="1.2em" class="text-primary-500" />
|
<Settings size="1.2em" class="text-primary-500" />
|
||||||
<h1 class="text-xl font-bold">Badges Config</h1>
|
<h1 class="text-xl font-bold">Badges Config</h1>
|
||||||
</div>
|
</div>
|
||||||
|
<a href="/events/{event_id}/templates"
|
||||||
|
class="btn btn-sm preset-tonal-surface"
|
||||||
|
title="Manage Badge Templates">
|
||||||
|
<FileText size="1em" class="mr-1" /> Templates
|
||||||
|
</a>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
{#if save_status === 'success'}
|
{#if save_status === 'success'}
|
||||||
<span class="badge preset-tonal-success flex items-center gap-1">
|
<span class="badge preset-tonal-success flex items-center gap-1">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { liveQuery } from 'dexie';
|
import { liveQuery } from 'dexie';
|
||||||
import { Pencil, Plus, Trash2 } from '@lucide/svelte';
|
import { ArrowLeft, Pencil, Plus, Settings, Trash2 } from '@lucide/svelte';
|
||||||
import { events_func } from '$lib/ae_events/ae_events_functions';
|
import { events_func } from '$lib/ae_events/ae_events_functions';
|
||||||
import { ae_api } from '$lib/stores/ae_stores';
|
import { ae_api } from '$lib/stores/ae_stores';
|
||||||
import { Modal } from 'flowbite-svelte';
|
import { Modal } from 'flowbite-svelte';
|
||||||
@@ -78,16 +78,23 @@ async function delete_template(template_id: string) {
|
|||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<section class="p-4">
|
<section class="p-4">
|
||||||
<h1 class="h1">Badge Templates</h1>
|
<header class="mb-4 flex items-center justify-between gap-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
<div class="my-4 flex justify-end">
|
<a href="/events/{event_id}/badges/config"
|
||||||
|
class="btn btn-sm preset-tonal-surface"
|
||||||
|
title="Back to Badges Config">
|
||||||
|
<ArrowLeft size="1em" />
|
||||||
|
</a>
|
||||||
|
<Settings size="1.2em" class="text-primary-500" />
|
||||||
|
<h1 class="text-xl font-bold">Badge Templates</h1>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
onclick={() => (show_create_template_modal = true)}>
|
onclick={() => (show_create_template_modal = true)}>
|
||||||
<Plus size="1em" class="mr-2" /> Add New Template
|
<Plus size="1em" class="mr-2" /> Add New Template
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</header>
|
||||||
|
|
||||||
{#if $lq__badge_templates}
|
{#if $lq__badge_templates}
|
||||||
{#if $lq__badge_templates.length > 0}
|
{#if $lq__badge_templates.length > 0}
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ let header_row_1 = $state('');
|
|||||||
let header_row_2 = $state('');
|
let header_row_2 = $state('');
|
||||||
let secondary_header_path = $state('');
|
let secondary_header_path = $state('');
|
||||||
let footer_text = $state('');
|
let footer_text = $state('');
|
||||||
let show_qr_front = $state(true);
|
// show_qr_front / show_qr_back: removed — UI now binds directly to cfg_show_qr_front/cfg_show_qr_back
|
||||||
let show_qr_back = $state(true);
|
|
||||||
let wireless_ssid = $state('');
|
let wireless_ssid = $state('');
|
||||||
let wireless_password = $state('');
|
let wireless_password = $state('');
|
||||||
let ticket_1_text = $state('');
|
let ticket_1_text = $state('');
|
||||||
@@ -56,10 +55,11 @@ let cfg_show_qr_back = $state(true);
|
|||||||
// Per-field hide toggles
|
// Per-field hide toggles
|
||||||
let cfg_hide_title = $state(false);
|
let cfg_hide_title = $state(false);
|
||||||
let cfg_hide_affiliations = $state(false);
|
let cfg_hide_affiliations = $state(false);
|
||||||
let cfg_hide_location = $state(false);
|
let cfg_hide_location = $state(true);
|
||||||
// Controls menu config (per-template) — which fields the controls panel shows
|
// Controls menu config (per-template) — which fields the controls panel shows
|
||||||
// and which fields authenticated users may edit. Stored under cfg_json.controls_cfg
|
// and which fields authenticated users may edit. Stored under cfg_json.controls_cfg
|
||||||
let cfg_controls_shown: string[] = $state([]);
|
// Defaults match DEFAULT_SHOWN in ae_comp__badge_print_controls.svelte (pronouns/leads off by default).
|
||||||
|
let cfg_controls_shown: string[] = $state(['name', 'title', 'affiliations', 'location']);
|
||||||
let cfg_controls_auth_editable: string[] = $state([]);
|
let cfg_controls_auth_editable: string[] = $state([]);
|
||||||
// Body text color (hex)
|
// Body text color (hex)
|
||||||
let cfg_body_text_color = $state('#000000');
|
let cfg_body_text_color = $state('#000000');
|
||||||
@@ -73,6 +73,15 @@ let cfg_qr_alignment_back = $state('center');
|
|||||||
|
|
||||||
let submit_status = $state('idle'); // idle, loading, success, error
|
let submit_status = $state('idle'); // idle, loading, success, error
|
||||||
|
|
||||||
|
// Section collapse state — General open by default (required name field); rest closed.
|
||||||
|
let sections_open = $state({
|
||||||
|
general: true,
|
||||||
|
branding: false,
|
||||||
|
footer: false,
|
||||||
|
qr: false,
|
||||||
|
tickets: false
|
||||||
|
});
|
||||||
|
|
||||||
// Load template data if in edit mode
|
// Load template data if in edit mode
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (template_id) {
|
if (template_id) {
|
||||||
@@ -155,10 +164,6 @@ async function load_template(id: string) {
|
|||||||
cfg_qr_alignment_front = parsed_cfg?.qr_alignment?.front ?? parsed_cfg.qr_alignment_front ?? 'center';
|
cfg_qr_alignment_front = parsed_cfg?.qr_alignment?.front ?? parsed_cfg.qr_alignment_front ?? 'center';
|
||||||
cfg_qr_alignment_back = parsed_cfg?.qr_alignment?.back ?? parsed_cfg.qr_alignment_back ?? 'center';
|
cfg_qr_alignment_back = parsed_cfg?.qr_alignment?.back ?? parsed_cfg.qr_alignment_back ?? 'center';
|
||||||
|
|
||||||
// Keep top-level fields in sync for backward compatibility
|
|
||||||
show_qr_front = cfg_show_qr_front;
|
|
||||||
show_qr_back = cfg_show_qr_back;
|
|
||||||
|
|
||||||
submit_status = 'idle';
|
submit_status = 'idle';
|
||||||
} else {
|
} else {
|
||||||
submit_status = 'error';
|
submit_status = 'error';
|
||||||
@@ -291,94 +296,119 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
|||||||
<form onsubmit={prevent_default(handle_submit)} class="space-y-4 p-4">
|
<form onsubmit={prevent_default(handle_submit)} class="space-y-4 p-4">
|
||||||
<h3 class="h3">{template_id ? 'Edit' : 'Create New'} Badge Template</h3>
|
<h3 class="h3">{template_id ? 'Edit' : 'Create New'} Badge Template</h3>
|
||||||
|
|
||||||
<section class="space-y-3">
|
<section class="border-t pt-3">
|
||||||
<h4 class="font-semibold">General</h4>
|
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.general = !sections_open.general)}>
|
||||||
<label class="label">
|
General {sections_open.general ? '▲' : '▼'}
|
||||||
<span>Template Name</span>
|
</button>
|
||||||
<input type="text" bind:value={name} class="input" required />
|
{#if sections_open.general}
|
||||||
</label>
|
<div class="space-y-3 pt-2">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Background Image Path (URL) — full-badge background, replaces header</span>
|
<span>Template Name</span>
|
||||||
<input type="text" bind:value={background_image_path} class="input" />
|
<input type="text" bind:value={name} class="input" required />
|
||||||
</label>
|
</label>
|
||||||
{#if background_image_path}
|
<label class="label">
|
||||||
<p class="text-xs text-amber-600 dark:text-amber-400">
|
<span>Background Image Path (URL) — full-badge background, replaces header</span>
|
||||||
⚠ When a background image is set, the header path and logo/text header are hidden on the badge front — the background image covers the full badge.
|
<input type="text" bind:value={background_image_path} class="input" />
|
||||||
</p>
|
</label>
|
||||||
|
{#if background_image_path}
|
||||||
|
<p class="text-xs text-amber-600 dark:text-amber-400">
|
||||||
|
⚠ When a background image is set, the header path and logo/text header are hidden on the badge front — the background image covers the full badge.
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="space-y-3">
|
<section class="border-t pt-3">
|
||||||
<h4 class="font-semibold">Header & Branding</h4>
|
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.branding = !sections_open.branding)}>
|
||||||
<label class="label">
|
Header & Branding {sections_open.branding ? '▲' : '▼'}
|
||||||
<span>Header Path (URL) — top banner image (used when no background image)</span>
|
</button>
|
||||||
<input type="text" bind:value={header_path} class="input" />
|
{#if sections_open.branding}
|
||||||
</label>
|
<div class="space-y-3 pt-2">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Logo Path (URL, if no Header Path)</span>
|
<span>Header Path (URL) — top banner image (used when no background image)</span>
|
||||||
<input type="text" bind:value={logo_path} class="input" />
|
<input type="text" bind:value={header_path} class="input" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Header Row 1 Text (HTML allowed)</span>
|
<span>Logo Path (URL, if no Header Path)</span>
|
||||||
<textarea bind:value={header_row_1} class="textarea" rows="2"
|
<input type="text" bind:value={logo_path} class="input" />
|
||||||
></textarea>
|
</label>
|
||||||
</label>
|
<label class="label">
|
||||||
<label class="label">
|
<span>Header Row 1 Text (HTML allowed)</span>
|
||||||
<span>Header Row 2 Text (HTML allowed)</span>
|
<textarea bind:value={header_row_1} class="textarea" rows="2"></textarea>
|
||||||
<textarea bind:value={header_row_2} class="textarea" rows="2"
|
</label>
|
||||||
></textarea>
|
<label class="label">
|
||||||
</label>
|
<span>Header Row 2 Text (HTML allowed)</span>
|
||||||
<label class="label">
|
<textarea bind:value={header_row_2} class="textarea" rows="2"></textarea>
|
||||||
<span>Secondary Header Path (URL, back of badge)</span>
|
</label>
|
||||||
<input type="text" bind:value={secondary_header_path} class="input" />
|
<label class="label">
|
||||||
</label>
|
<span>Secondary Header Path (URL, back of badge)</span>
|
||||||
|
<input type="text" bind:value={secondary_header_path} class="input" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="space-y-3">
|
<section class="border-t pt-3">
|
||||||
<h4 class="font-semibold">Footer</h4>
|
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.footer = !sections_open.footer)}>
|
||||||
<label class="label">
|
Footer {sections_open.footer ? '▲' : '▼'}
|
||||||
<span>Footer Text (HTML allowed)</span>
|
</button>
|
||||||
<textarea bind:value={footer_text} class="textarea" rows="2"></textarea>
|
{#if sections_open.footer}
|
||||||
</label>
|
<div class="space-y-3 pt-2">
|
||||||
|
<label class="label">
|
||||||
|
<span>Footer Text (HTML allowed)</span>
|
||||||
|
<textarea bind:value={footer_text} class="textarea" rows="2"></textarea>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="space-y-3">
|
<section class="border-t pt-3">
|
||||||
<h4 class="font-semibold">QR & Wireless</h4>
|
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.qr = !sections_open.qr)}>
|
||||||
<label class="label flex items-center gap-2">
|
QR & Wireless {sections_open.qr ? '▲' : '▼'}
|
||||||
<input type="checkbox" bind:checked={show_qr_front} class="checkbox" />
|
</button>
|
||||||
<span>Show QR Code on Front</span>
|
{#if sections_open.qr}
|
||||||
</label>
|
<div class="space-y-3 pt-2">
|
||||||
<label class="label flex items-center gap-2">
|
<label class="label flex items-center gap-2">
|
||||||
<input type="checkbox" bind:checked={show_qr_back} class="checkbox" />
|
<input type="checkbox" bind:checked={cfg_show_qr_front} class="checkbox" />
|
||||||
<span>Show QR Code on Back</span>
|
<span>Show QR Code on Front</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label flex items-center gap-2">
|
||||||
<span>Wireless SSID</span>
|
<input type="checkbox" bind:checked={cfg_show_qr_back} class="checkbox" />
|
||||||
<input type="text" bind:value={wireless_ssid} class="input" />
|
<span>Show QR Code on Back</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Wireless Password</span>
|
<span>Wireless SSID</span>
|
||||||
<input type="text" bind:value={wireless_password} class="input" />
|
<input type="text" bind:value={wireless_ssid} class="input" />
|
||||||
</label>
|
</label>
|
||||||
|
<label class="label">
|
||||||
|
<span>Wireless Password</span>
|
||||||
|
<input type="text" bind:value={wireless_password} class="input" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="space-y-3">
|
<section class="border-t pt-3">
|
||||||
<h4 class="font-semibold">Tickets</h4>
|
<button type="button" class="text-sm text-surface-500" onclick={() => (sections_open.tickets = !sections_open.tickets)}>
|
||||||
<label class="label">
|
Tickets {sections_open.tickets ? '▲' : '▼'}
|
||||||
<span>Ticket 1 Text (HTML allowed)</span>
|
</button>
|
||||||
<textarea bind:value={ticket_1_text} class="textarea" rows="2"
|
{#if sections_open.tickets}
|
||||||
></textarea>
|
<div class="space-y-3 pt-2">
|
||||||
</label>
|
<label class="label">
|
||||||
<label class="label">
|
<span>Ticket 1 Text (HTML allowed)</span>
|
||||||
<span>Ticket 2 Text (HTML allowed)</span>
|
<textarea bind:value={ticket_1_text} class="textarea" rows="2"></textarea>
|
||||||
<textarea bind:value={ticket_2_text} class="textarea" rows="2"
|
</label>
|
||||||
></textarea>
|
<label class="label">
|
||||||
</label>
|
<span>Ticket 2 Text (HTML allowed)</span>
|
||||||
<label class="label">
|
<textarea bind:value={ticket_2_text} class="textarea" rows="2"></textarea>
|
||||||
<span>Ticket 3 Text (HTML allowed)</span>
|
</label>
|
||||||
<textarea bind:value={ticket_3_text} class="textarea" rows="2"
|
<label class="label">
|
||||||
></textarea>
|
<span>Ticket 3 Text (HTML allowed)</span>
|
||||||
</label>
|
<textarea bind:value={ticket_3_text} class="textarea" rows="2"></textarea>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="border-t pt-3">
|
<section class="border-t pt-3">
|
||||||
@@ -386,90 +416,99 @@ function toggle_cfg_controls_auth_editable(key: string) {
|
|||||||
Advanced (cfg_json) {advanced_open ? '▲' : '▼'}
|
Advanced (cfg_json) {advanced_open ? '▲' : '▼'}
|
||||||
</button>
|
</button>
|
||||||
{#if advanced_open}
|
{#if advanced_open}
|
||||||
<div class="grid grid-cols-1 gap-2 pt-2">
|
<div class="space-y-4 pt-2">
|
||||||
<label class="label flex items-center gap-2">
|
|
||||||
<input type="checkbox" bind:checked={cfg_hide_badge_header} class="checkbox" />
|
<!-- Visibility -->
|
||||||
<span>Hide badge header</span>
|
<div>
|
||||||
</label>
|
<p class="text-xs font-semibold text-surface-500 uppercase tracking-wide mb-1">Visibility</p>
|
||||||
<label class="label flex items-center gap-2">
|
<div class="grid grid-cols-2 gap-2">
|
||||||
<input type="checkbox" bind:checked={cfg_hide_badge_footer} class="checkbox" />
|
<label class="label flex items-center gap-2">
|
||||||
<span>Hide badge footer</span>
|
<input type="checkbox" bind:checked={cfg_hide_badge_header} class="checkbox" />
|
||||||
</label>
|
<span>Hide badge header</span>
|
||||||
<label class="label flex items-center gap-2">
|
</label>
|
||||||
<input type="checkbox" bind:checked={cfg_show_qr_front} class="checkbox" />
|
<label class="label flex items-center gap-2">
|
||||||
<span>Show QR on Front (cfg_json)</span>
|
<input type="checkbox" bind:checked={cfg_hide_badge_footer} class="checkbox" />
|
||||||
</label>
|
<span>Hide badge footer</span>
|
||||||
<label class="label flex items-center gap-2">
|
</label>
|
||||||
<input type="checkbox" bind:checked={cfg_show_qr_back} class="checkbox" />
|
<label class="label flex items-center gap-2">
|
||||||
<span>Show QR on Back (cfg_json)</span>
|
<input type="checkbox" bind:checked={cfg_hide_title} class="checkbox" />
|
||||||
</label>
|
<span>Hide Title</span>
|
||||||
<div class="grid grid-cols-2 gap-2">
|
</label>
|
||||||
<label class="label flex items-center gap-2">
|
<label class="label flex items-center gap-2">
|
||||||
<input type="checkbox" bind:checked={cfg_hide_title} class="checkbox" />
|
<input type="checkbox" bind:checked={cfg_hide_affiliations} class="checkbox" />
|
||||||
<span>Hide Title</span>
|
<span>Hide Affiliations</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="label flex items-center gap-2">
|
<label class="label flex items-center gap-2">
|
||||||
<input type="checkbox" bind:checked={cfg_hide_affiliations} class="checkbox" />
|
<input type="checkbox" bind:checked={cfg_hide_location} class="checkbox" />
|
||||||
<span>Hide Affiliations</span>
|
<span>Hide Location</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="label flex items-center gap-2">
|
</div>
|
||||||
<input type="checkbox" bind:checked={cfg_hide_location} class="checkbox" />
|
</div>
|
||||||
<span>Hide Location</span>
|
|
||||||
</label>
|
<!-- Alignment -->
|
||||||
<label class="label">
|
<div>
|
||||||
<span>Name Alignment</span>
|
<p class="text-xs font-semibold text-surface-500 uppercase tracking-wide mb-1">Alignment</p>
|
||||||
<select bind:value={cfg_align_name} class="input">
|
<div class="grid grid-cols-2 gap-2">
|
||||||
<option value="left">Left</option>
|
<label class="label">
|
||||||
<option value="center">Center</option>
|
<span>Name</span>
|
||||||
<option value="right">Right</option>
|
<select bind:value={cfg_align_name} class="input">
|
||||||
<option value="justify">Justify</option>
|
<option value="left">Left</option>
|
||||||
</select>
|
<option value="center">Center</option>
|
||||||
</label>
|
<option value="right">Right</option>
|
||||||
<label class="label">
|
<option value="justify">Justify</option>
|
||||||
<span>Title Alignment</span>
|
</select>
|
||||||
<select bind:value={cfg_align_title} class="input">
|
</label>
|
||||||
<option value="left">Left</option>
|
<label class="label">
|
||||||
<option value="center">Center</option>
|
<span>Title</span>
|
||||||
<option value="right">Right</option>
|
<select bind:value={cfg_align_title} class="input">
|
||||||
<option value="justify">Justify</option>
|
<option value="left">Left</option>
|
||||||
</select>
|
<option value="center">Center</option>
|
||||||
</label>
|
<option value="right">Right</option>
|
||||||
<label class="label">
|
<option value="justify">Justify</option>
|
||||||
<span>Affiliations Alignment</span>
|
</select>
|
||||||
<select bind:value={cfg_align_affiliations} class="input">
|
</label>
|
||||||
<option value="left">Left</option>
|
<label class="label">
|
||||||
<option value="center">Center</option>
|
<span>Affiliations</span>
|
||||||
<option value="right">Right</option>
|
<select bind:value={cfg_align_affiliations} class="input">
|
||||||
<option value="justify">Justify</option>
|
<option value="left">Left</option>
|
||||||
</select>
|
<option value="center">Center</option>
|
||||||
</label>
|
<option value="right">Right</option>
|
||||||
<label class="label">
|
<option value="justify">Justify</option>
|
||||||
<span>Location Alignment</span>
|
</select>
|
||||||
<select bind:value={cfg_align_location} class="input">
|
</label>
|
||||||
<option value="left">Left</option>
|
<label class="label">
|
||||||
<option value="center">Center</option>
|
<span>Location</span>
|
||||||
<option value="right">Right</option>
|
<select bind:value={cfg_align_location} class="input">
|
||||||
<option value="justify">Justify</option>
|
<option value="left">Left</option>
|
||||||
</select>
|
<option value="center">Center</option>
|
||||||
</label>
|
<option value="right">Right</option>
|
||||||
<label class="label">
|
<option value="justify">Justify</option>
|
||||||
<span>QR Alignment (Front)</span>
|
</select>
|
||||||
<select bind:value={cfg_qr_alignment_front} class="input">
|
</label>
|
||||||
<option value="left">Left</option>
|
<label class="label">
|
||||||
<option value="center">Center</option>
|
<span>QR (Front)</span>
|
||||||
<option value="right">Right</option>
|
<select bind:value={cfg_qr_alignment_front} class="input">
|
||||||
<option value="justify">Justify</option>
|
<option value="left">Left</option>
|
||||||
</select>
|
<option value="center">Center</option>
|
||||||
</label>
|
<option value="right">Right</option>
|
||||||
<label class="label">
|
<option value="justify">Justify</option>
|
||||||
<span>QR Alignment (Back)</span>
|
</select>
|
||||||
<select bind:value={cfg_qr_alignment_back} class="input">
|
</label>
|
||||||
<option value="left">Left</option>
|
<label class="label">
|
||||||
<option value="center">Center</option>
|
<span>QR (Back)</span>
|
||||||
<option value="right">Right</option>
|
<select bind:value={cfg_qr_alignment_back} class="input">
|
||||||
<option value="justify">Justify</option>
|
<option value="left">Left</option>
|
||||||
</select>
|
<option value="center">Center</option>
|
||||||
</label>
|
<option value="right">Right</option>
|
||||||
|
<option value="justify">Justify</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Appearance -->
|
||||||
|
<div>
|
||||||
|
<p class="text-xs font-semibold text-surface-500 uppercase tracking-wide mb-1">Appearance</p>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Body Text Color (hex)</span>
|
<span>Body Text Color (hex)</span>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user