From 72c5379706f5a11997f0d739114107b28cd0d792 Mon Sep 17 00:00:00 2001 From: Michele Date: Mon, 6 Apr 2026 01:26:38 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20clickable=20character=20cards,=20defaul?= =?UTF-8?q?t=20character,=20rename=20Archivio=20=E2=86=92=20Libreria?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CharacterList: entire card is clickable to enter edit mode - CharacterList: uses ConfirmModal for delete (replaces browser confirm) - CharacterList: action buttons stop propagation to avoid double-nav - ContentPage: auto-selects first active character as default - Rename "Archivio Contenuti" → "Libreria Contenuti" everywhere - Mobile-safe grid for character cards Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/components/CharacterList.jsx | 33 +++++++++++++++------- frontend/src/components/ContentArchive.jsx | 6 ++-- frontend/src/components/ContentPage.jsx | 14 +++++++-- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/CharacterList.jsx b/frontend/src/components/CharacterList.jsx index 99397a3..d3afa75 100644 --- a/frontend/src/components/CharacterList.jsx +++ b/frontend/src/components/CharacterList.jsx @@ -1,10 +1,13 @@ import { useState, useEffect } from 'react' -import { Link } from 'react-router-dom' +import { Link, useNavigate } from 'react-router-dom' import { api } from '../api' +import ConfirmModal from './ConfirmModal' export default function CharacterList() { const [characters, setCharacters] = useState([]) const [loading, setLoading] = useState(true) + const [deleteTarget, setDeleteTarget] = useState(null) + const navigate = useNavigate() useEffect(() => { loadCharacters() }, []) @@ -13,9 +16,10 @@ export default function CharacterList() { api.get('/characters/').then(setCharacters).catch(() => {}).finally(() => setLoading(false)) } - const handleDelete = async (id, name) => { - if (!confirm(`Eliminare "${name}"?`)) return - await api.delete(`/characters/${id}`) + const handleDelete = async () => { + if (!deleteTarget) return + await api.delete(`/characters/${deleteTarget.id}`) + setDeleteTarget(null) loadCharacters() } @@ -52,20 +56,30 @@ export default function CharacterList() { to="/characters/new" /> ) : ( -
+
{characters.map((c) => ( - + setDeleteTarget({ id, name })} onToggle={handleToggle} onNavigate={() => navigate(`/characters/${c.id}/edit`)} /> ))}
)} + setDeleteTarget(null)} + />
) } -function CharacterCard({ character: c, onDelete, onToggle }) { +function CharacterCard({ character: c, onDelete, onToggle, onNavigate }) { const color = c.visual_style?.primary_color || 'var(--accent)' return ( -
e.currentTarget.style.borderColor = 'var(--accent)'} onMouseLeave={e => e.currentTarget.style.borderColor = 'var(--border)'} > @@ -99,8 +113,7 @@ function CharacterCard({ character: c, onDelete, onToggle }) {

)} -
- Modifica +
e.stopPropagation()}>
diff --git a/frontend/src/components/ContentArchive.jsx b/frontend/src/components/ContentArchive.jsx index 5b218af..ec431c2 100644 --- a/frontend/src/components/ContentArchive.jsx +++ b/frontend/src/components/ContentArchive.jsx @@ -87,12 +87,12 @@ export default function ContentArchive() {
- Archivio + Libreria

- Archivio Contenuti + Libreria Contenuti

-

Tutti i contenuti generati

+

I tuoi contenuti generati

← Genera nuovo diff --git a/frontend/src/components/ContentPage.jsx b/frontend/src/components/ContentPage.jsx index f2ca515..a7cc119 100644 --- a/frontend/src/components/ContentPage.jsx +++ b/frontend/src/components/ContentPage.jsx @@ -69,14 +69,22 @@ export default function ContentPage() { api.get('/characters/').then(d => { setCharacters(d) setCharsLoading(false) + + // Auto-select default character (first active one) + const activeChars = d.filter(c => c.is_active) + const defaultChar = activeChars.length > 0 ? String(activeChars[0].id) : '' + // One-click flow: pre-fill from URL params const urlTopic = searchParams.get('topic') const urlCharacter = searchParams.get('character') if (urlTopic && d.length > 0) { - const charId = urlCharacter || String(d[0].id) + const charId = urlCharacter || defaultChar setForm(prev => ({ ...prev, character_id: charId, topic_hint: urlTopic })) autoGenerateRef.current = true - setSearchParams({}, { replace: true }) // clean URL + setSearchParams({}, { replace: true }) + } else if (defaultChar) { + // Pre-select default character + setForm(prev => ({ ...prev, character_id: prev.character_id || defaultChar })) } }).catch(() => setCharsLoading(false)) }, []) @@ -205,7 +213,7 @@ export default function ContentPage() { Definisci un brief editoriale, scegli piattaforma e tipo, poi genera. L'AI terrà conto del tono e dei topic del personaggio selezionato.

- Archivio → + Libreria →