feat(badges): add print font size controls

- Add optional font_size_{name,title,affiliations,location} px props to
  ae_comp__badge_obj_view; when set, replaces auto inch-based sizing with
  an inline style so the caller controls the value
- Add screen-only (print:hidden) font size control panel to print page:
  four [−] [value] [+] [↺] rows, step 2px, null = auto (default)
  First + click activates at a sensible default that approximates the
  auto-sized inch values; ↺ button resets back to auto mode

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-02-27 18:49:58 -05:00
parent 011fc19a77
commit 3d7279da4c
2 changed files with 134 additions and 4 deletions

View File

@@ -7,6 +7,14 @@
update_status?: string;
update_complete?: boolean;
is_review_mode?: boolean;
/** Optional px override for name font size. When provided, replaces auto-sizing. */
font_size_name?: number;
/** Optional px override for professional title font size. */
font_size_title?: number;
/** Optional px override for affiliations font size. */
font_size_affiliations?: number;
/** Optional px override for location font size. */
font_size_location?: number;
log_lvl?: number;
}
@@ -18,6 +26,10 @@
update_status = $bindable('idle'),
update_complete = $bindable(true),
is_review_mode = false,
font_size_name = undefined,
font_size_title = undefined,
font_size_affiliations = undefined,
font_size_location = undefined,
log_lvl = 0
}: Props = $props();
@@ -803,7 +815,8 @@ onkeypress={() => {
<!-- Examples: mSC-tTzL_OA, QLddtYl8sfo -->
<div
class="full_name_override_all {full_name_class_size} leading-none"
class="full_name_override_all {font_size_name ? '' : full_name_class_size} leading-none"
style={font_size_name ? `font-size: ${font_size_name}px` : ''}
>
<!-- <span class="float-right text-sm italic m-2">
{longest_full_name_override_part}&times; char
@@ -828,9 +841,10 @@ onkeypress={() => {
{#if editable_professional_title_override || edit_mode_active}
<div
class="professional_title
{professional_title_class_size} leading-none
{font_size_title ? '' : professional_title_class_size} leading-none
italic
"
style={font_size_title ? `font-size: ${font_size_title}px` : ''}
>
{#if edit_mode_active}
<input
@@ -858,8 +872,9 @@ onkeypress={() => {
{#if editable_affiliations_override || edit_mode_active}
<div
class="affiliations
{affiliations_class_size} leading-none
{font_size_affiliations ? '' : affiliations_class_size} leading-none
"
style={font_size_affiliations ? `font-size: ${font_size_affiliations}px` : ''}
>
{#if edit_mode_active}
<textarea
@@ -878,8 +893,9 @@ onkeypress={() => {
{#if editable_location_override || edit_mode_active}
<div
class="location
{location_class_size} leading-none
{font_size_location ? '' : location_class_size} leading-none
"
style={font_size_location ? `font-size: ${font_size_location}px` : ''}
>
{#if edit_mode_active}
<input

View File

@@ -81,6 +81,39 @@
// Print mode: display only — ae_comp__badge_obj_view handles print count + window.print()
// The "Print Now" header button below only triggers window.print() for convenience;
// print count is incremented by the print button inside ae_comp__badge_obj_view.
// *** Font size overrides (screen-only, null = auto-sizing from badge view)
// Values are in px. Auto-sizing uses inch-based Tailwind classes in ae_comp__badge_obj_view.
// Reasonable defaults when first activated correspond roughly to the auto-sized inch values.
let font_size_name: number | null = $state(null);
let font_size_title: number | null = $state(null);
let font_size_affiliations: number | null = $state(null);
let font_size_location: number | null = $state(null);
const FONT_SIZE_DEFAULTS = { name: 58, title: 34, affiliations: 38, location: 34 };
const FONT_SIZE_MIN = { name: 20, title: 14, affiliations: 14, location: 14 };
const FONT_SIZE_MAX = { name: 80, title: 56, affiliations: 60, location: 56 };
const FONT_SIZE_STEP = 2;
function font_size_adjust(which: 'name' | 'title' | 'affiliations' | 'location', delta: number) {
if (which === 'name') {
font_size_name = font_size_name === null
? FONT_SIZE_DEFAULTS.name
: Math.max(FONT_SIZE_MIN.name, Math.min(FONT_SIZE_MAX.name, font_size_name + delta));
} else if (which === 'title') {
font_size_title = font_size_title === null
? FONT_SIZE_DEFAULTS.title
: Math.max(FONT_SIZE_MIN.title, Math.min(FONT_SIZE_MAX.title, font_size_title + delta));
} else if (which === 'affiliations') {
font_size_affiliations = font_size_affiliations === null
? FONT_SIZE_DEFAULTS.affiliations
: Math.max(FONT_SIZE_MIN.affiliations, Math.min(FONT_SIZE_MAX.affiliations, font_size_affiliations + delta));
} else if (which === 'location') {
font_size_location = font_size_location === null
? FONT_SIZE_DEFAULTS.location
: Math.max(FONT_SIZE_MIN.location, Math.min(FONT_SIZE_MAX.location, font_size_location + delta));
}
}
</script>
<svelte:head>
@@ -169,6 +202,83 @@
</div>
</header>
<!-- Font size controls: screen-only, hidden when browser prints -->
<div class="print:hidden flex flex-row flex-wrap gap-x-6 gap-y-2 items-center justify-start py-2 px-3 mb-3 bg-gray-50 dark:bg-gray-900 rounded border border-gray-200 dark:border-gray-700 text-sm">
<span class="text-xs font-semibold text-gray-400 uppercase tracking-wide shrink-0">Font Size:</span>
<!-- Name -->
<div class="flex items-center gap-1.5">
<span class="text-xs text-gray-500 w-16">Name</span>
<button type="button" class="btn btn-sm px-2 py-0 min-h-0 h-6 leading-none"
onclick={() => font_size_adjust('name', -FONT_SIZE_STEP)}
disabled={font_size_name !== null && font_size_name <= FONT_SIZE_MIN.name}
></button>
<span class="font-mono text-xs w-12 text-center">{font_size_name !== null ? `${font_size_name}px` : 'Auto'}</span>
<button type="button" class="btn btn-sm px-2 py-0 min-h-0 h-6 leading-none"
onclick={() => font_size_adjust('name', FONT_SIZE_STEP)}
disabled={font_size_name !== null && font_size_name >= FONT_SIZE_MAX.name}
>+</button>
{#if font_size_name !== null}
<button type="button" class="btn btn-sm px-1.5 py-0 min-h-0 h-6 leading-none text-xs opacity-60"
onclick={() => (font_size_name = null)} title="Reset to auto"></button>
{/if}
</div>
<!-- Title -->
<div class="flex items-center gap-1.5">
<span class="text-xs text-gray-500 w-16">Title</span>
<button type="button" class="btn btn-sm px-2 py-0 min-h-0 h-6 leading-none"
onclick={() => font_size_adjust('title', -FONT_SIZE_STEP)}
disabled={font_size_title !== null && font_size_title <= FONT_SIZE_MIN.title}
></button>
<span class="font-mono text-xs w-12 text-center">{font_size_title !== null ? `${font_size_title}px` : 'Auto'}</span>
<button type="button" class="btn btn-sm px-2 py-0 min-h-0 h-6 leading-none"
onclick={() => font_size_adjust('title', FONT_SIZE_STEP)}
disabled={font_size_title !== null && font_size_title >= FONT_SIZE_MAX.title}
>+</button>
{#if font_size_title !== null}
<button type="button" class="btn btn-sm px-1.5 py-0 min-h-0 h-6 leading-none text-xs opacity-60"
onclick={() => (font_size_title = null)} title="Reset to auto"></button>
{/if}
</div>
<!-- Affiliations -->
<div class="flex items-center gap-1.5">
<span class="text-xs text-gray-500 w-16">Affil.</span>
<button type="button" class="btn btn-sm px-2 py-0 min-h-0 h-6 leading-none"
onclick={() => font_size_adjust('affiliations', -FONT_SIZE_STEP)}
disabled={font_size_affiliations !== null && font_size_affiliations <= FONT_SIZE_MIN.affiliations}
></button>
<span class="font-mono text-xs w-12 text-center">{font_size_affiliations !== null ? `${font_size_affiliations}px` : 'Auto'}</span>
<button type="button" class="btn btn-sm px-2 py-0 min-h-0 h-6 leading-none"
onclick={() => font_size_adjust('affiliations', FONT_SIZE_STEP)}
disabled={font_size_affiliations !== null && font_size_affiliations >= FONT_SIZE_MAX.affiliations}
>+</button>
{#if font_size_affiliations !== null}
<button type="button" class="btn btn-sm px-1.5 py-0 min-h-0 h-6 leading-none text-xs opacity-60"
onclick={() => (font_size_affiliations = null)} title="Reset to auto"></button>
{/if}
</div>
<!-- Location -->
<div class="flex items-center gap-1.5">
<span class="text-xs text-gray-500 w-16">Location</span>
<button type="button" class="btn btn-sm px-2 py-0 min-h-0 h-6 leading-none"
onclick={() => font_size_adjust('location', -FONT_SIZE_STEP)}
disabled={font_size_location !== null && font_size_location <= FONT_SIZE_MIN.location}
></button>
<span class="font-mono text-xs w-12 text-center">{font_size_location !== null ? `${font_size_location}px` : 'Auto'}</span>
<button type="button" class="btn btn-sm px-2 py-0 min-h-0 h-6 leading-none"
onclick={() => font_size_adjust('location', FONT_SIZE_STEP)}
disabled={font_size_location !== null && font_size_location >= FONT_SIZE_MAX.location}
>+</button>
{#if font_size_location !== null}
<button type="button" class="btn btn-sm px-1.5 py-0 min-h-0 h-6 leading-none text-xs opacity-60"
onclick={() => (font_size_location = null)} title="Reset to auto"></button>
{/if}
</div>
</div>
<!-- Badge render — ae_comp__badge_obj_view handles print count + window.print() -->
<Comp_badge_obj_view
event_id={$lq__event_badge_obj.event_id as string}
@@ -176,6 +286,10 @@
{lq__event_badge_obj}
{lq__event_badge_template_obj}
is_review_mode={false}
font_size_name={font_size_name ?? undefined}
font_size_title={font_size_title ?? undefined}
font_size_affiliations={font_size_affiliations ?? undefined}
font_size_location={font_size_location ?? undefined}
/>
{:else if is_loading_idb || !event_badge_id}