diff --git a/src/components/StackingBlocks.tsx b/src/components/StackingBlocks.tsx index 2a1af48..2ccc84b 100644 --- a/src/components/StackingBlocks.tsx +++ b/src/components/StackingBlocks.tsx @@ -1,11 +1,10 @@ import React, { useState, useCallback } from 'react'; import { Button } from '@/components/ui/button'; import { Slider } from '@/components/ui/slider'; -import { Input } from '@/components/ui/input'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Label } from '@/components/ui/label'; import { Separator } from '@/components/ui/separator'; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import SocialShare from './SocialShare'; import confetti from 'canvas-confetti'; @@ -19,17 +18,16 @@ const StackingBlocks: React.FC = ({ showSocialShare = false const [score, setScore] = useState(0); const [gameStarted, setGameStarted] = useState(false); const [gameComplete, setGameComplete] = useState(false); - const [selectedStack, setSelectedStack] = useState(null); - const [splitSize1, setSplitSize1] = useState(''); - const [splitSize2, setSplitSize2] = useState(''); - const [dialogOpen, setDialogOpen] = useState(false); + const [hoveredStack, setHoveredStack] = useState(null); + const [hoveredSplitPoint, setHoveredSplitPoint] = useState(null); const startGame = useCallback(() => { setStacks([n]); setScore(0); setGameStarted(true); setGameComplete(false); - setSelectedStack(null); + setHoveredStack(null); + setHoveredSplitPoint(null); }, [n]); const resetGame = useCallback(() => { @@ -37,38 +35,23 @@ const StackingBlocks: React.FC = ({ showSocialShare = false setScore(0); setGameStarted(false); setGameComplete(false); - setSelectedStack(null); - setSplitSize1(''); - setSplitSize2(''); - setDialogOpen(false); + setHoveredStack(null); + setHoveredSplitPoint(null); }, []); - const handleStackClick = useCallback((index: number, stackSize: number) => { - if (stackSize === 1) return; // Can't split stacks of size 1 - setSelectedStack(index); - setSplitSize1('1'); - setSplitSize2((stackSize - 1).toString()); - setDialogOpen(true); - }, []); - - const executeSplit = useCallback(() => { - if (selectedStack === null) return; + const handleStackClick = useCallback((stackIndex: number, splitPoint: number) => { + if (hoveredStack !== stackIndex || hoveredSplitPoint !== splitPoint) return; - const size1 = parseInt(splitSize1); - const size2 = parseInt(splitSize2); - const originalSize = stacks[selectedStack]; - - // Validate the split - if (size1 <= 0 || size2 <= 0 || size1 + size2 !== originalSize) { - return; - } + const stackSize = stacks[stackIndex]; + const size1 = splitPoint; + const size2 = stackSize - splitPoint; // Calculate points gained const pointsGained = size1 * size2; // Update stacks const newStacks = [...stacks]; - newStacks.splice(selectedStack, 1); // Remove the original stack + newStacks.splice(stackIndex, 1); // Remove the original stack newStacks.push(size1, size2); // Add the two new stacks newStacks.sort((a, b) => b - a); // Sort in descending order for better visualization @@ -85,20 +68,9 @@ const StackingBlocks: React.FC = ({ showSocialShare = false }); } - setDialogOpen(false); - setSelectedStack(null); - setSplitSize1(''); - setSplitSize2(''); - }, [selectedStack, splitSize1, splitSize2, stacks]); - - const handleSplit1Change = (value: string) => { - setSplitSize1(value); - const size1 = parseInt(value); - if (!isNaN(size1) && selectedStack !== null) { - const originalSize = stacks[selectedStack]; - setSplitSize2((originalSize - size1).toString()); - } - }; + setHoveredStack(null); + setHoveredSplitPoint(null); + }, [stacks, hoveredStack, hoveredSplitPoint]); const getStackColor = (size: number) => { if (size === 1) return 'bg-gray-200'; @@ -108,25 +80,54 @@ const StackingBlocks: React.FC = ({ showSocialShare = false return 'bg-red-200'; }; - const renderStack = (size: number, index: number) => { + const renderStack = (size: number, stackIndex: number) => { const canSplit = size > 1; return ( -
canSplit && handleStackClick(index, size)} - > -
Stack {index + 1}
+
+
Stack {stackIndex + 1}
- {Array.from({ length: size }).map((_, blockIndex) => ( -
- ))} + {Array.from({ length: size }).map((_, blockIndex) => { + const splitPoint = size - blockIndex; // How many blocks would be in the top stack if we split here + const bottomSize = blockIndex + 1; // How many blocks would be in the bottom stack + const pointsGained = canSplit && splitPoint > 0 && bottomSize > 0 ? splitPoint * bottomSize : 0; + const isHovered = hoveredStack === stackIndex && hoveredSplitPoint === splitPoint; + const showSplitLine = canSplit && splitPoint > 0 && bottomSize > 0 && isHovered; + + return ( + + + +
0 && bottomSize > 0 ? 'cursor-pointer hover:brightness-90' : '' + } ${showSplitLine ? 'border-t-4 border-t-red-500' : ''} relative`} + style={{ marginBottom: '-1px' }} + onMouseEnter={() => { + if (canSplit && splitPoint > 0 && bottomSize > 0) { + setHoveredStack(stackIndex); + setHoveredSplitPoint(splitPoint); + } + }} + onMouseLeave={() => { + setHoveredStack(null); + setHoveredSplitPoint(null); + }} + onClick={() => { + if (canSplit && splitPoint > 0 && bottomSize > 0) { + handleStackClick(stackIndex, splitPoint); + } + }} + /> + + {canSplit && pointsGained > 0 && ( + +

Split into {splitPoint} + {bottomSize} = {pointsGained} points

+
+ )} + + + ); + })}
Size: {size}
@@ -189,7 +190,7 @@ const StackingBlocks: React.FC = ({ showSocialShare = false ) : ( <>
- Click on any stack with more than 1 block to split it + Hover over a stack to see where it will split, then click to execute
@@ -202,62 +203,6 @@ const StackingBlocks: React.FC = ({ showSocialShare = false - - - - Split Stack - -
- {selectedStack !== null && ( - <> -
- Splitting stack of size {stacks[selectedStack]} into two stacks: -
-
-
- - handleSplit1Change(e.target.value)} - /> -
-
- - -
-
- {splitSize1 && splitSize2 && ( -
- Points gained: {parseInt(splitSize1) * parseInt(splitSize2)} -
- )} -
- - -
- - )} -
-
-
{showSocialShare && (