feat(todos): favicon maison + mode édition double-tap/double-clic
- Favicon SVG maison Gruvbox orange sur fond sombre - TodoForm accepte initialValues et submitLabel pour l'édition - SwipeableRow détecte le double-tap (< 300ms, sans déplacement) - TodosPage : double-tap mobile / double-clic laptop ouvre l'édition Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,8 @@ import { fetchTodos, createTodo, updateTodo, deleteTodo, postponeTodo } from '..
|
||||
import SwipeableRow from '../components/todos/SwipeableRow'
|
||||
import TodoForm from '../components/todos/TodoForm'
|
||||
|
||||
type EditingTodo = Todo | null
|
||||
|
||||
const DOMAINS = [
|
||||
'informatique', 'diy', 'electronique', 'domotique',
|
||||
'bricolage', 'jardin', 'cuisine', 'voyage', 'animaux',
|
||||
@@ -31,6 +33,7 @@ export default function TodosPage() {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [showForm, setShowForm] = useState(false)
|
||||
const [editingTodo, setEditingTodo] = useState<EditingTodo>(null)
|
||||
const [filters, setFilters] = useState<TodoFilters>({ status: 'pending' })
|
||||
|
||||
const load = useCallback(async () => {
|
||||
@@ -57,6 +60,16 @@ export default function TodosPage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleUpdate(id: string, data: TodoCreate) {
|
||||
try {
|
||||
await updateTodo(id, data)
|
||||
setEditingTodo(null)
|
||||
void load()
|
||||
} catch {
|
||||
setError('Erreur lors de la mise à jour')
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDone(id: string) {
|
||||
try {
|
||||
await updateTodo(id, { status: 'done' })
|
||||
@@ -148,6 +161,30 @@ export default function TodosPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Formulaire d'édition */}
|
||||
{editingTodo && (
|
||||
<div className="glass" style={{ padding: 16, borderRadius: 10, marginBottom: 16, borderLeft: '3px solid var(--accent)' }}>
|
||||
<p style={{ color: 'var(--ink-3)', fontSize: 11, fontFamily: 'var(--font-ui)', marginBottom: 8, textTransform: 'uppercase', letterSpacing: 1 }}>
|
||||
Modifier la tâche
|
||||
</p>
|
||||
<TodoForm
|
||||
onSubmit={data => handleUpdate(editingTodo.id, data)}
|
||||
onCancel={() => setEditingTodo(null)}
|
||||
extended
|
||||
submitLabel="Enregistrer"
|
||||
initialValues={{
|
||||
title: editingTodo.title,
|
||||
domain: editingTodo.domain ?? undefined,
|
||||
priority: editingTodo.priority,
|
||||
due_date: editingTodo.due_date ?? undefined,
|
||||
body: editingTodo.body ?? undefined,
|
||||
url: editingTodo.url ?? undefined,
|
||||
tags: editingTodo.tags,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loading && (
|
||||
<p style={{ color: 'var(--ink-3)', textAlign: 'center', padding: 24 }}>Chargement…</p>
|
||||
)}
|
||||
@@ -177,6 +214,7 @@ export default function TodosPage() {
|
||||
<SwipeableRow
|
||||
key={todo.id}
|
||||
onSwipeRight={() => void handleDone(todo.id)}
|
||||
onDoubleTap={() => setEditingTodo(todo)}
|
||||
rightContent={
|
||||
<div style={{ display: 'flex', gap: 4, padding: '0 8px' }}>
|
||||
<button
|
||||
@@ -265,7 +303,11 @@ export default function TodosPage() {
|
||||
background: idx % 2 === 0 ? 'transparent' : 'rgba(0,0,0,0.1)',
|
||||
}}
|
||||
>
|
||||
<td style={{ padding: '10px 14px', color: 'var(--ink-1)', maxWidth: 280 }}>
|
||||
<td
|
||||
style={{ padding: '10px 14px', color: 'var(--ink-1)', maxWidth: 280, cursor: 'pointer' }}
|
||||
onDoubleClick={() => setEditingTodo(todo)}
|
||||
title="Double-clic pour modifier"
|
||||
>
|
||||
<div style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
||||
{todo.title}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user