From de43eb05d2e43ab31effce3dcca62ad91a556b26 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Sun, 5 Oct 2025 16:42:02 -0700 Subject: Init --- src/components/LoadScreen.tsx | 164 ++++++++++++++++++++++++ src/components/SaveModal.tsx | 79 ++++++++++++ src/components/grid/Cell.tsx | 11 +- src/components/grid/GridComponent.tsx | 37 +++++- src/components/toolbar/ColorSwatch.tsx | 227 +++++++++++++++++++++++++++++++++ src/components/toolbar/Toolbar.tsx | 9 ++ src/components/toolbar/ToolbarItem.tsx | 57 +++++++++ 7 files changed, 579 insertions(+), 5 deletions(-) create mode 100644 src/components/LoadScreen.tsx create mode 100644 src/components/SaveModal.tsx create mode 100644 src/components/toolbar/ColorSwatch.tsx create mode 100644 src/components/toolbar/Toolbar.tsx create mode 100644 src/components/toolbar/ToolbarItem.tsx (limited to 'src/components') diff --git a/src/components/LoadScreen.tsx b/src/components/LoadScreen.tsx new file mode 100644 index 0000000..e51ff6a --- /dev/null +++ b/src/components/LoadScreen.tsx @@ -0,0 +1,164 @@ +import React, { useState } from 'react'; +import type { Grid } from '@/types/grid'; +import { getSavedArt, deleteSavedArt, type SavedArt } from '@/utils/storage'; +import { GridComponent } from './grid/GridComponent'; +import { gridFromAscii } from '@/utils/grid'; + +const demoArt = [ + { name: '🎨 Butterfly', art: `| | +| ⠀⠀⠀⠀⊹ | +| ⢶⢻⣑⣒⢤⡀⠀⢄⠀⠀⡠⠀⢀⡤⣆⣊⡿⡷ | +| ⠀⠹⠹⣚⣣⠻⣦⡀⠀⠀⢀⣴⠟⣸⢓⢎⠏⠀ | +| ⠀⠀⢡⣱⣖⣢⡾⢿⣾⣷⡿⢷⣖⣒⣎⡎⠀⠀ | +| ⠀⠀⠀⣠⠓⢬⠅⡺⢻⡟⢗⠨⡥⠚⣄⠀⠀⠀ | +| ⠀⠀⠀⣿⡆⠘⠆⢇⢸⡇⠸⠰⠃⢰⣿⠀⠀⠀ | +| ⠀⠀⠀⠐⡻⣮⣬⠞⠈⠁⠳⣤⣴⢿⠂⠀⠀⠀ | +| ⠀⠀⠀⡜⠀⠁⠉⠀⠀⠀⠀⠈⠈⠀⢣⠀⠀⠀ | +| ⊹ | +| |` }, + { name: '😊 Smiley', art: ` ████████ + ██ ██ + ██ ██ ██ ██ +██ ██ +██ ██ ██ ██ +██ ██ + ██ ██████████ ██ + ██ ██ + ████████ ` }, + { name: '🌟 Star', art: ` ★ + ███ + █████ + ███████ +█████████ + ███████ + █████ + ███ + █ ` }, +]; + +interface LoadScreenProps { + onLoad: (grid: Grid) => void; + onNew: () => void; + onPaste: (ansiText: string) => void; +} + +export const LoadScreen: React.FC = ({ onLoad, onNew, onPaste }) => { + const [saves] = useState(getSavedArt()); + const [pasteText, setPasteText] = useState(''); + + const handleDemoLoad = (art: string) => { + const grid = gridFromAscii(art); + onLoad(grid); + }; + + const formatDate = (timestamp: number) => { + const date = new Date(timestamp); + return date.toLocaleString(); + }; + + const handleDelete = (id: string, e: React.MouseEvent) => { + e.stopPropagation(); + deleteSavedArt(id); + window.location.reload(); + }; + + const handlePaste = () => { + if (pasteText.trim()) { + onPaste(pasteText.trim()); + } + }; + + return ( +
+

ANSI Color Paint

+ +
+

Demo Templates

+
+ {demoArt.map((demo, idx) => ( + + ))} +
+
+ +
+

Recent Saves

+ {saves.length > 0 ? ( +
+ {saves.map((save) => ( +
onLoad(save.grid)} + style={{ + border: '2px solid var(--regular3)', + borderRadius: '4px', + padding: '1rem', + cursor: 'pointer', + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + transition: 'border-color 0.2s', + }} + onMouseEnter={(e) => { + e.currentTarget.style.borderColor = 'var(--regular6)'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.borderColor = 'var(--regular3)'; + }} + > +
+
+ {save.name} +
+
+ {formatDate(save.timestamp)} +
+
+ +
+ ))} +
+ ) : ( +

No saves yet

+ )} +
+ +
+

Import from ANSI Text

+