From 90d50bf1c2aa158fe2296af43a55bf1b37b8dd7f Mon Sep 17 00:00:00 2001 From: dnviti Date: Wed, 17 Dec 2025 14:37:49 +0100 Subject: [PATCH] feat: Unify card fetching/parsing and pack generation into a single `handleGenerate` function and button. --- docs/development/CENTRAL.md | 2 + .../2025-12-17-142500_responsive_pack_grid.md | 20 +++ ...025-12-17-143000_stack_view_consistency.md | 17 ++ src/client/src/components/PackCard.tsx | 6 +- src/client/src/modules/cube/CubeManager.tsx | 148 ++++++++---------- 5 files changed, 107 insertions(+), 86 deletions(-) create mode 100644 docs/development/devlog/2025-12-17-142500_responsive_pack_grid.md create mode 100644 docs/development/devlog/2025-12-17-143000_stack_view_consistency.md diff --git a/docs/development/CENTRAL.md b/docs/development/CENTRAL.md index 0d056eb..5ace898 100644 --- a/docs/development/CENTRAL.md +++ b/docs/development/CENTRAL.md @@ -74,3 +74,5 @@ - [Play Online Logic](./devlog/2025-12-17-031500_play_online_logic.md): Completed. Implemented strict pack limits (min 12 for 4 players) and visual feedback for the online lobby button. - [Lobby Rules Tooltip](./devlog/2025-12-17-032000_lobby_rules_tooltip.md): Completed. Added dynamic rules explanation and supported player indicators to the lobby creation screen. - [Fix Expansion Pack Generation](./devlog/2025-12-17-140000_fix_expansion_generation.md): Completed. Enforced infinite card pool for expansion drafts to ensure correct pack counts and prevent depletion. +- [Responsive Pack Grid Layout](./devlog/2025-12-17-142500_responsive_pack_grid.md): Completed. Implemented responsive multi-column grid for generated packs when card size is reduced (<25% slider). +- [Stack View Consistency Fix](./devlog/2025-12-17-143000_stack_view_consistency.md): Completed. Removed transparent overrides for Stack View, ensuring it renders with the standard unified container graphic. diff --git a/docs/development/devlog/2025-12-17-142500_responsive_pack_grid.md b/docs/development/devlog/2025-12-17-142500_responsive_pack_grid.md new file mode 100644 index 0000000..2da151f --- /dev/null +++ b/docs/development/devlog/2025-12-17-142500_responsive_pack_grid.md @@ -0,0 +1,20 @@ +# Responsive Pack Grid Layout + +## Objective +Update the generated packs UI to maximize pack density on screen when the user reduces the card size. + +## Requirements +- When the card size slider is under 25% (value <= 150), switch the pack container layout from a vertical stack (`grid-cols-1`) to a responsive multi-column grid (`grid-cols-1 md:grid-cols-2 xl:grid-cols-3` etc.). +- Ensure this applies to all view modes (List, Grid, Stack). +- Maintain consistency in UI. + +## Implementation +- Modified `src/client/src/modules/cube/CubeManager.tsx`. +- Added conditional logic to the main packs container `div`. +- Condition: `cardWidth <= 150`. +- Classes: `grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4` for compact mode. + +## Verification +- Verified using browser simulation. +- Verified that setting slider to 100 triggers the grid layout. +- Verified that setting slider to 300 reverts to vertical stack. diff --git a/docs/development/devlog/2025-12-17-143000_stack_view_consistency.md b/docs/development/devlog/2025-12-17-143000_stack_view_consistency.md new file mode 100644 index 0000000..4bc829d --- /dev/null +++ b/docs/development/devlog/2025-12-17-143000_stack_view_consistency.md @@ -0,0 +1,17 @@ +# Stack View Consistency Fix + +## Objective +Ensure the Stack View pack container has the same visual styling (background, border, shadow, header) as the List and Grid views. + +## User Request +"the stacked view region graphic is not consistent with the other views, the container region is missing" + +## Implementation +- Modified `src/client/src/components/PackCard.tsx`. +- Removed the conditional ternary operators that stripped the background and border when `viewMode === 'stack'`. +- Ensured consistent `p-4` padding for the content wrapper. +- The `StackView` component is now rendered inside the standard slate card container. + +## Verification +- Code review confirms the removal of `bg-transparent border-none` overrides. +- This ensures the `bg-slate-800` class applied to the parent `div` is visible in all modes. diff --git a/src/client/src/components/PackCard.tsx b/src/client/src/components/PackCard.tsx index f6fc830..e78ed5c 100644 --- a/src/client/src/components/PackCard.tsx +++ b/src/client/src/components/PackCard.tsx @@ -57,9 +57,9 @@ export const PackCard: React.FC = ({ pack, viewMode, cardWidth = }; return ( -
+
{/* Header */} -
+

Pack #{pack.id}

