v23: React + TypeScript SPA migration
Complete frontend rewrite from vanilla HTML/CSS/JS to React 19 + TypeScript + Tailwind CSS v4. Frontend (frontend/commander-ai-lab-ui/): - Vite + React 19 + TypeScript + Tailwind CSS v4 + React Router - 7 pages: BatchSim, Collection, Decks, AutoGen, Simulator, Coach, Training - Reusable components: Spinner, StatusBadge, CardImage, ManaSymbols, EmptyState - Full typed API client layer (8 modules matching all backend endpoints) - Recharts for mana curves, win rate charts, progress bars - Lucide icons throughout - Custom dark theme with MTG mana color tokens - Code splitting (recharts + react in separate chunks) Backend (lab_api.py): - SPA-aware static file serving with catch-all for client-side routing - Fallback to legacy ui/ folder if React dist not built - Updated startup log with SPA route list Build system: - .gitignore added (was missing - removes pyc, db, node_modules, etc.) - build-full-installer-v2.py: v23 with Node.js check + React build step - Vite build config with manual chunks for optimal loading Also includes: V3 deck generator fixes, coach improvements, DeepSeek sim modules
This commit is contained in:
1 parent
e6b5e0cedb
commit
a5fe8cb3fa
376 files changed
+18367
-22656
No files matched your search
+69
-28
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Commander AI Lab — Auto Deck Generator</title>
|
||||
<title>Commander AI Lab — Auto Deck Generator V3</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
@@ -39,13 +39,37 @@
|
||||
</div>
|
||||
<div class="dg-commander-selected" id="dg-commander-selected" style="display:none">
|
||||
<div class="dg-commander-card">
|
||||
<button class="dg-commander-clear" id="dg-commander-clear" title="Clear commander">×</button>
|
||||
<img class="dg-commander-img" id="dg-commander-img" src="" alt="" />
|
||||
<div class="dg-commander-info">
|
||||
<div class="dg-commander-name" id="dg-commander-name"></div>
|
||||
<div class="dg-commander-type" id="dg-commander-type"></div>
|
||||
<div class="dg-commander-colors" id="dg-commander-colors"></div>
|
||||
</div>
|
||||
<button class="dg-commander-clear" id="dg-commander-clear" title="Clear commander">×</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Strategy & Bracket -->
|
||||
<div class="dg-panel">
|
||||
<div class="dg-panel-header">
|
||||
<span class="dg-panel-title">Strategy & Power</span>
|
||||
</div>
|
||||
<div class="dg-panel-body">
|
||||
<input
|
||||
type="text"
|
||||
class="dg-input"
|
||||
id="dg-strategy"
|
||||
placeholder="e.g. zombie tokens, voltron, spellslinger..."
|
||||
/>
|
||||
<div class="dg-bracket-row">
|
||||
<label class="dg-label">Target Bracket</label>
|
||||
<div class="dg-bracket-btns" id="dg-bracket-btns">
|
||||
<button class="dg-bracket-btn" data-bracket="1" title="Casual — precon level">B1</button>
|
||||
<button class="dg-bracket-btn" data-bracket="2" title="Upgraded Casual">B2</button>
|
||||
<button class="dg-bracket-btn dg-bracket-active" data-bracket="3" title="High Power">B3</button>
|
||||
<button class="dg-bracket-btn" data-bracket="4" title="cEDH — maximum power">B4</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -66,27 +90,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Source Toggles -->
|
||||
<!-- Budget -->
|
||||
<div class="dg-panel">
|
||||
<div class="dg-panel-header">
|
||||
<span class="dg-panel-title">Template Sources</span>
|
||||
<span class="dg-panel-title">Budget</span>
|
||||
</div>
|
||||
<div class="dg-panel-body">
|
||||
<div class="dg-source-toggles" id="dg-source-toggles">
|
||||
<!-- Populated by JS from /api/deck-generator/config -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card Type Ratios -->
|
||||
<div class="dg-panel">
|
||||
<div class="dg-panel-header">
|
||||
<span class="dg-panel-title">Card Type Targets</span>
|
||||
<span class="dg-panel-hint" id="dg-total-hint">100 / 100</span>
|
||||
</div>
|
||||
<div class="dg-panel-body">
|
||||
<div class="dg-ratio-list" id="dg-ratio-list">
|
||||
<!-- Populated by JS from config defaults -->
|
||||
<div class="dg-budget-row">
|
||||
<input
|
||||
type="number"
|
||||
class="dg-input dg-input-narrow"
|
||||
id="dg-budget"
|
||||
placeholder="No limit"
|
||||
min="0"
|
||||
step="25"
|
||||
/>
|
||||
<select class="dg-select" id="dg-budget-mode">
|
||||
<option value="total">Total Deck $</option>
|
||||
<option value="per_card">Per Card Max $</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -98,22 +120,29 @@
|
||||
</div>
|
||||
<div class="dg-panel-body">
|
||||
<label class="dg-toggle-row">
|
||||
<span class="dg-toggle-label">Only cards I own</span>
|
||||
<input type="checkbox" class="dg-toggle-check" id="dg-only-owned" />
|
||||
<span class="dg-toggle-label">Use my collection</span>
|
||||
<input type="checkbox" class="dg-toggle-check" id="dg-use-collection" checked />
|
||||
<span class="dg-toggle-track"><span class="dg-toggle-thumb"></span></span>
|
||||
</label>
|
||||
<label class="dg-toggle-row">
|
||||
<span class="dg-toggle-label">Allow proxies (from sources)</span>
|
||||
<input type="checkbox" class="dg-toggle-check" id="dg-allow-proxies" checked />
|
||||
<span class="dg-toggle-label">Smart Substitution</span>
|
||||
<input type="checkbox" class="dg-toggle-check" id="dg-substitution" checked />
|
||||
<span class="dg-toggle-track"><span class="dg-toggle-thumb"></span></span>
|
||||
</label>
|
||||
<div class="dg-model-row">
|
||||
<label class="dg-label">AI Model</label>
|
||||
<select class="dg-select" id="dg-model">
|
||||
<option value="sonar">Sonar (fast, ~$0.004)</option>
|
||||
<option value="sonar-pro">Sonar Pro (deep, ~$0.04)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="dg-actions">
|
||||
<button class="dg-btn dg-btn-preview" id="dg-preview-btn" disabled>
|
||||
<span class="dg-btn-icon">👁</span> Preview Deck
|
||||
<span class="dg-btn-icon">⚡</span> Generate Deck
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -124,26 +153,32 @@
|
||||
<!-- Empty State -->
|
||||
<div class="dg-empty-state" id="dg-empty-state">
|
||||
<div class="dg-empty-icon">⚡</div>
|
||||
<div class="dg-empty-title">Configure & Preview</div>
|
||||
<div class="dg-empty-text">Select a commander and click "Preview Deck" to generate a deck from your collection.</div>
|
||||
<div class="dg-empty-title">V3 AI Deck Generator</div>
|
||||
<div class="dg-empty-text">Select a commander, set your bracket and strategy, then click "Generate Deck" to build a complete 100-card deck using Perplexity AI with structured output.</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading State -->
|
||||
<div class="dg-loading" id="dg-loading" style="display:none">
|
||||
<div class="dg-spinner"></div>
|
||||
<div class="dg-loading-text">Generating deck...</div>
|
||||
<div class="dg-loading-text" id="dg-loading-text">Generating deck via Perplexity AI...</div>
|
||||
</div>
|
||||
|
||||
<!-- Results -->
|
||||
<div class="dg-results" id="dg-results" style="display:none">
|
||||
|
||||
<!-- Strategy & Bracket Summary -->
|
||||
<div class="dg-strategy-bar" id="dg-strategy-bar"></div>
|
||||
|
||||
<!-- Stats Bar -->
|
||||
<div class="dg-stats-bar" id="dg-stats-bar"></div>
|
||||
|
||||
<!-- Substitution Summary -->
|
||||
<div class="dg-sub-summary" id="dg-sub-summary" style="display:none"></div>
|
||||
|
||||
<!-- Card Groups -->
|
||||
<div class="dg-card-groups" id="dg-card-groups"></div>
|
||||
|
||||
<!-- Save Bar -->
|
||||
<!-- Export & Save Bar -->
|
||||
<div class="dg-save-bar" id="dg-save-bar">
|
||||
<button class="dg-btn dg-btn-save" id="dg-save-btn">
|
||||
<span class="dg-btn-icon">💾</span> Save to Deck Builder
|
||||
@@ -151,6 +186,12 @@
|
||||
<button class="dg-btn dg-btn-ghost" id="dg-regenerate-btn">
|
||||
<span class="dg-btn-icon">🔄</span> Regenerate
|
||||
</button>
|
||||
<div class="dg-export-group">
|
||||
<button class="dg-btn dg-btn-export" id="dg-export-csv">📊 CSV</button>
|
||||
<button class="dg-btn dg-btn-export" id="dg-export-dck">🎮 Forge .dck</button>
|
||||
<button class="dg-btn dg-btn-export" id="dg-export-moxfield">📋 Moxfield</button>
|
||||
<button class="dg-btn dg-btn-export" id="dg-export-shopping">🛒 Shopping List</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in new issue
Block a user