import { GridComponent } from '@/components/grid/GridComponent'; import { ColorSwatch } from '@/components/toolbar/ColorSwatch'; import { Toolbar } from '@/components/toolbar/Toolbar'; import { ToolbarItem } from '@/components/toolbar/ToolbarItem'; import { SaveModal } from '@/components/SaveModal'; import type { AnsiTermColor, Grid, GridCell } from '@/types/grid'; import { gridToAnsi } from '@/utils/grid'; import { saveArt } from '@/utils/storage'; import { type IZipper, ListZipper } from '@emprespresso/pengueno'; import { useCallback, useEffect, useState } from 'react'; import { flushSync } from 'react-dom'; export interface ChooseArtProps { grid: Grid; onGoHome?: () => void; } // Gruvbox theme colors converted to ANSI RGB values const defaultColors: AnsiTermColor[] = [ { foreground: { r: 5, g: 5, b: 5 }, background: null }, // bright7 #ebdbb2 { foreground: { r: 5, g: 1, b: 1 }, background: null }, // regular1 #cc241d { foreground: { r: 4, g: 4, b: 1 }, background: null }, // regular2 #98971a { foreground: { r: 5, g: 4, b: 1 }, background: null }, // regular3 #d79921 { foreground: { r: 2, g: 3, b: 4 }, background: null }, // regular4 #458588 { foreground: { r: 4, g: 2, b: 3 }, background: null }, // regular5 #b16286 { foreground: { r: 3, g: 4, b: 3 }, background: null }, // regular6 #689d6a { foreground: { r: 4, g: 4, b: 3 }, background: null }, // regular7 #a89984 ]; export const Paint: React.FC = ({ grid, onGoHome }) => { const [showSaveModal, setShowSaveModal] = useState(false); const [selectedColor, setSelectedColor] = useState({ foreground: { r: 5, g: 5, b: 5 }, background: null, }); const [history, setHistory] = useState>( ListZipper.from([grid]), ); const [isDragging, setIsDragging] = useState(false); const [workingGrid, setWorkingGrid] = useState(grid); const handleDragStart = useCallback(() => { setIsDragging(true); // Don't reset workingGrid here - let it accumulate changes }, []); const handleDragEnd = useCallback(() => { if (isDragging) { // Commit the working grid to history as a single atomic operation setHistory((currentHistory) => { return currentHistory.prepend(workingGrid).previous().get(); }); setIsDragging(false); } }, [isDragging, workingGrid]); const cellInteractionCallback = useCallback( (cell: GridCell) => { flushSync(() => { setWorkingGrid((currentGrid) => { const newGrid = currentGrid.map((row) => [...row]); newGrid[cell.y][cell.x] = { ...cell, color: selectedColor }; return newGrid; }); }); }, [selectedColor], ); const handleSave = (name: string) => { const currentGrid = history.read().get(); saveArt(name, currentGrid); }; const currentGrid = workingGrid; const ansiOutput = gridToAnsi(currentGrid); return (
{showSaveModal && ( setShowSaveModal(false)} /> )} ( )} > 🎨 it.read()) .present() } onClick={() => { setHistory((history) => { const newHistory = history.previous().get(); setWorkingGrid(newHistory.read().get()); return newHistory; }); }} > ↷ it.read()) .present() } onClick={() => { setHistory((history) => { const newHistory = history.next().get(); setWorkingGrid(newHistory.read().get()); return newHistory; }); }} > ↶ setShowSaveModal(true)}> 💾 🏠
); };