From 59badcbfe87ed441ad12d5ba2b88f5920526c3c2 Mon Sep 17 00:00:00 2001 From: Mikkel Georgsen Date: Sun, 1 Mar 2026 08:26:12 +0100 Subject: [PATCH] feat(01-14): implement More tab with templates, blind editor, wizard, settings, audit - TemplateManager with LEGO-style building block composition (5 block types) - BlindStructureEditor with full level fields, mixed game, reorder, add/delete - StructureWizard generates structures from player count, chips, duration params - More page with navigable menu to all sub-pages (admin-gated operators section) - Templates page with DataTable list, create/edit/duplicate/delete actions - Structures page with DataTable list, wizard integration, and editor - Settings page with venue config, currency, receipts, theme toggle (Mocha/Latte) - Audit log page with filterable DataTable, detail panel, and undo capability Co-Authored-By: Claude Opus 4.6 --- .../components/BlindStructureEditor.svelte | 564 +++++++++++++++++ .../src/lib/components/StructureWizard.svelte | 580 ++++++++++++++++++ .../src/lib/components/TemplateManager.svelte | 514 ++++++++++++++++ frontend/src/routes/more/+page.svelte | 173 ++++-- frontend/src/routes/more/audit/+page.svelte | 396 ++++++++++++ .../src/routes/more/settings/+page.svelte | 395 ++++++++++++ .../src/routes/more/structures/+page.svelte | 189 ++++++ .../src/routes/more/templates/+page.svelte | 165 +++++ 8 files changed, 2937 insertions(+), 39 deletions(-) create mode 100644 frontend/src/lib/components/BlindStructureEditor.svelte create mode 100644 frontend/src/lib/components/StructureWizard.svelte create mode 100644 frontend/src/lib/components/TemplateManager.svelte create mode 100644 frontend/src/routes/more/audit/+page.svelte create mode 100644 frontend/src/routes/more/settings/+page.svelte create mode 100644 frontend/src/routes/more/structures/+page.svelte create mode 100644 frontend/src/routes/more/templates/+page.svelte diff --git a/frontend/src/lib/components/BlindStructureEditor.svelte b/frontend/src/lib/components/BlindStructureEditor.svelte new file mode 100644 index 0000000..f362768 --- /dev/null +++ b/frontend/src/lib/components/BlindStructureEditor.svelte @@ -0,0 +1,564 @@ + + +
+

Blind Structure Editor

