feat(badges): add demo background pattern toggle in edit mode

Adds a 🎨 button to the badge debug bar (edit-mode only) that cycles
through 5 SVG background patterns keyed by badge type color palette:
stripes, dots, diamonds, grid, swirls.

Swirl tile is 64×64 with corner-to-corner cubic bezier S-curves so
edges align seamlessly when tiled. Off by default; never prints.
This commit is contained in:
Scott Idem
2026-03-12 19:23:21 -04:00
parent c867795f4d
commit cfa9e85d05

View File

@@ -223,6 +223,45 @@
let qr_data_url: any = $state('');
let qr_error_message = $state('');
// --- Demo background pattern (edit mode only, for preview/demo purposes) ---
// 0 = off, 14 = pattern variants. Cycles on each button click.
let demo_bg_state = $state(0);
const DEMO_BG_PATTERNS = 5;
function cycle_demo_bg() {
demo_bg_state = (demo_bg_state + 1) % (DEMO_BG_PATTERNS + 1);
}
let demo_bg_style = $derived.by(() => {
if (demo_bg_state === 0) return '';
// Colors keyed by badge type code — bg tint + accent
const palettes: Record<string, [string, string]> = {
member: ['#dbeafe', '#3b82f6'],
staff: ['#dcfce7', '#16a34a'],
guest: ['#f3e8ff', '#9333ea'],
exhibitor: ['#ffedd5', '#ea580c'],
'non-member': ['#fce7f3', '#db2777'],
test: ['#fef9c3', '#ca8a04'],
};
const [bg, fg] = palettes[effective_badge_type_code?.toLowerCase() ?? ''] ?? ['#f1f5f9', '#64748b'];
// Each entry: [svg string, tile size]. Swirls use a larger tile for smoother repeats.
const patterns: [string, string][] = [
// 1: diagonal stripes
[`<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><rect width='24' height='24' fill='${bg}'/><line x1='0' y1='24' x2='24' y2='0' stroke='${fg}' stroke-width='1.5' stroke-opacity='0.5'/><line x1='-12' y1='24' x2='12' y2='0' stroke='${fg}' stroke-width='1.5' stroke-opacity='0.5'/><line x1='12' y1='24' x2='36' y2='0' stroke='${fg}' stroke-width='1.5' stroke-opacity='0.5'/></svg>`, '24px 24px'],
// 2: polka dots
[`<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><rect width='24' height='24' fill='${bg}'/><circle cx='12' cy='12' r='5' fill='${fg}' fill-opacity='0.35'/></svg>`, '24px 24px'],
// 3: diamonds
[`<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><rect width='24' height='24' fill='${bg}'/><polygon points='12,3 21,12 12,21 3,12' fill='none' stroke='${fg}' stroke-width='1.5' stroke-opacity='0.5'/></svg>`, '24px 24px'],
// 4: grid
[`<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><rect width='24' height='24' fill='${bg}'/><line x1='12' y1='0' x2='12' y2='24' stroke='${fg}' stroke-width='1' stroke-opacity='0.4'/><line x1='0' y1='12' x2='24' y2='12' stroke='${fg}' stroke-width='1' stroke-opacity='0.4'/></svg>`, '24px 24px'],
// 5: swirls — two crossing S-curves (yin-yang tiling) + echo curves for depth.
// Paths use corner-to-corner cubic beziers so opposite tile edges match perfectly.
[`<svg xmlns='http://www.w3.org/2000/svg' width='64' height='64'><rect width='64' height='64' fill='${bg}'/><path d='M0,0 C0,32 64,32 64,64' fill='none' stroke='${fg}' stroke-width='2.5' stroke-opacity='0.45' stroke-linecap='round'/><path d='M64,0 C64,32 0,32 0,64' fill='none' stroke='${fg}' stroke-width='2.5' stroke-opacity='0.45' stroke-linecap='round'/><path d='M0,16 C16,32 48,32 64,48' fill='none' stroke='${fg}' stroke-width='1.5' stroke-opacity='0.22' stroke-linecap='round'/><path d='M64,16 C48,32 16,32 0,48' fill='none' stroke='${fg}' stroke-width='1.5' stroke-opacity='0.22' stroke-linecap='round'/><circle cx='32' cy='32' r='4' fill='${fg}' fill-opacity='0.18'/></svg>`, '64px 64px'],
];
const [svg, size] = patterns[(demo_bg_state - 1) % DEMO_BG_PATTERNS];
return `background-image: url("data:image/svg+xml,${encodeURIComponent(svg)}"); background-repeat: repeat; background-size: ${size};`;
});
$effect(() => {
if (browser && $lq__event_badge_obj?.event_badge_id) {
qr_error_message = '';
@@ -281,6 +320,16 @@
<span title="Layout code">{$lq__event_badge_template_obj?.layout ?? '(no layout)'}</span>
<span class="text-gray-300">|</span>
<span class="text-blue-400" title="V2 — auto-scaling text, display-only render">v2</span>
{#if $ae_loc.edit_mode}
<span class="text-gray-300">|</span>
<button
class="px-1.5 py-0.5 rounded border text-xs transition-colors {demo_bg_state > 0 ? 'border-indigo-400 text-indigo-600 bg-indigo-50 dark:bg-indigo-950/40 dark:text-indigo-300 dark:border-indigo-600' : 'border-gray-300 text-gray-400 hover:text-gray-600 dark:border-zinc-600 dark:hover:text-zinc-300'}"
onclick={cycle_demo_bg}
title="Cycle demo background pattern edit mode only"
>
🎨 {demo_bg_state > 0 ? ['stripes','dots','diamonds','grid','swirls'][demo_bg_state - 1] : 'demo bg'}
</button>
{/if}
</div>
<section
@@ -312,6 +361,7 @@
outline-4 outline-red-500/50 hover:outline-red-700/75
group
"
style={demo_bg_style}
>
<span
class="