Refactor drag and drop for mobile

Replaced drag and drop functionality with a click-to-select and click-to-drop interaction for mobile friendliness. When a box in the container is clicked, columns become highlighted and clickable. Clicking a column drops the box there, and the columns return to their default state. Existing features like double-clicking and desktop drag-and-drop remain.
This commit is contained in:
gpt-engineer-app[bot] 2025-08-22 04:57:14 +00:00
parent 1700a6f984
commit cbe2461204

View file

@ -24,6 +24,7 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
const [highlightedBoxes, setHighlightedBoxes] = useState<Set<number>>(new Set()); const [highlightedBoxes, setHighlightedBoxes] = useState<Set<number>>(new Set());
const [isAnimating, setIsAnimating] = useState(false); const [isAnimating, setIsAnimating] = useState(false);
const [lastUsedColumn, setLastUsedColumn] = useState<number | null>(null); const [lastUsedColumn, setLastUsedColumn] = useState<number | null>(null);
const [selectedBoxForMove, setSelectedBoxForMove] = useState<number | null>(null);
const totalBoxes = (n * (n + 1)) / 2; const totalBoxes = (n * (n + 1)) / 2;
@ -98,6 +99,33 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
setDraggedBox(null); setDraggedBox(null);
}; };
const handleBoxClick = (boxId: number) => {
const box = boxes.find(b => b.id === boxId);
if (!box || box.columnIndex !== null || isPlaying) return;
// Select box for moving
setSelectedBoxForMove(boxId);
};
const handleColumnClick = (e: React.MouseEvent, columnIndex: number) => {
e.stopPropagation();
if (selectedBoxForMove === null || isPlaying) return;
// Move selected box to this column
setColumns(prev => prev.map((col, idx) =>
idx === columnIndex ? [...col, selectedBoxForMove] : col
));
// Update box location
setBoxes(prev => prev.map(b =>
b.id === selectedBoxForMove ? { ...b, columnIndex } : b
));
// Track last used column and clear selection
setLastUsedColumn(columnIndex);
setSelectedBoxForMove(null);
};
const handleDoubleClick = (boxId: number) => { const handleDoubleClick = (boxId: number) => {
const box = boxes.find(b => b.id === boxId); const box = boxes.find(b => b.id === boxId);
if (!box) return; if (!box) return;
@ -258,8 +286,14 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
const containerBoxes = boxes.filter(box => box.columnIndex === null); const containerBoxes = boxes.filter(box => box.columnIndex === null);
const handleBackgroundClick = () => {
if (selectedBoxForMove !== null) {
setSelectedBoxForMove(null);
}
};
return ( return (
<div className="max-w-6xl mx-auto p-6 space-y-8"> <div className="max-w-6xl mx-auto p-6 space-y-8" onClick={handleBackgroundClick}>
<div className="text-center space-y-4"> <div className="text-center space-y-4">
<h1 className="text-4xl font-bold text-foreground">Bulgarian Solitaire</h1> <h1 className="text-4xl font-bold text-foreground">Bulgarian Solitaire</h1>
<p className="text-muted-foreground text-lg max-w-3xl mx-auto"> <p className="text-muted-foreground text-lg max-w-3xl mx-auto">
@ -302,7 +336,10 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
draggable={!isPlaying} draggable={!isPlaying}
onDragStart={(e) => handleDragStart(e, box.id)} onDragStart={(e) => handleDragStart(e, box.id)}
onDoubleClick={() => handleDoubleClick(box.id)} onDoubleClick={() => handleDoubleClick(box.id)}
className="w-8 h-8 bg-primary rounded cursor-move hover:bg-primary/80 transition-colors" onClick={() => handleBoxClick(box.id)}
className={`w-8 h-8 bg-primary rounded cursor-pointer hover:bg-primary/80 transition-colors ${
selectedBoxForMove === box.id ? 'ring-2 ring-blue-500 ring-offset-2' : ''
}`}
> >
</div> </div>
))} ))}
@ -325,7 +362,10 @@ const BulgarianSolitaire: React.FC<BulgarianSolitaireProps> = ({ showSocialShare
key={index} key={index}
onDragOver={handleDragOver} onDragOver={handleDragOver}
onDrop={(e) => handleDrop(e, index)} onDrop={(e) => handleDrop(e, index)}
className="border border-muted-foreground rounded-lg min-h-[100px] w-12 p-1 bg-background/50 flex flex-col-reverse gap-1 transition-all duration-500" onClick={(e) => handleColumnClick(e, index)}
className={`border rounded-lg min-h-[100px] w-12 p-1 bg-background/50 flex flex-col-reverse gap-1 transition-all duration-500 ${
selectedBoxForMove !== null ? 'border-blue-500 border-2 cursor-pointer hover:bg-blue-50' : 'border-muted-foreground'
}`}
style={{ flexBasis: `calc(${100/15}% - 0.25rem)`, minWidth: '48px' }} style={{ flexBasis: `calc(${100/15}% - 0.25rem)`, minWidth: '48px' }}
> >
<div className="text-xs text-center text-muted-foreground mb-1 transform rotate-0"> <div className="text-xs text-center text-muted-foreground mb-1 transform rotate-0">