+ +
+ + +
+ + +
+
+ + + + + + + + + + + + + + + + + {#each editLevels as level, idx (level.position)} + + + + + + + + + + + + + {/each} + +
#TypeGameSBBBAnteBB AnteMinChip UpActions
{level.position} + + + {#if level.type === 'round'} + + {:else} + -- + {/if} + + {#if level.type === 'round'} + + {:else} + -- + {/if} + + {#if level.type === 'round'} + + {:else} + -- + {/if} + + {#if level.type === 'round'} + + {:else} + -- + {/if} + + {#if level.type === 'round'} + + {:else} + -- + {/if} + + + + {#if level.type === 'round'} + + {:else} + -- + {/if} + +
+ + + +
+
+
+
+ + +
+ + +
+ + +
+ + {#if oncancel} + + {/if} +
+
+ + diff --git a/frontend/src/lib/components/StructureWizard.svelte b/frontend/src/lib/components/StructureWizard.svelte new file mode 100644 index 0000000..2e41942 --- /dev/null +++ b/frontend/src/lib/components/StructureWizard.svelte @@ -0,0 +1,580 @@ + + +
+

Structure Wizard

+

Generate a blind structure from tournament parameters.

+ + +
+
+ + + {playerCount} +
+ +
+ +
+ {#each CHIP_PRESETS as preset} + + {/each} +
+ +
+ +
+ + + {targetHours}h +
+ +
+ + +
+
+ + + + + + {#if hasGenerated} +
+
+

Preview

+ + {roundLevelCount} levels, {totalDuration} min ({(totalDuration / 60).toFixed(1)}h) + +
+ +
+ + + + + + + + + + + + + + {#each generatedLevels as level (level.position)} + + + + + + + + + + {/each} + +
#TypeSBBBAnteBB AnteMin
{level.position}{level.type === 'break' ? 'Break' : 'Round'}{level.type === 'round' ? level.small_blind.toLocaleString() : '--'}{level.type === 'round' ? level.big_blind.toLocaleString() : '--'}{level.type === 'round' && level.ante > 0 ? level.ante.toLocaleString() : '--'}{level.type === 'round' && level.bb_ante > 0 ? level.bb_ante.toLocaleString() : '--'}{level.duration_minutes}
+
+ + +
+ + +
+ +
+ + {#if onusetemplate} + + {/if} +
+
+ {/if} + + {#if oncancel} + + {/if} +
+ + diff --git a/frontend/src/lib/components/TemplateManager.svelte b/frontend/src/lib/components/TemplateManager.svelte new file mode 100644 index 0000000..a8cdb6c --- /dev/null +++ b/frontend/src/lib/components/TemplateManager.svelte @@ -0,0 +1,514 @@ + + +
+

{isNew ? 'Create Template' : 'Edit Template'}

+ + +
+ + +
+ +
+ + +
+ + +
+

Building Blocks

+ + +
+
+ Chip Set + +
+ + {#if form.chip_set_id} +
{getBlockSummary(chipSets, form.chip_set_id)}
+ {/if} +
+ + +
+
+ Blind Structure + +
+ + {#if form.blind_structure_id} +
{getBlockSummary(blindStructures, form.blind_structure_id)}
+ {/if} +
+ + +
+
+ Payout Structure + +
+ + {#if form.payout_structure_id} +
{getBlockSummary(payoutStructures, form.payout_structure_id)}
+ {/if} +
+ + +
+
+ Buy-in Config + +
+ + {#if form.buyin_config_id} +
{getBlockSummary(buyinConfigs, form.buyin_config_id)}
+ {/if} +
+ + +
+
+ Points Formula (optional) + +
+ + {#if form.points_formula_id} +
{getBlockSummary(pointsFormulas, form.points_formula_id)}
+ {/if} +
+
+ + +
+

Tournament Options

+ +
+
+ + +
+
+ + +
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+ + +
+ + {#if oncancel} + + {/if} +
+
+ + diff --git a/frontend/src/routes/more/+page.svelte b/frontend/src/routes/more/+page.svelte index b9c8506..4380e31 100644 --- a/frontend/src/routes/more/+page.svelte +++ b/frontend/src/routes/more/+page.svelte @@ -1,7 +1,39 @@ + +
+

Audit Log

+

Action history with undo capability.

+ + +
+
+ + +
+
+ + +
+
+ + + []} + sortable={true} + searchable={true} + loading={false} + emptyMessage="No audit entries match your filters." + rowKey={(item) => String(item['id'])} + onrowclick={handleRowClick} + /> + + + {#if selectedEntry} + + {/if} +
+ + diff --git a/frontend/src/routes/more/settings/+page.svelte b/frontend/src/routes/more/settings/+page.svelte new file mode 100644 index 0000000..76f5352 --- /dev/null +++ b/frontend/src/routes/more/settings/+page.svelte @@ -0,0 +1,395 @@ + + +
+

Venue Settings

+

Configure your poker room.

+ +
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ {#each RECEIPT_OPTIONS as opt} + + {/each} +
+
+ + +
+ + +
+ + + +
+ + + {#if auth.isAdmin} +
+

Operators

+

Manage floor staff (admin only).

+ +
+
+
+ {auth.operator?.name ?? 'Admin'} + admin +
+ You +
+
+
+ Floor Manager + floor +
+ +
+
+
+ {/if} +
+ + diff --git a/frontend/src/routes/more/structures/+page.svelte b/frontend/src/routes/more/structures/+page.svelte new file mode 100644 index 0000000..af5f70a --- /dev/null +++ b/frontend/src/routes/more/structures/+page.svelte @@ -0,0 +1,189 @@ + + +
+ {#if mode === 'list'} + + + []} + sortable={true} + searchable={true} + loading={false} + emptyMessage="No blind structures. Create one or use the wizard." + rowKey={(item) => String(item['id'])} + onrowclick={handleEdit} + swipeActions={[ + { id: 'delete', label: 'Delete', color: 'var(--color-error)', handler: handleDelete } + ]} + /> + {:else if mode === 'edit'} + + {:else if mode === 'wizard'} + + {/if} +
+ + diff --git a/frontend/src/routes/more/templates/+page.svelte b/frontend/src/routes/more/templates/+page.svelte new file mode 100644 index 0000000..d489efe --- /dev/null +++ b/frontend/src/routes/more/templates/+page.svelte @@ -0,0 +1,165 @@ + + +
+ {#if mode === 'list'} + + + []} + sortable={true} + searchable={true} + loading={false} + emptyMessage="No templates yet. Create one to get started." + rowKey={(item) => String(item['id'])} + onrowclick={handleEdit} + swipeActions={[ + { id: 'duplicate', label: 'Duplicate', color: 'var(--color-primary)', handler: handleDuplicate }, + { id: 'delete', label: 'Delete', color: 'var(--color-error)', handler: handleDelete } + ]} + /> + {:else} + + {/if} +
+ +