Add multi-cart UI, image caching, copy/paste, and mobile layout fixes

- Multi-cart system with create, rename, delete, import/export
- Sections with copy/paste items via clipboard JSON
- IndexedDB image cache with deduplication and unused-image pruning
- Migrate existing localStorage base64 images to IndexedDB on load
- Mobile-responsive header and cart bar
- Template row with pill buttons replacing dropdown select
- Cart rename via double-click inline edit
- Storage quota error handling with user-facing banner
- Updated README and page title/description
This commit is contained in:
2026-04-20 01:00:48 +02:00
parent 1f21d857e4
commit 70315a3fd1
8 changed files with 310 additions and 51 deletions
+3 -2
View File
@@ -52,7 +52,7 @@ export default function App() {
const importRef = useRef<HTMLInputElement>(null)
const { catalog, loading: catalogLoading, error: catalogError } = useCatalog()
const { carts, activeCart, activeId, setActiveCart, createCart, deleteCart, renameCart, importCart, exportCart, addSection, removeSection, renameSection, addItem, updateItem, removeItem } = useCarts()
const { carts, activeCart, activeId, storageError, setActiveCart, createCart, deleteCart, renameCart, importCart, exportCart, addSection, removeSection, renameSection, addItem, updateItem, removeItem } = useCarts()
function commitCartRename() {
if (renamingCartId && renameCartValue.trim()) renameCart(renamingCartId, renameCartValue.trim())
@@ -169,7 +169,7 @@ export default function App() {
const file = e.target.files?.[0]
if (!file) return
file.text().then(json => {
if (!importCart(json)) alert('Invalid cart file.')
importCart(json).then(ok => { if (!ok) alert('Invalid cart file.') })
})
e.target.value = ''
}}
@@ -201,6 +201,7 @@ export default function App() {
<main className="mx-auto flex max-w-2xl flex-col gap-4 px-4 py-6">
{catalogLoading && <p className="py-12 text-center text-sm" style={{ color: 'var(--color-grey)' }}>Loading</p>}
{catalogError && <p className="py-12 text-center text-sm" style={{ color: 'var(--color-red)' }}>{catalogError}</p>}
{storageError && <p className="rounded-lg border px-4 py-3 text-sm" style={{ color: 'var(--color-red)', borderColor: 'var(--color-red)', background: 'var(--color-bg1)' }}>{storageError}</p>}
{!activeCart && !catalogLoading && (
<p className="py-12 text-center text-sm" style={{ color: 'var(--color-grey)' }}>