From dc0872c3a81899b2e40f20eb7da1c05221bbbb72 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 10:57:46 +0000 Subject: [PATCH] Refine Bulgarian Solitaire animation Update Bulgarian Solitaire animation to fade red highlight in, pause, move blocks to a new column, and then fade back to black. --- src/components/BulgarianSolitaire.tsx | 53 +++++++++++++++++++++++---- tailwind.config.ts | 13 +++++-- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/components/BulgarianSolitaire.tsx b/src/components/BulgarianSolitaire.tsx index 955519f..2730f26 100644 --- a/src/components/BulgarianSolitaire.tsx +++ b/src/components/BulgarianSolitaire.tsx @@ -24,6 +24,7 @@ const BulgarianSolitaire: React.FC = ({ showSocialShare const [isComplete, setIsComplete] = useState(false); const [highlightedBoxes, setHighlightedBoxes] = useState>(new Set()); const [isAnimating, setIsAnimating] = useState(false); + const [animationPhase, setAnimationPhase] = useState<'idle' | 'fade-to-red' | 'red-pause' | 'moving' | 'fade-from-red'>('idle'); const [lastUsedColumn, setLastUsedColumn] = useState(null); const [selectedBoxForMove, setSelectedBoxForMove] = useState(null); const [showInstructions, setShowInstructions] = useState(false); @@ -232,10 +233,21 @@ const BulgarianSolitaire: React.FC = ({ showSocialShare }); setHighlightedBoxes(topBoxes); + + // Phase 1: Fade to red + setAnimationPhase('fade-to-red'); setIsAnimating(true); - await sleep(800); // Show highlighting - await waitForUnpause(); // Check for pause + await sleep(500); // Fade to red animation + await waitForUnpause(); + // Phase 2: Red pause + setAnimationPhase('red-pause'); + await sleep(1000); // Pause for 1 second with red blocks + await waitForUnpause(); + + // Phase 3: Move blocks + setAnimationPhase('moving'); + // Create new pile from non-empty columns const newPile: number[] = []; const updatedColumns = currentColumns.map(col => { @@ -257,12 +269,34 @@ const BulgarianSolitaire: React.FC = ({ showSocialShare break; } + currentColumns = updatedColumns; + setColumns(currentColumns); + + // Update box positions + setBoxes(prev => prev.map(box => { + for (let i = 0; i < currentColumns.length; i++) { + if (currentColumns[i].includes(box.id)) { + return { ...box, columnIndex: i }; + } + } + return box; + })); + + await sleep(500); // Show move + await waitForUnpause(); + + // Phase 4: Fade from red to normal + setAnimationPhase('fade-from-red'); + await sleep(500); // Fade from red animation + await waitForUnpause(); + // Clear highlighting and animation setHighlightedBoxes(new Set()); setIsAnimating(false); + setAnimationPhase('idle'); // Sort columns by height (tallest to left) - const columnData = updatedColumns.map((col, index) => ({ col, originalIndex: index })) + const columnData = currentColumns.map((col, index) => ({ col, originalIndex: index })) .filter(item => item.col.length > 0) .sort((a, b) => b.col.length - a.col.length); @@ -284,7 +318,7 @@ const BulgarianSolitaire: React.FC = ({ showSocialShare return box; })); - await sleep(1200); // Wait to see the sorted result + await sleep(800); // Wait to see the sorted result await waitForUnpause(); // Check for pause again } @@ -316,6 +350,7 @@ const BulgarianSolitaire: React.FC = ({ showSocialShare setIsComplete(false); setHighlightedBoxes(new Set()); setIsAnimating(false); + setAnimationPhase('idle'); }; const randomStart = () => { @@ -440,10 +475,12 @@ const BulgarianSolitaire: React.FC = ({ showSocialShare onDragStart={(e) => handleDragStart(e, boxId)} onDoubleClick={() => handleDoubleClick(boxId)} className={`w-8 h-8 rounded cursor-move transition-all duration-300 flex items-center justify-center text-xs font-medium mx-auto ${ - isAnimating && highlightedBoxes.has(boxId) - ? 'animate-[fade-red_1.6s_ease-in-out_infinite] shadow-lg scale-110 text-white' - : highlightedBoxes.has(boxId) - ? 'bg-red-500 text-white shadow-lg scale-110' + highlightedBoxes.has(boxId) && animationPhase === 'fade-to-red' + ? 'animate-fade-to-red shadow-lg scale-110 text-white' + : highlightedBoxes.has(boxId) && (animationPhase === 'red-pause' || animationPhase === 'moving') + ? 'bg-red-500 text-white shadow-lg scale-110' + : highlightedBoxes.has(boxId) && animationPhase === 'fade-from-red' + ? 'animate-fade-from-red shadow-lg scale-110' : 'bg-primary text-primary-foreground hover:bg-primary/80' }`} title="Drag to move or double-click to move to last-used column" diff --git a/tailwind.config.ts b/tailwind.config.ts index 812f0fa..a4b00a3 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -101,15 +101,20 @@ export default { height: '0' } }, - 'fade-red': { - '0%, 100%': { backgroundColor: 'hsl(var(--primary))' }, - '50%': { backgroundColor: 'hsl(0, 84%, 60%)' } + 'fade-to-red': { + '0%': { backgroundColor: 'hsl(var(--primary))' }, + '100%': { backgroundColor: 'hsl(0, 84%, 60%)' } + }, + 'fade-from-red': { + '0%': { backgroundColor: 'hsl(0, 84%, 60%)' }, + '100%': { backgroundColor: 'hsl(var(--primary))' } } }, animation: { 'accordion-down': 'accordion-down 0.2s ease-out', 'accordion-up': 'accordion-up 0.2s ease-out', - 'fade-red': 'fade-red 1.6s ease-in-out infinite' + 'fade-to-red': 'fade-to-red 0.5s ease-out forwards', + 'fade-from-red': 'fade-from-red 0.5s ease-out forwards' }, fontFamily: { 'sans': ['Lato', 'ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', 'sans-serif'],