From f9819b324e68bb054bdd2ff3fdd35d5ffd4c7704 Mon Sep 17 00:00:00 2001 From: dnviti Date: Wed, 17 Dec 2025 01:20:17 +0100 Subject: [PATCH] feat: Introduce card size slider for unified scaling across grid and stack views, and add smart preview suppression. --- docs/development/CENTRAL.md | 3 +++ ...-12-17-023000_smart_preview_suppression.md | 16 +++++++++++++ .../2025-12-17-023500_compact_card_layout.md | 18 ++++++++++++++ .../2025-12-17-024000_view_scale_slider.md | 19 +++++++++++++++ src/client/src/components/CardPreview.tsx | 13 ++++++++-- src/client/src/components/PackCard.tsx | 9 +++---- src/client/src/components/StackView.tsx | 5 ++-- src/client/src/modules/cube/CubeManager.tsx | 24 ++++++++++++++++++- 8 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 docs/development/devlog/2025-12-17-023000_smart_preview_suppression.md create mode 100644 docs/development/devlog/2025-12-17-023500_compact_card_layout.md create mode 100644 docs/development/devlog/2025-12-17-024000_view_scale_slider.md diff --git a/docs/development/CENTRAL.md b/docs/development/CENTRAL.md index 31621cb..8ba6aba 100644 --- a/docs/development/CENTRAL.md +++ b/docs/development/CENTRAL.md @@ -55,3 +55,6 @@ - [Entrance Animation Fix](./devlog/2025-12-17-021500_entrance_animation_fix.md): Completed. Implemented 'isMounted' state to ensuring scale-in animation triggers correctly on first render. - [Foil Bug Fix](./devlog/2025-12-17-022000_foil_bug_fix.md): Completed. Fixed regression where foil animations applied to non-foil cards on desktop. - [Universal Foil Application](./devlog/2025-12-17-022500_universal_foil_application.md): Completed. Applied foil animation to Grid View and Stack View card thumbnails. +- [Smart Preview Suppression](./devlog/2025-12-17-023000_smart_preview_suppression.md): Completed. Disabled hover preview for card elements that are already rendered large enough on screen. +- [Compact Card Layout](./devlog/2025-12-17-023500_compact_card_layout.md): Completed. Decreased card sizes in Grid and Stack views for a denser UI. +- [View Scale Slider](./devlog/2025-12-17-024000_view_scale_slider.md): Completed. Added a slider to dynamically adjust card dimensions, synced across Grid and Stack views. diff --git a/docs/development/devlog/2025-12-17-023000_smart_preview_suppression.md b/docs/development/devlog/2025-12-17-023000_smart_preview_suppression.md new file mode 100644 index 0000000..98be908 --- /dev/null +++ b/docs/development/devlog/2025-12-17-023000_smart_preview_suppression.md @@ -0,0 +1,16 @@ +# Intelligent Preview Suppression + +## Objective +Prevent the card preview popup from appearing when the user hovers over a card that is already displayed at a significantly large size on the screen (e.g., in a large grid view), reducing UI clutter. + +## Changes +- Modified `CardHoverWrapper` in `src/client/src/components/CardPreview.tsx`: + - Updated `handleMouseEnter` to inspect the dimensions of the hovered element using `getBoundingClientRect`. + - Implemented a threshold check: `Width > 240px` AND `Height > 300px`. + - **Logic**: + - **Large Grid Items**: If a card in the grid is rendered wider than 240px and taller than 300px, the hover preview is suppressed. + - **List Items**: Even if a list row is wide (e.g., 800px), its height is small (e.g., 40px), so the preview **will still appear**. + - **Small Thumbnails**: Small grid items or stack views usually fall below this threshold, ensuring the preview appears when needed. + +## Result +The system now intelligently hides the preview when it is redundant, creating a cleaner experience on large desktop screens while maintaining necessary functionality for smaller thumbnails and list views. diff --git a/docs/development/devlog/2025-12-17-023500_compact_card_layout.md b/docs/development/devlog/2025-12-17-023500_compact_card_layout.md new file mode 100644 index 0000000..fdb9004 --- /dev/null +++ b/docs/development/devlog/2025-12-17-023500_compact_card_layout.md @@ -0,0 +1,18 @@ +# Compact Card Layout + +## Objective +Slightly resize the card visualizations in both Grid and Stack views to allow more cards to fit on the screen, creating a denser and more "compact" interface as requested. + +## Changes +- **Pack Grid View** (`src/client/src/components/PackCard.tsx`): + - Increased the column density across all breakpoints: + - Base: `grid-cols-2` -> `grid-cols-3` + - Small: `grid-cols-3` -> `grid-cols-4` + - Medium: `grid-cols-4` -> `grid-cols-5` + - Large: `grid-cols-5` -> `grid-cols-6` + - This reduces the individual card width, making them visually smaller. +- **Stack / Deck View** (`src/client/src/components/StackView.tsx`): + - Reduced the fixed width of each stack column from `w-44` (176px) to `w-36` (144px). + +## Result +Cards appear slightly smaller ("a little more smaller"), providing a broader overview of the pool and deck without requiring as much scrolling. This works in tandem with the "Smart Preview Suppression" (which will likely now re-enable previews for these smaller cards, aiding readability). diff --git a/docs/development/devlog/2025-12-17-024000_view_scale_slider.md b/docs/development/devlog/2025-12-17-024000_view_scale_slider.md new file mode 100644 index 0000000..14df8fa --- /dev/null +++ b/docs/development/devlog/2025-12-17-024000_view_scale_slider.md @@ -0,0 +1,19 @@ +# View Scale Slider + +## Objective +Provide the user with granular control over card thumbnail sizes across the application, ensuring consistency between Grid and Stack views. + +## Changes +- **CubeManager**: + - Added a new `cardWidth` state variable, persisted to `localStorage` (default `140px`). + - Introduced a **Range Slider** in the top-right control toolbar (visible on desktop) allowing adjustment from 100px to 300px. + - Passed `cardWidth` down to `PackCard`. +- **PackCard (Grid View)**: + - Replaced the responsive `grid-cols-*` logic with a `flex flex-wrap` layout. + - Each card container now receives an explicit `style={{ width: cardWidth }}`. +- **StackView (Stack View)**: + - Accepted `cardWidth` prop. + - Applied `style={{ width: cardWidth }}` to the column containers, dynamically ensuring that stacks resize in sync with the grid view setting. + +## Result +Users can now drag a slider to instantly resize all card thumbnails on the screen. This allows for customized density—make cards huge to admire the art, or tiny to see the entire cube/pool at a glance—with perfect size synchronization between the different view modes. diff --git a/src/client/src/components/CardPreview.tsx b/src/client/src/components/CardPreview.tsx index 6e7ac4e..5fd49fc 100644 --- a/src/client/src/components/CardPreview.tsx +++ b/src/client/src/components/CardPreview.tsx @@ -125,8 +125,17 @@ export const CardHoverWrapper: React.FC<{ card: DraftCard; children: React.React setCoords({ x: e.clientX, y: e.clientY }); }; - const handleMouseEnter = () => { - if (!isMobile) setIsHovering(true); + const handleMouseEnter = (e: React.MouseEvent) => { + if (isMobile) return; + + // Check if the card is already "big enough" on screen + const rect = e.currentTarget.getBoundingClientRect(); + // Width > 240 && Height > 300 targets large grid items but excludes thin list rows + if (rect.width > 240 && rect.height > 300) { + return; + } + + setIsHovering(true); }; const handleMouseLeave = () => { diff --git a/src/client/src/components/PackCard.tsx b/src/client/src/components/PackCard.tsx index b21a433..9c9fc42 100644 --- a/src/client/src/components/PackCard.tsx +++ b/src/client/src/components/PackCard.tsx @@ -6,6 +6,7 @@ import { StackView } from './StackView'; interface PackCardProps { pack: Pack; viewMode: 'list' | 'grid' | 'stack'; + cardWidth?: number; } import { CardHoverWrapper, FoilOverlay } from './CardPreview'; @@ -41,7 +42,7 @@ const ListItem: React.FC<{ card: DraftCard }> = ({ card }) => { ); }; -export const PackCard: React.FC = ({ pack, viewMode }) => { +export const PackCard: React.FC = ({ pack, viewMode, cardWidth = 150 }) => { const mythics = pack.cards.filter(c => c.rarity === 'mythic'); const rares = pack.cards.filter(c => c.rarity === 'rare'); const uncommons = pack.cards.filter(c => c.rarity === 'uncommon'); @@ -97,10 +98,10 @@ export const PackCard: React.FC = ({ pack, viewMode }) => { )} {viewMode === 'grid' && ( -
+
{pack.cards.map((card) => ( -
+
{/* Visual Card */}
{isFoil(card) && } @@ -126,7 +127,7 @@ export const PackCard: React.FC = ({ pack, viewMode }) => {
)} - {viewMode === 'stack' && } + {viewMode === 'stack' && }
); diff --git a/src/client/src/components/StackView.tsx b/src/client/src/components/StackView.tsx index 6b13d31..4351292 100644 --- a/src/client/src/components/StackView.tsx +++ b/src/client/src/components/StackView.tsx @@ -4,6 +4,7 @@ import { CardHoverWrapper, FoilOverlay } from './CardPreview'; interface StackViewProps { cards: DraftCard[]; + cardWidth?: number; } const CATEGORY_ORDER = [ @@ -18,7 +19,7 @@ const CATEGORY_ORDER = [ 'Other' ]; -export const StackView: React.FC = ({ cards }) => { +export const StackView: React.FC = ({ cards, cardWidth = 150 }) => { const categorizedCards = useMemo(() => { const categories: Record = {}; @@ -59,7 +60,7 @@ export const StackView: React.FC = ({ cards }) => { if (catCards.length === 0) return null; return ( -
+
{/* Header */}
{category} diff --git a/src/client/src/modules/cube/CubeManager.tsx b/src/client/src/modules/cube/CubeManager.tsx index 45bff5b..af0d614 100644 --- a/src/client/src/modules/cube/CubeManager.tsx +++ b/src/client/src/modules/cube/CubeManager.tsx @@ -101,6 +101,11 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT return saved ? parseInt(saved) : 3; }); + const [cardWidth, setCardWidth] = useState(() => { + const saved = localStorage.getItem('cube_cardWidth'); + return saved ? parseInt(saved) : 140; + }); + // --- Persistence Effects --- useEffect(() => localStorage.setItem('cube_inputText', inputText), [inputText]); useEffect(() => localStorage.setItem('cube_filters', JSON.stringify(filters)), [filters]); @@ -108,6 +113,7 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT useEffect(() => localStorage.setItem('cube_sourceMode', sourceMode), [sourceMode]); useEffect(() => localStorage.setItem('cube_selectedSets', JSON.stringify(selectedSets)), [selectedSets]); useEffect(() => localStorage.setItem('cube_numBoxes', numBoxes.toString()), [numBoxes]); + useEffect(() => localStorage.setItem('cube_cardWidth', cardWidth.toString()), [cardWidth]); const fileInputRef = useRef(null); @@ -660,6 +666,22 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT {copySuccess ? : } {copySuccess ? 'Copied!' : 'Copy'} + + {/* Size Slider */} +
+
+ setCardWidth(parseInt(e.target.value))} + className="w-24 accent-purple-500 cursor-pointer h-1.5 bg-slate-600 rounded-lg appearance-none" + title={`Card Size: ${cardWidth}px`} + /> +
+
)} @@ -679,7 +701,7 @@ export const CubeManager: React.FC = ({ packs, setPacks, onGoT ) : (
{packs.map((pack) => ( - + ))}
)}