{pack.setName} @@ -74,7 +74,7 @@ export const PackCard: React.FC = ({ pack, viewMode, cardWidth =
{/* Content */} -
+
{viewMode === 'list' && (
{(mythics.length > 0 || rares.length > 0) && ( diff --git a/src/client/src/modules/cube/CubeManager.tsx b/src/client/src/modules/cube/CubeManager.tsx index 97328d4..0cc0c2c 100644 --- a/src/client/src/modules/cube/CubeManager.tsx +++ b/src/client/src/modules/cube/CubeManager.tsx @@ -175,27 +175,30 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT - const fetchAndParse = async () => { + const handleGenerate = async () => { + // Validate inputs + if (sourceMode === 'set' && selectedSets.length === 0) return; + if (sourceMode === 'upload' && !inputText) return; + setLoading(true); - setPacks([]); - setProgress(sourceMode === 'set' ? 'Fetching set data...' : 'Parsing text...'); + setPacks([]); // Clear old packs to avoid confusion try { - let expandedCards: ScryfallCard[] = []; + // --- Step 1: Fetch/Parse --- + let currentCards: ScryfallCard[] = []; + + setProgress(sourceMode === 'set' ? 'Fetching set data...' : 'Parsing text...'); if (sourceMode === 'set') { - if (selectedSets.length === 0) throw new Error("Please select at least one set."); - - // We fetch set by set to show progress + // Fetch set by set for (const [index, setCode] of selectedSets.entries()) { setProgress(`Fetching set ${setCode.toUpperCase()} (${index + 1}/${selectedSets.length})...`); - const response = await fetch(`/api/sets/${setCode}/cards`); if (!response.ok) throw new Error(`Failed to fetch set ${setCode}`); - const cards: ScryfallCard[] = await response.json(); - expandedCards.push(...cards); + currentCards.push(...cards); } + } else { // Parse Text setProgress('Parsing and fetching from server...'); @@ -210,36 +213,18 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT throw new Error(err.error || "Failed to parse cards"); } - expandedCards = await response.json(); + currentCards = await response.json(); + } - setRawScryfallData(expandedCards); - setLoading(false); - setProgress(''); + // Update local state for UI preview/stats + setRawScryfallData(currentCards); - } catch (err: any) { - console.error(err); - alert(err.message || "Error during process."); - setLoading(false); - } - }; + // --- Step 2: Generate --- + setProgress('Generating packs on server...'); - const generatePacks = async () => { - // if (!processedData) return; // Logic moved to server, but we still use processedData for UI check - if (!rawScryfallData || rawScryfallData.length === 0) { - if (sourceMode === 'set' && selectedSets.length > 0) { - // Allowed to proceed if sets selected (server fetches) - } else { - return; - } - } - - setLoading(true); - setProgress('Generating packs on server...'); - - try { const payload = { - cards: sourceMode === 'upload' ? rawScryfallData : [], + cards: sourceMode === 'upload' ? currentCards : [], // For set mode, we let server refetch or handle it sourceMode, selectedSets, settings: { @@ -251,7 +236,6 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT filters }; - // Use fetch from server logic if (sourceMode === 'set') { payload.cards = []; } @@ -274,9 +258,9 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT } else { setPacks(newPacks); } - } catch (e: any) { - console.error("Generation failed", e); - alert("Error generating packs: " + e.message); + } catch (err: any) { + console.error("Process failed", err); + alert(err.message || "Error during process."); } finally { setLoading(false); setProgress(''); @@ -434,13 +418,7 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT disabled={loading} /> - + {/* Parse Button Removed per request */} ) : ( <> @@ -559,34 +537,12 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT
-
- -
- setNumBoxes(parseInt(e.target.value))} - className="w-16 bg-slate-800 border-none rounded p-1 text-center text-white font-mono" - disabled={loading} - /> - Booster Boxes ({numBoxes * 36} Packs) -
-
- - + {/* Fetch Set and Quantity Blocks Removed/Moved */} )} {/* Generation Settings */} - {processedData && Object.keys(processedData.sets).length > 0 && ( + {(sourceMode === 'set' ? selectedSets.length > 0 : !!inputText) && (

Configuration @@ -630,25 +586,46 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT

- {/* Sets Info */} -
- {Object.values(processedData.sets).sort((a, b) => b.commons.length - a.commons.length).map(set => ( -
- {set.name} - {set.commons.length}C / {set.uncommons.length}U / {set.rares.length}R + {/* Quantity - Moved Here */} + {sourceMode === 'set' && ( +
+ +
+ setNumBoxes(parseInt(e.target.value))} + className="w-16 bg-slate-700 border-none rounded p-1 text-center text-white font-mono" + disabled={loading} + /> + Boxes ({numBoxes * 36} Packs)
- ))} -
+
+ )} + + {/* Sets Info */} + {processedData && Object.keys(processedData.sets).length > 0 && ( +
+ {Object.values(processedData.sets).sort((a, b) => b.commons.length - a.commons.length).map(set => ( +
+ {set.name} + {set.commons.length}C / {set.uncommons.length}U / {set.rares.length}R +
+ ))} +
+ )}
)} {/* Reset Button */} @@ -734,7 +711,12 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT

No packs generated.

) : ( -
+
{packs.map((pack) => ( ))}