diff --git a/apps/manacore/apps/web/src/lib/i18n/locales/de.json b/apps/manacore/apps/web/src/lib/i18n/locales/de.json
index e9b7c5d2b..aa524eb2d 100644
--- a/apps/manacore/apps/web/src/lib/i18n/locales/de.json
+++ b/apps/manacore/apps/web/src/lib/i18n/locales/de.json
@@ -187,6 +187,187 @@
"invoices": "Rechnungen",
"no_invoices": "Noch keine Rechnungen vorhanden"
},
+ "todo": {
+ "title": "Todo",
+ "tasks": "Aufgaben",
+ "completed": "erledigt",
+ "overdue": "überfällig",
+ "today": "heute",
+ "inbox": "Inbox",
+ "todayView": "Heute",
+ "upcoming": "Bald fällig",
+ "completedView": "Erledigt",
+ "search": "Suche",
+ "newTask": "Neue Aufgabe",
+ "quickAddPlaceholder": "z.B. 'Meeting morgen um 14 Uhr !hoch #wichtig'",
+ "addTask": "Hinzufügen",
+ "cancel": "Abb.",
+ "syntaxHelp": "Syntax-Hilfe",
+ "noTasks": "Keine Aufgaben",
+ "noTasksInbox": "Inbox ist leer",
+ "noTasksToday": "Keine Aufgaben für heute",
+ "noTasksUpcoming": "Keine anstehenden Aufgaben",
+ "noTasksCompleted": "Noch keine Aufgaben erledigt",
+ "firstTaskHint": "Erstelle deine erste Aufgabe mit dem + Button oben.",
+ "edit": "Bearbeiten",
+ "markDone": "Erledigen",
+ "reopen": "Wieder öffnen",
+ "deleteConfirm": "Wirklich löschen?",
+ "yesDelete": "Ja, löschen",
+ "save": "Speichern",
+ "close": "Schließen",
+ "description": "Beschreibung",
+ "addDescription": "Beschreibung hinzufügen...",
+ "subtasks": "Teilaufgaben",
+ "addSubtask": "Teilaufgabe hinzufügen...",
+ "status": "Status",
+ "statusPending": "Offen",
+ "statusInProgress": "In Arbeit",
+ "statusCompleted": "Erledigt",
+ "statusCancelled": "Abgebrochen",
+ "priority": "Priorität",
+ "priorityUrgent": "Dringend",
+ "priorityHigh": "Hoch",
+ "priorityMedium": "Mittel",
+ "priorityLow": "Niedrig",
+ "dueDate": "Fällig",
+ "time": "Uhrzeit",
+ "startDate": "Start",
+ "recurrence": "Wiederholung",
+ "recurrenceNone": "Keine",
+ "recurrenceDaily": "Täglich",
+ "recurrenceWeekly": "Wöchentlich",
+ "recurrenceMonthly": "Monatlich",
+ "recurrenceYearly": "Jährlich",
+ "reminder": "Erinnerung",
+ "reminderNone": "Keine",
+ "tags": "Tags",
+ "storypoints": "Punkte",
+ "duration": "Dauer",
+ "fun": "Spaß",
+ "projects": "Projekte",
+ "labels": "Labels",
+ "sort": "Sortierung",
+ "sortManual": "Manuell",
+ "sortDueDate": "Fälligkeit",
+ "sortPriority": "Priorität",
+ "sortName": "Name",
+ "sortCreated": "Erstellt",
+ "showCompleted": "Erledigt",
+ "boardView": "Board",
+ "listView": "Liste",
+ "board": {
+ "new": "Neues Board",
+ "edit": "Board bearbeiten",
+ "create": "Board erstellen",
+ "name": "Board-Name...",
+ "groupBy": "Gruppierung",
+ "layout": "Layout",
+ "columns": "Spalten",
+ "addColumn": "Spalte",
+ "columnName": "Spaltenname...",
+ "delete": "Löschen",
+ "noTasks": "Keine Aufgaben",
+ "groupStatus": "Status",
+ "groupPriority": "Priorität",
+ "groupDueDate": "Fälligkeit",
+ "groupTag": "Tag",
+ "groupCustom": "Benutzerdefiniert",
+ "layoutKanban": "Kanban",
+ "layoutGrid": "Grid",
+ "layoutFocus": "Fokus"
+ },
+ "settings": {
+ "title": "Todo Einstellungen",
+ "taskBehavior": "Aufgaben-Verhalten",
+ "defaultPriority": "Standard-Priorität",
+ "defaultDueTime": "Standard-Fälligkeit",
+ "autoArchive": "Auto-Archivierung (Tage)",
+ "viewDisplay": "Ansicht & Darstellung",
+ "defaultView": "Standard-Ansicht",
+ "compactMode": "Kompaktmodus",
+ "showTaskCounts": "Aufgabenzahl anzeigen",
+ "showSubtaskProgress": "Teilaufgaben-Fortschritt",
+ "groupByProject": "Nach Projekt gruppieren",
+ "kanbanSettings": "Kanban Board",
+ "cardSize": "Kartengröße",
+ "cardSizeCompact": "Kompakt",
+ "cardSizeNormal": "Normal",
+ "cardSizeLarge": "Groß",
+ "showLabelsOnCards": "Labels auf Karten",
+ "wipLimit": "WIP-Limit pro Spalte",
+ "notifications": "Benachrichtigungen",
+ "defaultReminder": "Standard-Erinnerung",
+ "dailyDigest": "Tägliche Zusammenfassung",
+ "overdueNotifications": "Überfällig-Benachrichtigungen",
+ "smartDuration": "Smarte Dauer",
+ "smartDurationEnabled": "Smarte Dauer-Schätzung",
+ "defaultTaskDuration": "Standard-Dauer (Min.)",
+ "productivity": "Produktivität",
+ "focusMode": "Fokus-Modus",
+ "pomodoro": "Pomodoro",
+ "dailyGoal": "Tagesziel",
+ "showStreak": "Streak anzeigen",
+ "immersiveMode": "Immersiver Modus",
+ "reset": "Einstellungen zurücksetzen"
+ },
+ "syntaxHelpContent": {
+ "title": "Quick-Add Syntax",
+ "date": "Datum: heute, morgen, nächsten Montag, 15.12.",
+ "time": "Uhrzeit: um 14 Uhr, 14:00",
+ "priority": "Priorität: !hoch, !niedrig, !dringend, !!!",
+ "labels": "Labels: #wichtig #idee",
+ "duration": "Dauer: 30min, 2h, 1.5 Stunden",
+ "recurrence": "Wiederholung: jeden Tag, wöchentlich",
+ "multi": "Mehrere: Task1, danach Task2",
+ "subtasks": "Subtasks: Titel: item1, item2, item3"
+ },
+ "onboarding": {
+ "welcome": "Willkommen bei Todo!",
+ "intro": "Dein persönlicher Aufgabenplaner mit Kanban-Boards, smarter Eingabe und mehr.",
+ "step1Title": "Natürliche Sprache",
+ "step1": "Erstelle Aufgaben wie \"Meeting morgen um 14 Uhr !hoch #arbeit\" — Datum, Priorität und Labels werden automatisch erkannt.",
+ "step2Title": "Kanban-Boards",
+ "step2": "Organisiere deine Aufgaben visuell mit verschiedenen Board-Ansichten: Status, Priorität oder benutzerdefiniert.",
+ "step3Title": "Los geht's!",
+ "step3": "Erstelle deine erste Aufgabe mit dem + Button. Tipps findest du jederzeit über das ? Symbol.",
+ "next": "Weiter",
+ "letsGo": "Los geht's",
+ "getStarted": "Los geht's"
+ },
+ "syntaxHelp": {
+ "title": "Quick-Add Syntax",
+ "description": "Nutze natürliche Sprache, um Aufgaben schnell zu erstellen. Alle Muster werden automatisch erkannt.",
+ "date": "Datum",
+ "dateToday": "Heute",
+ "dateTomorrow": "Morgen",
+ "dateNextWeekday": "Nächster Wochentag",
+ "dateSpecific": "Bestimmtes Datum",
+ "time": "Uhrzeit",
+ "priority": "Priorität",
+ "priorityUrgent": "Dringend",
+ "priorityHigh": "Hoch",
+ "priorityLow": "Niedrig",
+ "labels": "Labels",
+ "labelsAdd": "Tags hinzufügen",
+ "duration": "Dauer",
+ "duration30m": "30 Minuten",
+ "duration2h": "2 Stunden",
+ "duration90m": "90 Minuten",
+ "recurrence": "Wiederholung",
+ "recurrenceDaily": "Täglich",
+ "recurrenceWeekly": "Wöchentlich",
+ "recurrenceMonthly": "Monatlich",
+ "multiTask": "Mehrere Aufgaben",
+ "multiTaskChain": "Aufgaben verketten",
+ "multiTaskSemicolon": "Mit Semikolon trennen",
+ "subtasks": "Subtasks",
+ "subtasksColonComma": "Doppelpunkt + Komma",
+ "exampleTitle": "Beispiel",
+ "exampleInput": "Meeting morgen um 14 Uhr 1h !hoch #arbeit",
+ "exampleOutput": "→ \"Meeting\" am nächsten Tag um 14:00, Dauer 1h, Priorität Hoch, Label \"arbeit\""
+ }
+ },
"app_slider": {
"title": "Teil des Mana Ökosystems",
"memoro_desc": "KI-gestützte Sprachnotizen",
diff --git a/apps/manacore/apps/web/src/lib/i18n/locales/en.json b/apps/manacore/apps/web/src/lib/i18n/locales/en.json
index 2f77ea482..91fbec09a 100644
--- a/apps/manacore/apps/web/src/lib/i18n/locales/en.json
+++ b/apps/manacore/apps/web/src/lib/i18n/locales/en.json
@@ -187,6 +187,187 @@
"invoices": "Invoices",
"no_invoices": "No invoices yet"
},
+ "todo": {
+ "title": "Todo",
+ "tasks": "Tasks",
+ "completed": "completed",
+ "overdue": "overdue",
+ "today": "today",
+ "inbox": "Inbox",
+ "todayView": "Today",
+ "upcoming": "Upcoming",
+ "completedView": "Completed",
+ "search": "Search",
+ "newTask": "New task",
+ "quickAddPlaceholder": "e.g. 'Meeting tomorrow at 2pm !high #important'",
+ "addTask": "Add",
+ "cancel": "Cancel",
+ "syntaxHelp": "Syntax help",
+ "noTasks": "No tasks",
+ "noTasksInbox": "Inbox is empty",
+ "noTasksToday": "No tasks for today",
+ "noTasksUpcoming": "No upcoming tasks",
+ "noTasksCompleted": "No tasks completed yet",
+ "firstTaskHint": "Create your first task with the + button above.",
+ "edit": "Edit",
+ "markDone": "Complete",
+ "reopen": "Reopen",
+ "deleteConfirm": "Really delete?",
+ "yesDelete": "Yes, delete",
+ "save": "Save",
+ "close": "Close",
+ "description": "Description",
+ "addDescription": "Add description...",
+ "subtasks": "Subtasks",
+ "addSubtask": "Add subtask...",
+ "status": "Status",
+ "statusPending": "Open",
+ "statusInProgress": "In Progress",
+ "statusCompleted": "Completed",
+ "statusCancelled": "Cancelled",
+ "priority": "Priority",
+ "priorityUrgent": "Urgent",
+ "priorityHigh": "High",
+ "priorityMedium": "Medium",
+ "priorityLow": "Low",
+ "dueDate": "Due",
+ "time": "Time",
+ "startDate": "Start",
+ "recurrence": "Recurrence",
+ "recurrenceNone": "None",
+ "recurrenceDaily": "Daily",
+ "recurrenceWeekly": "Weekly",
+ "recurrenceMonthly": "Monthly",
+ "recurrenceYearly": "Yearly",
+ "reminder": "Reminder",
+ "reminderNone": "None",
+ "tags": "Tags",
+ "storypoints": "Points",
+ "duration": "Duration",
+ "fun": "Fun",
+ "projects": "Projects",
+ "labels": "Labels",
+ "sort": "Sort",
+ "sortManual": "Manual",
+ "sortDueDate": "Due date",
+ "sortPriority": "Priority",
+ "sortName": "Name",
+ "sortCreated": "Created",
+ "showCompleted": "Completed",
+ "boardView": "Board",
+ "listView": "List",
+ "board": {
+ "new": "New board",
+ "edit": "Edit board",
+ "create": "Create board",
+ "name": "Board name...",
+ "groupBy": "Group by",
+ "layout": "Layout",
+ "columns": "Columns",
+ "addColumn": "Column",
+ "columnName": "Column name...",
+ "delete": "Delete",
+ "noTasks": "No tasks",
+ "groupStatus": "Status",
+ "groupPriority": "Priority",
+ "groupDueDate": "Due date",
+ "groupTag": "Tag",
+ "groupCustom": "Custom",
+ "layoutKanban": "Kanban",
+ "layoutGrid": "Grid",
+ "layoutFocus": "Focus"
+ },
+ "settings": {
+ "title": "Todo Settings",
+ "taskBehavior": "Task Behavior",
+ "defaultPriority": "Default priority",
+ "defaultDueTime": "Default due time",
+ "autoArchive": "Auto-archive (days)",
+ "viewDisplay": "View & Display",
+ "defaultView": "Default view",
+ "compactMode": "Compact mode",
+ "showTaskCounts": "Show task counts",
+ "showSubtaskProgress": "Subtask progress",
+ "groupByProject": "Group by project",
+ "kanbanSettings": "Kanban Board",
+ "cardSize": "Card size",
+ "cardSizeCompact": "Compact",
+ "cardSizeNormal": "Normal",
+ "cardSizeLarge": "Large",
+ "showLabelsOnCards": "Labels on cards",
+ "wipLimit": "WIP limit per column",
+ "notifications": "Notifications",
+ "defaultReminder": "Default reminder",
+ "dailyDigest": "Daily digest",
+ "overdueNotifications": "Overdue notifications",
+ "smartDuration": "Smart Duration",
+ "smartDurationEnabled": "Smart duration estimation",
+ "defaultTaskDuration": "Default duration (min)",
+ "productivity": "Productivity",
+ "focusMode": "Focus mode",
+ "pomodoro": "Pomodoro",
+ "dailyGoal": "Daily goal",
+ "showStreak": "Show streak",
+ "immersiveMode": "Immersive mode",
+ "reset": "Reset settings"
+ },
+ "syntaxHelpContent": {
+ "title": "Quick-Add Syntax",
+ "date": "Date: today, tomorrow, next Monday, Dec 15",
+ "time": "Time: at 2pm, 14:00",
+ "priority": "Priority: !high, !low, !urgent, !!!",
+ "labels": "Labels: #important #idea",
+ "duration": "Duration: 30min, 2h, 1.5 hours",
+ "recurrence": "Recurrence: every day, weekly",
+ "multi": "Multiple: Task1, then Task2",
+ "subtasks": "Subtasks: Title: item1, item2, item3"
+ },
+ "onboarding": {
+ "welcome": "Welcome to Todo!",
+ "intro": "Your personal task planner with Kanban boards, smart input, and more.",
+ "step1Title": "Natural Language",
+ "step1": "Create tasks like \"Meeting tomorrow at 2pm !high #work\" — date, priority and labels are detected automatically.",
+ "step2Title": "Kanban Boards",
+ "step2": "Organize your tasks visually with different board views: status, priority, or custom.",
+ "step3Title": "Let's go!",
+ "step3": "Create your first task with the + button. Tips are always available via the ? icon.",
+ "next": "Next",
+ "letsGo": "Let's go",
+ "getStarted": "Get started"
+ },
+ "syntaxHelp": {
+ "title": "Quick-Add Syntax",
+ "description": "Use natural language to quickly create tasks. All patterns are automatically detected.",
+ "date": "Date",
+ "dateToday": "Today",
+ "dateTomorrow": "Tomorrow",
+ "dateNextWeekday": "Next weekday",
+ "dateSpecific": "Specific date",
+ "time": "Time",
+ "priority": "Priority",
+ "priorityUrgent": "Urgent",
+ "priorityHigh": "High",
+ "priorityLow": "Low",
+ "labels": "Labels",
+ "labelsAdd": "Add tags",
+ "duration": "Duration",
+ "duration30m": "30 minutes",
+ "duration2h": "2 hours",
+ "duration90m": "90 minutes",
+ "recurrence": "Recurrence",
+ "recurrenceDaily": "Daily",
+ "recurrenceWeekly": "Weekly",
+ "recurrenceMonthly": "Monthly",
+ "multiTask": "Multiple tasks",
+ "multiTaskChain": "Chain tasks",
+ "multiTaskSemicolon": "Separate with semicolons",
+ "subtasks": "Subtasks",
+ "subtasksColonComma": "Colon + comma",
+ "exampleTitle": "Example",
+ "exampleInput": "Meeting tomorrow at 2pm 1h !high #work",
+ "exampleOutput": "→ \"Meeting\" tomorrow at 14:00, duration 1h, priority High, label \"work\""
+ }
+ },
"app_slider": {
"title": "Part of the Mana Ecosystem",
"memoro_desc": "AI-powered voice notes",
diff --git a/apps/manacore/apps/web/src/lib/i18n/locales/es.json b/apps/manacore/apps/web/src/lib/i18n/locales/es.json
index 1bc965ef1..1d32cb525 100644
--- a/apps/manacore/apps/web/src/lib/i18n/locales/es.json
+++ b/apps/manacore/apps/web/src/lib/i18n/locales/es.json
@@ -6,6 +6,145 @@
"back": "Atrás",
"loading": "Cargando..."
},
+ "todo": {
+ "title": "Tareas",
+ "tasks": "Tareas",
+ "completed": "completadas",
+ "overdue": "vencidas",
+ "today": "hoy",
+ "inbox": "Bandeja",
+ "todayView": "Hoy",
+ "upcoming": "Próximas",
+ "completedView": "Completadas",
+ "search": "Buscar",
+ "newTask": "Nueva tarea",
+ "quickAddPlaceholder": "ej. 'Reunión mañana a las 14h !alta #importante'",
+ "addTask": "Añadir",
+ "cancel": "Canc.",
+ "syntaxHelp": "Ayuda sintaxis",
+ "noTasks": "Sin tareas",
+ "noTasksInbox": "Bandeja vacía",
+ "noTasksToday": "Sin tareas para hoy",
+ "noTasksUpcoming": "Sin tareas próximas",
+ "noTasksCompleted": "Ninguna tarea completada",
+ "firstTaskHint": "Crea tu primera tarea con el botón + arriba.",
+ "edit": "Editar",
+ "markDone": "Completar",
+ "reopen": "Reabrir",
+ "deleteConfirm": "¿Eliminar?",
+ "yesDelete": "Sí, eliminar",
+ "save": "Guardar",
+ "close": "Cerrar",
+ "description": "Descripción",
+ "addDescription": "Añadir descripción...",
+ "subtasks": "Subtareas",
+ "addSubtask": "Añadir subtarea...",
+ "status": "Estado",
+ "statusPending": "Abierta",
+ "statusInProgress": "En curso",
+ "statusCompleted": "Completada",
+ "statusCancelled": "Cancelada",
+ "priority": "Prioridad",
+ "priorityUrgent": "Urgente",
+ "priorityHigh": "Alta",
+ "priorityMedium": "Media",
+ "priorityLow": "Baja",
+ "dueDate": "Vence",
+ "time": "Hora",
+ "startDate": "Inicio",
+ "recurrence": "Recurrencia",
+ "recurrenceNone": "Ninguna",
+ "recurrenceDaily": "Diario",
+ "recurrenceWeekly": "Semanal",
+ "recurrenceMonthly": "Mensual",
+ "recurrenceYearly": "Anual",
+ "reminder": "Recordatorio",
+ "reminderNone": "Ninguno",
+ "tags": "Tags",
+ "storypoints": "Puntos",
+ "duration": "Duración",
+ "fun": "Diversión",
+ "projects": "Proyectos",
+ "labels": "Etiquetas",
+ "sort": "Ordenar",
+ "sortManual": "Manual",
+ "sortDueDate": "Vencimiento",
+ "sortPriority": "Prioridad",
+ "sortName": "Nombre",
+ "sortCreated": "Creación",
+ "showCompleted": "Completadas",
+ "boardView": "Board",
+ "listView": "Lista",
+ "board": {
+ "new": "Nuevo board",
+ "edit": "Editar board",
+ "create": "Crear board",
+ "name": "Nombre del board...",
+ "groupBy": "Agrupar por",
+ "layout": "Diseño",
+ "columns": "Columnas",
+ "addColumn": "Columna",
+ "columnName": "Nombre de columna...",
+ "delete": "Eliminar",
+ "noTasks": "Sin tareas",
+ "groupStatus": "Estado",
+ "groupPriority": "Prioridad",
+ "groupDueDate": "Vencimiento",
+ "groupTag": "Tag",
+ "groupCustom": "Personalizado",
+ "layoutKanban": "Kanban",
+ "layoutGrid": "Cuadrícula",
+ "layoutFocus": "Enfoque"
+ },
+ "settings": {
+ "title": "Ajustes Todo"
+ },
+ "onboarding": {
+ "welcome": "¡Bienvenido a Todo!",
+ "intro": "Tu planificador de tareas personal con boards Kanban, entrada inteligente y más.",
+ "step1Title": "Lenguaje natural",
+ "step1": "Crea tareas como \"Reunión mañana a las 14h !alta #trabajo\" — fecha, prioridad y etiquetas se detectan automáticamente.",
+ "step2Title": "Boards Kanban",
+ "step2": "Organiza tus tareas visualmente con diferentes vistas: estado, prioridad o personalizado.",
+ "step3Title": "¡Vamos!",
+ "step3": "Crea tu primera tarea con el botón +. Los consejos están disponibles en el icono ?.",
+ "next": "Siguiente",
+ "letsGo": "¡Vamos!",
+ "getStarted": "Empezar"
+ },
+ "syntaxHelp": {
+ "title": "Sintaxis Quick-Add",
+ "description": "Usa lenguaje natural para crear tareas rápidamente.",
+ "date": "Fecha",
+ "dateToday": "Hoy",
+ "dateTomorrow": "Mañana",
+ "dateNextWeekday": "Próximo día",
+ "dateSpecific": "Fecha específica",
+ "time": "Hora",
+ "priority": "Prioridad",
+ "priorityUrgent": "Urgente",
+ "priorityHigh": "Alta",
+ "priorityLow": "Baja",
+ "labels": "Etiquetas",
+ "labelsAdd": "Añadir tags",
+ "duration": "Duración",
+ "duration30m": "30 minutos",
+ "duration2h": "2 horas",
+ "duration90m": "90 minutos",
+ "recurrence": "Recurrencia",
+ "recurrenceDaily": "Diario",
+ "recurrenceWeekly": "Semanal",
+ "recurrenceMonthly": "Mensual",
+ "multiTask": "Múltiples tareas",
+ "multiTaskChain": "Encadenar tareas",
+ "multiTaskSemicolon": "Separar con punto y coma",
+ "subtasks": "Subtareas",
+ "subtasksColonComma": "Dos puntos + coma",
+ "exampleTitle": "Ejemplo",
+ "exampleInput": "Reunión mañana a las 14h 1h !alta #trabajo",
+ "exampleOutput": "→ \"Reunión\" mañana a las 14:00, duración 1h, prioridad Alta, etiqueta \"trabajo\""
+ }
+ },
"app_slider": {
"title": "Parte del ecosistema Mana",
"memoro_desc": "Notas de voz con IA",
diff --git a/apps/manacore/apps/web/src/lib/i18n/locales/fr.json b/apps/manacore/apps/web/src/lib/i18n/locales/fr.json
index ff07f2cfe..fac7caf5a 100644
--- a/apps/manacore/apps/web/src/lib/i18n/locales/fr.json
+++ b/apps/manacore/apps/web/src/lib/i18n/locales/fr.json
@@ -6,6 +6,145 @@
"back": "Retour",
"loading": "Chargement..."
},
+ "todo": {
+ "title": "Tâches",
+ "tasks": "Tâches",
+ "completed": "terminées",
+ "overdue": "en retard",
+ "today": "aujourd'hui",
+ "inbox": "Boîte de réception",
+ "todayView": "Aujourd'hui",
+ "upcoming": "À venir",
+ "completedView": "Terminées",
+ "search": "Recherche",
+ "newTask": "Nouvelle tâche",
+ "quickAddPlaceholder": "ex. 'Réunion demain à 14h !haute #important'",
+ "addTask": "Ajouter",
+ "cancel": "Ann.",
+ "syntaxHelp": "Aide syntaxe",
+ "noTasks": "Aucune tâche",
+ "noTasksInbox": "Boîte de réception vide",
+ "noTasksToday": "Aucune tâche aujourd'hui",
+ "noTasksUpcoming": "Aucune tâche à venir",
+ "noTasksCompleted": "Aucune tâche terminée",
+ "firstTaskHint": "Créez votre première tâche avec le bouton + ci-dessus.",
+ "edit": "Modifier",
+ "markDone": "Terminer",
+ "reopen": "Rouvrir",
+ "deleteConfirm": "Vraiment supprimer ?",
+ "yesDelete": "Oui, supprimer",
+ "save": "Enregistrer",
+ "close": "Fermer",
+ "description": "Description",
+ "addDescription": "Ajouter une description...",
+ "subtasks": "Sous-tâches",
+ "addSubtask": "Ajouter une sous-tâche...",
+ "status": "Statut",
+ "statusPending": "Ouvert",
+ "statusInProgress": "En cours",
+ "statusCompleted": "Terminé",
+ "statusCancelled": "Annulé",
+ "priority": "Priorité",
+ "priorityUrgent": "Urgent",
+ "priorityHigh": "Haute",
+ "priorityMedium": "Moyenne",
+ "priorityLow": "Basse",
+ "dueDate": "Échéance",
+ "time": "Heure",
+ "startDate": "Début",
+ "recurrence": "Récurrence",
+ "recurrenceNone": "Aucune",
+ "recurrenceDaily": "Quotidien",
+ "recurrenceWeekly": "Hebdomadaire",
+ "recurrenceMonthly": "Mensuel",
+ "recurrenceYearly": "Annuel",
+ "reminder": "Rappel",
+ "reminderNone": "Aucun",
+ "tags": "Tags",
+ "storypoints": "Points",
+ "duration": "Durée",
+ "fun": "Fun",
+ "projects": "Projets",
+ "labels": "Labels",
+ "sort": "Tri",
+ "sortManual": "Manuel",
+ "sortDueDate": "Échéance",
+ "sortPriority": "Priorité",
+ "sortName": "Nom",
+ "sortCreated": "Création",
+ "showCompleted": "Terminées",
+ "boardView": "Board",
+ "listView": "Liste",
+ "board": {
+ "new": "Nouveau board",
+ "edit": "Modifier le board",
+ "create": "Créer un board",
+ "name": "Nom du board...",
+ "groupBy": "Grouper par",
+ "layout": "Disposition",
+ "columns": "Colonnes",
+ "addColumn": "Colonne",
+ "columnName": "Nom de colonne...",
+ "delete": "Supprimer",
+ "noTasks": "Aucune tâche",
+ "groupStatus": "Statut",
+ "groupPriority": "Priorité",
+ "groupDueDate": "Échéance",
+ "groupTag": "Tag",
+ "groupCustom": "Personnalisé",
+ "layoutKanban": "Kanban",
+ "layoutGrid": "Grille",
+ "layoutFocus": "Focus"
+ },
+ "settings": {
+ "title": "Paramètres Todo"
+ },
+ "onboarding": {
+ "welcome": "Bienvenue dans Todo !",
+ "intro": "Votre planificateur de tâches personnel avec boards Kanban, saisie intelligente et plus.",
+ "step1Title": "Langage naturel",
+ "step1": "Créez des tâches comme \"Réunion demain à 14h !haute #travail\" — date, priorité et labels sont détectés automatiquement.",
+ "step2Title": "Boards Kanban",
+ "step2": "Organisez vos tâches visuellement avec différentes vues : statut, priorité ou personnalisé.",
+ "step3Title": "C'est parti !",
+ "step3": "Créez votre première tâche avec le bouton +. Des astuces sont disponibles via l'icône ?.",
+ "next": "Suivant",
+ "letsGo": "C'est parti",
+ "getStarted": "Commencer"
+ },
+ "syntaxHelp": {
+ "title": "Syntaxe Quick-Add",
+ "description": "Utilisez le langage naturel pour créer rapidement des tâches.",
+ "date": "Date",
+ "dateToday": "Aujourd'hui",
+ "dateTomorrow": "Demain",
+ "dateNextWeekday": "Prochain jour",
+ "dateSpecific": "Date spécifique",
+ "time": "Heure",
+ "priority": "Priorité",
+ "priorityUrgent": "Urgent",
+ "priorityHigh": "Haute",
+ "priorityLow": "Basse",
+ "labels": "Labels",
+ "labelsAdd": "Ajouter des tags",
+ "duration": "Durée",
+ "duration30m": "30 minutes",
+ "duration2h": "2 heures",
+ "duration90m": "90 minutes",
+ "recurrence": "Récurrence",
+ "recurrenceDaily": "Quotidien",
+ "recurrenceWeekly": "Hebdomadaire",
+ "recurrenceMonthly": "Mensuel",
+ "multiTask": "Tâches multiples",
+ "multiTaskChain": "Enchaîner les tâches",
+ "multiTaskSemicolon": "Séparer par point-virgule",
+ "subtasks": "Sous-tâches",
+ "subtasksColonComma": "Deux-points + virgule",
+ "exampleTitle": "Exemple",
+ "exampleInput": "Réunion demain à 14h 1h !haute #travail",
+ "exampleOutput": "→ \"Réunion\" demain à 14:00, durée 1h, priorité Haute, label \"travail\""
+ }
+ },
"app_slider": {
"title": "Partie de l'écosystème Mana",
"memoro_desc": "Notes vocales IA",
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/MinimizedTabs.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/MinimizedTabs.svelte
new file mode 100644
index 000000000..0cb7c10a5
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/MinimizedTabs.svelte
@@ -0,0 +1,34 @@
+
+
+{#if pages.length > 0}
+
+ {#each pages as page (page.id)}
+
+
+
+
+ {/each}
+
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/OnboardingModal.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/OnboardingModal.svelte
new file mode 100644
index 000000000..dfaf7f1c2
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/OnboardingModal.svelte
@@ -0,0 +1,102 @@
+
+
+{#if open}
+
+
+ e.target === e.currentTarget && finish()}
+ >
+
+
+ {@const CurrentIcon = steps[step].icon}
+
+
+
+
+
{steps[step].title}
+
{steps[step].desc}
+
+
+
+ {#each steps as _, i}
+
+ {/each}
+
+
+
+ {#if step < steps.length - 1}
+
+ {/if}
+
+
+
+
+
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/QuickAddTask.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/QuickAddTask.svelte
new file mode 100644
index 000000000..261da437c
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/QuickAddTask.svelte
@@ -0,0 +1,196 @@
+
+
+{#if isOpen}
+
+
+
+
+ {#if onShowSyntaxHelp}
+
+ {/if}
+
+
+
+
+ {#if parsed.length > 0 && hasParsedMeta}
+
+ {#each parsed as task, i}
+
+ {#if parsed.length > 1}
+
#{i + 1}
+ {/if}
+
{task.title}
+ {#if task.dueDate}
+
+
+ {task.dueDate.toLocaleDateString('de-DE', { day: 'numeric', month: 'short' })}
+ {#if task.dueTime}
+ {task.dueTime}
+ {/if}
+
+ {/if}
+ {#if task.priority}
+
+
+ {task.priority}
+
+ {/if}
+ {#if task.recurrenceRule}
+
+
+
+ {/if}
+ {#if task.estimatedDuration}
+
+
+ {formatDuration(task.estimatedDuration)}
+
+ {/if}
+ {#each task.labelNames as name}
+
+
+ {name}
+
+ {/each}
+
+ {/each}
+
+ {/if}
+
+{:else}
+
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/SubtaskList.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/SubtaskList.svelte
new file mode 100644
index 000000000..127d02cc3
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/SubtaskList.svelte
@@ -0,0 +1,104 @@
+
+
+
+ {#each subtasks as subtask (subtask.id)}
+
+
+
+ {subtask.title}
+
+ {#if !readonly}
+
+ {/if}
+
+ {/each}
+
+ {#if !readonly}
+
+ {/if}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/SyncIndicator.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/SyncIndicator.svelte
new file mode 100644
index 000000000..a003d6ed2
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/SyncIndicator.svelte
@@ -0,0 +1,34 @@
+
+
+
+ {#if status === 'synced'}
+
+
Sync
+ {:else if status === 'syncing'}
+
+
Sync...
+ {:else if status === 'offline'}
+
+
Offline
+ {:else}
+
+
Fehler
+ {/if}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/SyntaxHelpOverlay.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/SyntaxHelpOverlay.svelte
new file mode 100644
index 000000000..a57279f2d
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/SyntaxHelpOverlay.svelte
@@ -0,0 +1,132 @@
+
+
+{#if open}
+
+
+ e.target === e.currentTarget && onClose()}
+ >
+
+
+
{$_('todo.syntaxHelp.title')}
+
+
+
+
+
+ {$_('todo.syntaxHelp.description')}
+
+
+
+ {#each sections as section}
+
+
+ {section.title}
+
+
+ {#each section.examples as example}
+
+
+ {example.input}
+
+ {example.desc}
+
+ {/each}
+
+
+ {/each}
+
+
+
+
{$_('todo.syntaxHelp.exampleTitle')}
+
+ {$_('todo.syntaxHelp.exampleInput')}
+
+
+ {$_('todo.syntaxHelp.exampleOutput')}
+
+
+
+
+
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/TagStrip.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/TagStrip.svelte
new file mode 100644
index 000000000..57bda280c
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/TagStrip.svelte
@@ -0,0 +1,48 @@
+
+
+{#if labels.length > 0 && !collapsed}
+
+ {#if viewStore.currentView === 'label'}
+
+ {/if}
+ {#each labels as label (label.id)}
+
+ {/each}
+
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/TaskEditModal.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/TaskEditModal.svelte
new file mode 100644
index 000000000..2118b34b3
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/TaskEditModal.svelte
@@ -0,0 +1,315 @@
+
+
+
+
+{#if open}
+
+
+
+
+
+
+
+ {#if form.showDeleteConfirm}
+ {$_('todo.deleteConfirm')}
+
+
+ {:else}
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {$_('todo.description')}
+
+
+
+
+ {$_('todo.subtasks')}
+
+
+
+
+
+
+
+
+ {$_('todo.status')}
+
+
+
+
+
+
{$_('todo.priority')}
+
(form.priority = p)} />
+
+
+
+
+ {$_('todo.dueDate')}
+
+
+
+
+
+ {$_('todo.time')}
+
+
+
+
+
+ {$_('todo.startDate')}
+
+
+
+
+
+ {$_('todo.recurrence')}
+
+
+
+
+
+ {$_('todo.reminder')}
+ (form.reminderMinutes = v)}
+ disabled={!form.dueDate}
+ />
+
+
+
+
+ {$_('todo.tags')}
+ (form.selectedLabelIds = ids)}
+ />
+
+
+
+
+ {$_('todo.storypoints')}
+ (form.storyPoints = v)} />
+
+
+
+
+ {$_('todo.duration')}
+ (form.effectiveDuration = v)}
+ />
+
+
+
+
+ {$_('todo.fun')}
+ (form.funRating = v)} />
+
+
+
+
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/TaskItem.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/TaskItem.svelte
new file mode 100644
index 000000000..caea45cf6
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/TaskItem.svelte
@@ -0,0 +1,132 @@
+
+
+
+ {
+ e.preventDefault();
+ onContextMenu(e);
+ }}
+ onkeydown={(e) => e.key === 'Enter' && onClick()}
+>
+
+
+
+
+
+
+ {task.title}
+
+
+
+
+ {#if dueInfo}
+
+
+ {dueInfo.text}
+
+ {/if}
+ {#if task.priority !== 'medium'}
+
+ {getPriorityLabel(task.priority)}
+
+ {/if}
+ {#if subtaskInfo}
+
+
+ {subtaskInfo.done}/{subtaskInfo.total}
+
+ {/if}
+ {#each taskTags as tag (tag.id)}
+
+ {tag.name}
+
+ {/each}
+
+
+
+
+ {#if task.priority === 'urgent' || task.priority === 'high'}
+
+ {/if}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/TaskList.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/TaskList.svelte
new file mode 100644
index 000000000..f0400044a
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/TaskList.svelte
@@ -0,0 +1,172 @@
+
+
+{#if dragEnabled}
+
+ {#each items as task (task.id)}
+
+ tasksStore.toggleComplete(task.id)}
+ onClick={() => onOpenTask(task)}
+ onContextMenu={(e) => handleContextMenu(task, e)}
+ />
+
+ {/each}
+
+{:else}
+
+ {#each tasks as task (task.id)}
+ tasksStore.toggleComplete(task.id)}
+ onClick={() => onOpenTask(task)}
+ onContextMenu={(e) => handleContextMenu(task, e)}
+ />
+ {/each}
+
+{/if}
+
+
+{#if contextMenu}
+
+
+
+
+
+
+
+
+ {$_('todo.priority')}
+
+ {#each ['urgent', 'high', 'medium', 'low'] as p}
+
+ {/each}
+
+
+
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/TodoToolbar.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/TodoToolbar.svelte
new file mode 100644
index 000000000..c57e37ede
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/TodoToolbar.svelte
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+ {#if showSortMenu}
+
+
+
(showSortMenu = false)}>
+
+ {#each sortOptions as opt}
+
+ {/each}
+
+ {/if}
+
+
+
+
+
+
+ {#if showBoardToggle}
+
+ {/if}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/BoardViewRenderer.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/BoardViewRenderer.svelte
new file mode 100644
index 000000000..8759fbdf7
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/BoardViewRenderer.svelte
@@ -0,0 +1,51 @@
+
+
+{#if view.layout === 'grid'}
+
+{:else if view.layout === 'fokus'}
+
+{:else}
+
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/FokusLayout.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/FokusLayout.svelte
new file mode 100644
index 000000000..399c32dce
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/FokusLayout.svelte
@@ -0,0 +1,90 @@
+
+
+
+
+ {#if focusColumn}
+
+
+
+ {focusColumn.name}
+
+
+ {#each focusTasks as task, i (task.id)}
+
+
+
onOpenTask(task)}
+ class="group flex cursor-pointer items-center gap-4 rounded-xl border border-border bg-card p-4 transition-all hover:shadow-md"
+ style="border-left: 4px solid {getPriorityColor(task.priority)}"
+ >
+
+
+
+ {task.title}
+
+ {#if task.description}
+
+ {task.description}
+
+ {/if}
+
+
+
+ {/each}
+
+
+ {/if}
+
+
+ {#each remainingColumns as column (column.id)}
+ {#if column.tasks.length > 0}
+
+
+
+ {column.name}
+ ({column.tasks.length})
+
+
+ {/if}
+ {/each}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/GridLayout.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/GridLayout.svelte
new file mode 100644
index 000000000..7e52308e9
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/GridLayout.svelte
@@ -0,0 +1,47 @@
+
+
+
+ {#each columns as column (column.id)}
+
+
+
+ {column.name}
+ ({column.tasks.length})
+
+
+ {#each column.tasks as task (task.id)}
+
+
+
onOpenTask(task)} class="cursor-pointer">
+ onToggleComplete(task.id)}
+ onSave={(data) => onSaveTask(task.id, data)}
+ onDelete={() => onDeleteTask(task.id)}
+ />
+
+ {/each}
+
+
+ {/each}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/KanbanLayout.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/KanbanLayout.svelte
new file mode 100644
index 000000000..eb7c3000d
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/KanbanLayout.svelte
@@ -0,0 +1,62 @@
+
+
+
+ {#each columns as column (column.id)}
+
+ {/each}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewColumn.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewColumn.svelte
new file mode 100644
index 000000000..b5ec953fe
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewColumn.svelte
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+ {#each items as task (task.id)}
+
+
+
+
onOpenTask(task)} class="cursor-pointer">
+ onToggleComplete(task.id)}
+ onSave={(data) => onSaveTask(task.id, data)}
+ onDelete={() => onDeleteTask(task.id)}
+ />
+
+
+ {/each}
+
+
+
+ onQuickAdd(title, column.id)} />
+
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewColumnHeader.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewColumnHeader.svelte
new file mode 100644
index 000000000..356e16949
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewColumnHeader.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
+ {column.name}
+
+ {column.tasks.length}{wipLimit != null ? `/${wipLimit}` : ''}
+
+
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewEditorModal.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewEditorModal.svelte
new file mode 100644
index 000000000..bea957fa7
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewEditorModal.svelte
@@ -0,0 +1,228 @@
+
+
+{#if open}
+
+
+ e.target === e.currentTarget && onClose()}
+ >
+
+
+
+
+ {view ? $_('todo.board.edit') : $_('todo.board.new')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if view}
+
+ {/if}
+
+
+
+
+
+
+
+
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewSelector.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewSelector.svelte
new file mode 100644
index 000000000..9cee6494e
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/ViewSelector.svelte
@@ -0,0 +1,47 @@
+
+
+
+ {#each views as view (view.id)}
+ {@const Icon = getIcon(view.layout)}
+
+ {/each}
+
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/index.ts b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/index.ts
new file mode 100644
index 000000000..d88f51d7f
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/board-views/index.ts
@@ -0,0 +1,8 @@
+export { default as BoardViewRenderer } from './BoardViewRenderer.svelte';
+export { default as KanbanLayout } from './KanbanLayout.svelte';
+export { default as GridLayout } from './GridLayout.svelte';
+export { default as FokusLayout } from './FokusLayout.svelte';
+export { default as ViewColumn } from './ViewColumn.svelte';
+export { default as ViewColumnHeader } from './ViewColumnHeader.svelte';
+export { default as ViewSelector } from './ViewSelector.svelte';
+export { default as ViewEditorModal } from './ViewEditorModal.svelte';
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/form/DurationPicker.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/form/DurationPicker.svelte
new file mode 100644
index 000000000..15159c99a
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/form/DurationPicker.svelte
@@ -0,0 +1,49 @@
+
+
+
+
+
+ {#each presets as preset}
+
+ {/each}
+
+ {#if value && !presets.some((p) => p.value === value)}
+
{formatDuration(value)}
+ {/if}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/form/FunRatingPicker.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/form/FunRatingPicker.svelte
new file mode 100644
index 000000000..92b628861
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/form/FunRatingPicker.svelte
@@ -0,0 +1,41 @@
+
+
+
+ {#each ratings as r}
+
+ {/each}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/form/PrioritySelector.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/form/PrioritySelector.svelte
new file mode 100644
index 000000000..a72712c71
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/form/PrioritySelector.svelte
@@ -0,0 +1,32 @@
+
+
+
+ {#each priorities as p}
+
+ {/each}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/form/ReminderSelector.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/form/ReminderSelector.svelte
new file mode 100644
index 000000000..8926b4443
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/form/ReminderSelector.svelte
@@ -0,0 +1,37 @@
+
+
+
+
+
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/form/StorypointsSelector.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/form/StorypointsSelector.svelte
new file mode 100644
index 000000000..7a78e2186
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/form/StorypointsSelector.svelte
@@ -0,0 +1,30 @@
+
+
+
+
+
+ {#each points as p}
+
+ {/each}
+
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/form/TagSelector.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/form/TagSelector.svelte
new file mode 100644
index 000000000..183907027
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/form/TagSelector.svelte
@@ -0,0 +1,92 @@
+
+
+
+ {#each selectedLabels as label (label.id)}
+
+ {label.name}
+
+
+ {/each}
+
+
+
+
+ {#if showPicker && availableLabels.length > 0}
+
+
+
+ {#each availableLabels as label (label.id)}
+
+ {/each}
+
+ {/if}
+
+
+
+{#if showPicker}
+
+
+ (showPicker = false)}>
+{/if}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/form/index.ts b/apps/manacore/apps/web/src/lib/modules/todo/components/form/index.ts
new file mode 100644
index 000000000..b770414a5
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/form/index.ts
@@ -0,0 +1,6 @@
+export { default as PrioritySelector } from './PrioritySelector.svelte';
+export { default as TagSelector } from './TagSelector.svelte';
+export { default as ReminderSelector } from './ReminderSelector.svelte';
+export { default as DurationPicker } from './DurationPicker.svelte';
+export { default as StorypointsSelector } from './StorypointsSelector.svelte';
+export { default as FunRatingPicker } from './FunRatingPicker.svelte';
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/KanbanBoardSkeleton.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/KanbanBoardSkeleton.svelte
new file mode 100644
index 000000000..c57f3cf3b
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/KanbanBoardSkeleton.svelte
@@ -0,0 +1,15 @@
+
+
+
+ {#each Array(columns) as _}
+
+ {/each}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/KanbanColumnSkeleton.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/KanbanColumnSkeleton.svelte
new file mode 100644
index 000000000..8c5a919e0
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/KanbanColumnSkeleton.svelte
@@ -0,0 +1,16 @@
+
+
+ {#each Array(3) as _}
+
+ {/each}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/StatisticsSkeleton.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/StatisticsSkeleton.svelte
new file mode 100644
index 000000000..4b5bde739
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/StatisticsSkeleton.svelte
@@ -0,0 +1,5 @@
+
+ {#each Array(4) as _}
+
+ {/each}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/TaskItemSkeleton.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/TaskItemSkeleton.svelte
new file mode 100644
index 000000000..c68bd03bd
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/TaskItemSkeleton.svelte
@@ -0,0 +1,10 @@
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/TaskListSkeleton.svelte b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/TaskListSkeleton.svelte
new file mode 100644
index 000000000..e16ea32a0
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/TaskListSkeleton.svelte
@@ -0,0 +1,15 @@
+
+
+
+ {#each Array(count) as _, i}
+
+ {/each}
+
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/index.ts b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/index.ts
new file mode 100644
index 000000000..266050b38
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/components/skeletons/index.ts
@@ -0,0 +1,5 @@
+export { default as TaskItemSkeleton } from './TaskItemSkeleton.svelte';
+export { default as TaskListSkeleton } from './TaskListSkeleton.svelte';
+export { default as KanbanColumnSkeleton } from './KanbanColumnSkeleton.svelte';
+export { default as KanbanBoardSkeleton } from './KanbanBoardSkeleton.svelte';
+export { default as StatisticsSkeleton } from './StatisticsSkeleton.svelte';
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/composables/useTaskForm.svelte.ts b/apps/manacore/apps/web/src/lib/modules/todo/composables/useTaskForm.svelte.ts
new file mode 100644
index 000000000..5a46954b8
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/composables/useTaskForm.svelte.ts
@@ -0,0 +1,233 @@
+/**
+ * useTaskForm — Shared form state logic for TaskEditModal & inline editing.
+ */
+
+import type { Task, TaskPriority, Subtask } from '../types';
+import { reminderTable } from '../collections';
+
+export interface TaskFormState {
+ title: string;
+ description: string;
+ dueDate: string;
+ dueTime: string;
+ startDate: string;
+ priority: TaskPriority;
+ status: string;
+ selectedLabelIds: string[];
+ subtasks: Subtask[];
+ recurrenceRule: string;
+ storyPoints: number | null;
+ effectiveDuration: number | null;
+ funRating: number | null;
+ reminderMinutes: number | null;
+ showDeleteConfirm: boolean;
+ isLoading: boolean;
+}
+
+export function useTaskForm() {
+ let title = $state('');
+ let description = $state('');
+ let dueDate = $state('');
+ let dueTime = $state('');
+ let startDate = $state('');
+ let priority = $state('medium');
+ let status = $state('pending');
+ let selectedLabelIds = $state([]);
+ let subtasks = $state([]);
+ let recurrenceRule = $state('');
+ let storyPoints = $state(null);
+ let effectiveDuration = $state(null);
+ let funRating = $state(null);
+ let reminderMinutes = $state(null);
+ let showDeleteConfirm = $state(false);
+ let isLoading = $state(false);
+
+ function initFromTask(task: Task) {
+ title = task.title;
+ description = task.description ?? '';
+ dueDate = task.dueDate ? task.dueDate.split('T')[0] : '';
+ dueTime = task.scheduledStartTime ?? '';
+ startDate = task.scheduledDate ? task.scheduledDate.split('T')[0] : '';
+ priority = task.priority;
+ status = task.status;
+ subtasks = task.subtasks ? [...task.subtasks] : [];
+ recurrenceRule = task.recurrenceRule ?? '';
+ effectiveDuration = task.estimatedDuration ?? null;
+ showDeleteConfirm = false;
+ isLoading = false;
+
+ const meta = task.metadata as Record | null;
+ selectedLabelIds = (meta?.labelIds as string[]) ?? [];
+ storyPoints = (meta?.storyPoints as number) ?? null;
+ funRating = (meta?.funRating as number) ?? null;
+ reminderMinutes = null;
+
+ // Load existing reminder
+ loadReminder(task.id);
+ }
+
+ async function loadReminder(taskId: string) {
+ try {
+ const reminders = await reminderTable.where('taskId').equals(taskId).toArray();
+ const active = reminders.find((r) => !r.deletedAt && r.status === 'pending');
+ if (active) {
+ reminderMinutes = active.minutesBefore;
+ }
+ } catch {
+ // Reminders table may not exist yet
+ }
+ }
+
+ function buildUpdatePayload(): Record {
+ const update: Record = {
+ title: title.trim(),
+ description: description || undefined,
+ priority,
+ dueDate: dueDate ? new Date(dueDate).toISOString() : null,
+ scheduledDate: startDate ? new Date(startDate).toISOString() : null,
+ scheduledStartTime: dueTime || null,
+ estimatedDuration: effectiveDuration,
+ recurrenceRule: recurrenceRule || null,
+ subtasks: subtasks.length > 0 ? subtasks : null,
+ isCompleted: status === 'completed',
+ completedAt: status === 'completed' ? new Date().toISOString() : null,
+ metadata: {
+ labelIds: selectedLabelIds,
+ storyPoints,
+ funRating,
+ },
+ };
+ return update;
+ }
+
+ async function persistReminder(taskId: string) {
+ try {
+ // Remove old reminders
+ const existing = await reminderTable.where('taskId').equals(taskId).toArray();
+ for (const r of existing) {
+ if (!r.deletedAt) {
+ await reminderTable.update(r.id, {
+ deletedAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+ });
+ }
+ }
+
+ // Create new if set
+ if (reminderMinutes != null && dueDate) {
+ await reminderTable.add({
+ id: crypto.randomUUID(),
+ taskId,
+ minutesBefore: reminderMinutes,
+ type: 'push',
+ status: 'pending',
+ });
+ }
+ } catch {
+ // Silently ignore if table doesn't exist
+ }
+ }
+
+ return {
+ get title() {
+ return title;
+ },
+ set title(v: string) {
+ title = v;
+ },
+ get description() {
+ return description;
+ },
+ set description(v: string) {
+ description = v;
+ },
+ get dueDate() {
+ return dueDate;
+ },
+ set dueDate(v: string) {
+ dueDate = v;
+ },
+ get dueTime() {
+ return dueTime;
+ },
+ set dueTime(v: string) {
+ dueTime = v;
+ },
+ get startDate() {
+ return startDate;
+ },
+ set startDate(v: string) {
+ startDate = v;
+ },
+ get priority() {
+ return priority;
+ },
+ set priority(v: TaskPriority) {
+ priority = v;
+ },
+ get status() {
+ return status;
+ },
+ set status(v: string) {
+ status = v;
+ },
+ get selectedLabelIds() {
+ return selectedLabelIds;
+ },
+ set selectedLabelIds(v: string[]) {
+ selectedLabelIds = v;
+ },
+ get subtasks() {
+ return subtasks;
+ },
+ set subtasks(v: Subtask[]) {
+ subtasks = v;
+ },
+ get recurrenceRule() {
+ return recurrenceRule;
+ },
+ set recurrenceRule(v: string) {
+ recurrenceRule = v;
+ },
+ get storyPoints() {
+ return storyPoints;
+ },
+ set storyPoints(v: number | null) {
+ storyPoints = v;
+ },
+ get effectiveDuration() {
+ return effectiveDuration;
+ },
+ set effectiveDuration(v: number | null) {
+ effectiveDuration = v;
+ },
+ get funRating() {
+ return funRating;
+ },
+ set funRating(v: number | null) {
+ funRating = v;
+ },
+ get reminderMinutes() {
+ return reminderMinutes;
+ },
+ set reminderMinutes(v: number | null) {
+ reminderMinutes = v;
+ },
+ get showDeleteConfirm() {
+ return showDeleteConfirm;
+ },
+ set showDeleteConfirm(v: boolean) {
+ showDeleteConfirm = v;
+ },
+ get isLoading() {
+ return isLoading;
+ },
+ set isLoading(v: boolean) {
+ isLoading = v;
+ },
+
+ initFromTask,
+ buildUpdatePayload,
+ persistReminder,
+ };
+}
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/index.ts b/apps/manacore/apps/web/src/lib/modules/todo/index.ts
index 9f9dd0eb0..14d7c575a 100644
--- a/apps/manacore/apps/web/src/lib/modules/todo/index.ts
+++ b/apps/manacore/apps/web/src/lib/modules/todo/index.ts
@@ -2,10 +2,17 @@
* Todo module — barrel exports.
*/
+// Stores
export { tasksStore } from './stores/tasks.svelte';
export { boardViewsStore } from './stores/board-views.svelte';
export { viewStore } from './stores/view.svelte';
export { labelsStore } from './stores/labels.svelte';
+export { remindersStore } from './stores/reminders.svelte';
+export { todoSettings } from './stores/settings.svelte';
+export { minimizedPagesStore } from './stores/minimized-pages.svelte';
+export { contactsStore } from './stores/contacts.svelte';
+
+// Queries
export {
useAllTasks,
useAllLabels,
@@ -25,6 +32,8 @@ export {
getPriorityColor,
getTaskStats,
} from './queries';
+
+// Collections
export {
taskTable,
todoProjectTable,
@@ -34,6 +43,26 @@ export {
boardViewTable,
TODO_GUEST_SEED,
} from './collections';
+
+// View Grouping
+export { groupTasksByView, getDropActionUpdate } from './view-grouping';
+export type { GroupedColumn } from './view-grouping';
+
+// Utilities
+export {
+ parseTaskInput,
+ parseMultiTaskInput,
+ resolveTaskIds,
+ formatDuration,
+} from './utils/task-parser';
+export { estimateDuration } from './utils/time-estimator';
+export type { ParsedTask, ParsedTaskWithIds } from './utils/task-parser';
+export type { DurationEstimate } from './utils/time-estimator';
+
+// Composables
+export { useTaskForm } from './composables/useTaskForm.svelte';
+
+// Types
export type {
LocalTask,
LocalLabel,
diff --git a/apps/manacore/apps/web/src/lib/modules/todo/stores/contacts.svelte.ts b/apps/manacore/apps/web/src/lib/modules/todo/stores/contacts.svelte.ts
new file mode 100644
index 000000000..1661df8e7
--- /dev/null
+++ b/apps/manacore/apps/web/src/lib/modules/todo/stores/contacts.svelte.ts
@@ -0,0 +1,66 @@
+/**
+ * Contacts Integration Store — Task assignment via Contacts app.
+ *
+ * Checks if the Contacts module is available and provides search functionality.
+ */
+
+import { db } from '$lib/data/database';
+
+export interface ContactResult {
+ id: string;
+ name: string;
+ email?: string;
+}
+
+let isAvailable = $state(false);
+let cache = $state