diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e1bbc6..0df95e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.36.1] - 2026-04-29 + +### Fixed +- Date input: default date format changed from US (`MM/DD/YYYY`) to day-month-year (`DD.MM.YYYY`) for new users +- Date input: dot-separated dates (`DD.MM.YYYY`) are now accepted in addition to slash-separated dates +- Date input: `dmy` placeholder and display format updated to use dots instead of slashes + +## [0.36.0] - 2026-04-29 + +### Added +- Navigation: Kitchen (Meals/Recipes/Shopping) is now grouped as a single "Küche" entry in the desktop sidebar, consistent with the mobile bottom bar +- UX: empty states in Tasks, Notes, Contacts, Shopping, Recipes and Budget now include a primary CTA button that triggers the page FAB +- UX: `friendlyError(err)` helper added to `window.oikos`; unhandled promise rejections now show status-code-aware messages (offline, forbidden, not found, server error, timeout) instead of raw error text +- i18n: five new `common.error*` keys (offline, forbidden, notFound, server, timeout) added to all 15 locale files + +### Changed +- Navigation: more-button icon changed from `grid-2x2` to `ellipsis` (matches the sheet it opens) +- Navigation: desktop sidebar expands labels at 1 280 px instead of 1 440 px +- UX: search overlay input field is now at the top, results below (standard top-to-bottom scan path) +- UX: touch targets for kitchen tabs and shopping list tabs raised to 44 px (iOS minimum) +- UX: dashboard metric values enlarged to `xl`/`bold` and labels styled as `2xs`/`uppercase` for clearer data hierarchy +- Onboarding: step 2 text and icon updated to accurately describe the navigation structure (···-button and module groups); step 3 text and icon updated to explain the FAB and swipe gestures + ## [0.35.0] - 2026-04-29 ### Added diff --git a/package-lock.json b/package-lock.json index 825c7c9..e22e06c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "oikos", - "version": "0.34.1", + "version": "0.36.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "oikos", - "version": "0.34.1", + "version": "0.36.1", "license": "MIT", "dependencies": { "bcrypt": "^6.0.0", diff --git a/package.json b/package.json index 43a57d8..9f3a45f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oikos", - "version": "0.35.0", + "version": "0.36.1", "description": "Self-hosted family planner - calendar, tasks, shopping, meal planning, budget and more. Private, open-source, no subscription.", "main": "server/index.js", "type": "module", diff --git a/public/i18n.js b/public/i18n.js index 9228070..ee3f587 100644 --- a/public/i18n.js +++ b/public/i18n.js @@ -9,7 +9,7 @@ const SUPPORTED_LOCALES = ['de', 'en', 'es', 'fr', 'it', 'sv', 'el', 'ru', 'tr', const DEFAULT_LOCALE = 'de'; const STORAGE_KEY = 'oikos-locale'; const DATE_FORMAT_KEY = 'oikos-date-format'; -const DEFAULT_DATE_FORMAT = 'mdy'; +const DEFAULT_DATE_FORMAT = 'dmy'; let currentLocale = DEFAULT_LOCALE; let translations = {}; @@ -100,7 +100,7 @@ function formatDateParts(date, useUtc = false) { const month = String((useUtc ? d.getUTCMonth() : d.getMonth()) + 1).padStart(2, '0'); const day = String(useUtc ? d.getUTCDate() : d.getDate()).padStart(2, '0'); switch (getDateFormatPreference()) { - case 'dmy': return `${day}/${month}/${year}`; + case 'dmy': return `${day}.${month}.${year}`; case 'ymd': return `${year}-${month}-${day}`; default: return `${month}/${day}/${year}`; } @@ -127,7 +127,7 @@ export function formatDate(date) { export function dateInputPlaceholder() { switch (getDateFormatPreference()) { - case 'dmy': return 'DD/MM/YYYY'; + case 'dmy': return 'DD.MM.YYYY'; case 'ymd': return 'YYYY-MM-DD'; default: return 'MM/DD/YYYY'; } @@ -145,7 +145,7 @@ export function parseDateInput(value) { const isoMatch = raw.match(/^(\d{4})-(\d{2})-(\d{2})$/); if (isoMatch) return isValidDateParts(isoMatch[1], isoMatch[2], isoMatch[3]) ? raw : ''; - const slashMatch = raw.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/); + const slashMatch = raw.match(/^(\d{1,2})[\/.](\d{1,2})[\/.](\d{4})$/); if (!slashMatch) return ''; const [, first, second, year] = slashMatch; diff --git a/public/locales/ar.json b/public/locales/ar.json index 3bda328..9dc25ef 100644 --- a/public/locales/ar.json +++ b/public/locales/ar.json @@ -29,7 +29,12 @@ "unknownError": "خطأ غير معروف", "confirm": "تأكيد", "undo": "تراجع", - "reset": "إعادة التعيين للأصل" + "reset": "إعادة التعيين للأصل", + "errorOffline": "لا يوجد اتصال بالإنترنت. يرجى التحقق من شبكتك.", + "errorForbidden": "تم رفض الوصول. يرجى تسجيل الدخول مرة أخرى.", + "errorNotFound": "لم يتم العثور على السجل.", + "errorServer": "خطأ في الخادم. يرجى المحاولة لاحقاً.", + "errorTimeout": "استغرق الاتصال وقتاً طويلاً. يرجى المحاولة مجدداً." }, "nav": { "dashboard": "لوحة التحكم", @@ -187,7 +192,8 @@ "archiveButton": "أرشفة المهمة", "archivedToast": "تم أرشفة المهمة.", "kanbanArchived": "مؤرشف", - "reminderNeedsDueDate": "حدّد تاريخ استحقاق لتفعيل تذكيرات المهمة." + "reminderNeedsDueDate": "حدّد تاريخ استحقاق لتفعيل تذكيرات المهمة.", + "emptyAction": "إنشاء مهمة" }, "shopping": { "title": "التسوق", @@ -227,7 +233,8 @@ "catDrinks": "مشروبات", "catHousehold": "مستلزمات المنزل", "catDrugstore": "صيدلية", - "catMisc": "متنوع" + "catMisc": "متنوع", + "emptyAction": "إضافة عنصر" }, "meals": { "title": "خطة الوجبات", @@ -403,7 +410,8 @@ "formatLink": "رابط", "formatCode": "كود", "formatQuote": "اقتباس", - "formatDivider": "فاصل" + "formatDivider": "فاصل", + "emptyAction": "إنشاء ملاحظة" }, "contacts": { "title": "جهات الاتصال", @@ -456,7 +464,8 @@ "categoryInsurance": "تأمين", "categoryCraftsman": "حرفي", "categoryEmergency": "طوارئ", - "categoryOther": "متنوع" + "categoryOther": "متنوع", + "emptyAction": "إضافة جهة اتصال" }, "budget": { "title": "الميزانية", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "إضافة إدخال" }, "settings": { "title": "الإعدادات", @@ -843,7 +853,8 @@ "titleRequired": "العنوان مطلوب", "duplicate": "نسخ", "duplicated": "تم نسخ الوصفة.", - "copySuffix": "نسخة" + "copySuffix": "نسخة", + "emptyAction": "إنشاء وصفة" }, "search": { "title": "بحث", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "التنقل والوحدات", + "step2Body": "في الأسفل يمكنك الوصول مباشرة إلى لوحة التحكم والتقويم. بزر ··· تفتح وحدات أخرى مثل المطبخ والملاحظات وجهات الاتصال.", + "step3Title": "ابدأ بسرعة", + "step3Body": "بزر + الكبير يمكنك إنشاء إدخالات جديدة في أي مكان. اسحب عناصر القائمة يساراً أو يميناً للإجراءات السريعة.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "المطبخ" } -} +} \ No newline at end of file diff --git a/public/locales/de.json b/public/locales/de.json index 91d9f6a..09be1e2 100644 --- a/public/locales/de.json +++ b/public/locales/de.json @@ -29,7 +29,12 @@ "unknownError": "Unbekannter Fehler", "confirm": "Bestätigen", "undo": "Rückgängig", - "reset": "Auf Original zurücksetzen" + "reset": "Auf Original zurücksetzen", + "errorOffline": "Keine Internetverbindung. Bitte prüfe dein Netzwerk.", + "errorForbidden": "Zugriff verweigert. Bitte erneut anmelden.", + "errorNotFound": "Der Eintrag wurde nicht gefunden.", + "errorServer": "Serverfehler. Bitte versuche es später erneut.", + "errorTimeout": "Die Verbindung hat zu lange gedauert. Bitte erneut versuchen." }, "nav": { "dashboard": "Übersicht", @@ -121,6 +126,7 @@ "editTask": "Aufgabe bearbeiten", "emptyTitle": "Keine Aufgaben - alles erledigt?", "emptyDescription": "Neue Aufgaben über den + Button erstellen.", + "emptyAction": "Aufgabe erstellen", "titleLabel": "Titel *", "titlePlaceholder": "Was muss erledigt werden?", "descriptionLabel": "Notiz", @@ -202,6 +208,7 @@ "noListsDescription": "Erstelle eine Liste mit dem + Button.", "emptyList": "Die Liste ist leer", "emptyListDescription": "Artikel über das Eingabefeld oben hinzufügen.", + "emptyAction": "Artikel hinzufügen", "newListPrompt": "Name der neuen Liste:", "newListButton": "Neue Liste erstellen", "renameListPrompt": "Neuer Listen-Name:", @@ -392,6 +399,7 @@ "searchPlaceholder": "Notizen durchsuchen…", "emptyTitle": "Noch keine Notizen", "emptyDescription": "Neue Notiz über den + Button erstellen.", + "emptyAction": "Notiz erstellen", "noResultsTitle": "Keine Treffer", "noResultsDescription": "Keine Notiz enthält \"{{query}}\".", "titleLabel": "Titel (optional)", @@ -442,6 +450,7 @@ "importTooltip": "vCard importieren", "emptyTitle": "Noch keine Kontakte", "emptyDescription": "Neue Kontakte über den + Button hinzufügen.", + "emptyAction": "Kontakt hinzufügen", "filterAll": "Alle", "nameLabel": "Name *", "namePlaceholder": "Vollständiger Name", @@ -499,6 +508,7 @@ "transactions": "Transaktionen", "emptyTitle": "Keine Einträge diesen Monat", "emptyDescription": "Budget-Einträge über den + Button hinzufügen.", + "emptyAction": "Eintrag erstellen", "csvExport": "CSV", "typeExpense": "Ausgabe", "typeIncome": "Einnahme", @@ -912,6 +922,7 @@ "editRecipe": "Rezept bearbeiten", "emptyTitle": "Noch keine Rezepte", "emptyDescription": "Speichere deine Lieblingsrezepte und nutze sie für die Essensplanung.", + "emptyAction": "Rezept erstellen", "titleLabel": "Titel *", "titlePlaceholder": "z. B. Pasta Carbonara", "notesLabel": "Notizen", @@ -933,10 +944,10 @@ "onboarding": { "step1Title": "Willkommen bei Oikos", "step1Body": "Dein persönlicher Familienplaner. Aufgaben, Kalender, Einkauf und mehr – alles an einem Ort.", - "step2Title": "Alles im Blick", - "step2Body": "Über die Navigation unten erreichst du alle Module. Mit dem +-Button erstellst du schnell neue Einträge.", - "step3Title": "Bereit loszulegen", - "step3Body": "Das Dashboard zeigt dir die wichtigsten Infos auf einen Blick. Du kannst es unter \"Anpassen\" nach deinen Wünschen einrichten.", + "step2Title": "Navigation & Module", + "step2Body": "Unten erreichst du Dashboard und Kalender direkt. Mit dem ···-Button öffnest du weitere Module wie Küche, Notizen und Kontakte.", + "step3Title": "Schnell loslegen", + "step3Body": "Mit dem + FAB-Button erstellst du überall neue Einträge. Wische Listeneinträge nach links oder rechts für Schnellaktionen.", "next": "Weiter", "done": "Loslegen", "skip": "Überspringen" diff --git a/public/locales/el.json b/public/locales/el.json index f7d378e..3cd0e17 100644 --- a/public/locales/el.json +++ b/public/locales/el.json @@ -29,7 +29,12 @@ "unknownError": "Άγνωστο σφάλμα", "confirm": "Επιβεβαίωση", "undo": "Αναίρεση", - "reset": "Επαναφορά στο αρχικό" + "reset": "Επαναφορά στο αρχικό", + "errorOffline": "Δεν υπάρχει σύνδεση στο διαδίκτυο. Ελέγξτε το δίκτυό σας.", + "errorForbidden": "Η πρόσβαση απορρίφθηκε. Παρακαλώ συνδεθείτε ξανά.", + "errorNotFound": "Η εγγραφή δεν βρέθηκε.", + "errorServer": "Σφάλμα διακομιστή. Δοκιμάστε ξανά αργότερα.", + "errorTimeout": "Η σύνδεση διήρκεσε πολύ. Παρακαλώ δοκιμάστε ξανά." }, "nav": { "dashboard": "Επισκόπηση", @@ -187,7 +192,8 @@ "archiveButton": "Αρχειοθέτηση εργασίας", "archivedToast": "Η εργασία αρχειοθετήθηκε.", "kanbanArchived": "Αρχειοθετημένο", - "reminderNeedsDueDate": "Ορίστε ημερομηνία λήξης για να ενεργοποιήσετε τις υπενθυμίσεις." + "reminderNeedsDueDate": "Ορίστε ημερομηνία λήξης για να ενεργοποιήσετε τις υπενθυμίσεις.", + "emptyAction": "Δημιουργία εργασίας" }, "shopping": { "title": "Αγορές", @@ -227,7 +233,8 @@ "catDrinks": "Ποτά", "catHousehold": "Οικιακά", "catDrugstore": "Φαρμακείο", - "catMisc": "Διάφορα" + "catMisc": "Διάφορα", + "emptyAction": "Προσθήκη στοιχείου" }, "meals": { "title": "Πρόγραμμα γευμάτων", @@ -403,7 +410,8 @@ "formatLink": "Σύνδεσμος", "formatCode": "Κώδικας", "formatQuote": "Παράθεση", - "formatDivider": "Διαχωριστής" + "formatDivider": "Διαχωριστής", + "emptyAction": "Δημιουργία σημείωσης" }, "contacts": { "title": "Επαφές", @@ -456,7 +464,8 @@ "categoryInsurance": "Ασφάλεια", "categoryCraftsman": "Τεχνίτης", "categoryEmergency": "Έκτακτη ανάγκη", - "categoryOther": "Άλλο" + "categoryOther": "Άλλο", + "emptyAction": "Προσθήκη επαφής" }, "budget": { "title": "Προϋπολογισμός", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "Προσθήκη εγγραφής" }, "settings": { "title": "Ρυθμίσεις", @@ -843,7 +853,8 @@ "titleRequired": "Ο τίτλος είναι υποχρεωτικός", "duplicate": "Διπλότυπο", "duplicated": "Η συνταγή αντιγράφηκε.", - "copySuffix": "αντίγραφο" + "copySuffix": "αντίγραφο", + "emptyAction": "Δημιουργία συνταγής" }, "search": { "title": "Αναζήτηση", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Πλοήγηση & Ενότητες", + "step2Body": "Στο κάτω μέρος έχεις άμεση πρόσβαση στον Πίνακα ελέγχου και το Ημερολόγιο. Με το κουμπί ··· ανοίγεις άλλες ενότητες όπως Κουζίνα, Σημειώσεις και Επαφές.", + "step3Title": "Ξεκίνα γρήγορα", + "step3Body": "Με το κουμπί + δημιουργείς νέες καταχωρήσεις οπουδήποτε. Σύρε στοιχεία λίστας αριστερά ή δεξιά για γρήγορες ενέργειες.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "Κουζίνα" } -} +} \ No newline at end of file diff --git a/public/locales/en.json b/public/locales/en.json index f1021ad..b9d3157 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -29,7 +29,12 @@ "unknownError": "Unknown error", "confirm": "Confirm", "undo": "Undo", - "reset": "Reset to original" + "reset": "Reset to original", + "errorOffline": "No internet connection. Please check your network.", + "errorForbidden": "Access denied. Please sign in again.", + "errorNotFound": "The entry was not found.", + "errorServer": "Server error. Please try again later.", + "errorTimeout": "The connection took too long. Please try again." }, "nav": { "dashboard": "Overview", @@ -187,7 +192,8 @@ "filterGroupStatus": "Status", "swipedDoneToast": "Marked as done.", "swipedOpenToast": "Marked as open.", - "reminderNeedsDueDate": "Set a due date to enable task reminders." + "reminderNeedsDueDate": "Set a due date to enable task reminders.", + "emptyAction": "Create task" }, "shopping": { "title": "Shopping", @@ -227,7 +233,8 @@ "catDrinks": "Drinks", "catHousehold": "Household", "catDrugstore": "Drugstore", - "catMisc": "Miscellaneous" + "catMisc": "Miscellaneous", + "emptyAction": "Add item" }, "meals": { "title": "Meal Plan", @@ -403,7 +410,8 @@ "formatLink": "Link", "formatCode": "Code", "formatQuote": "Quote", - "formatDivider": "Divider" + "formatDivider": "Divider", + "emptyAction": "Create note" }, "contacts": { "title": "Contacts", @@ -456,7 +464,8 @@ "categoryInsurance": "Insurance", "categoryCraftsman": "Tradesperson", "categoryEmergency": "Emergency", - "categoryOther": "Other" + "categoryOther": "Other", + "emptyAction": "Add contact" }, "budget": { "title": "Budget", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "Add entry" }, "settings": { "title": "Settings", @@ -903,7 +913,8 @@ "titleRequired": "Title is required", "duplicate": "Duplicate", "duplicated": "Recipe duplicated.", - "copySuffix": "copy" + "copySuffix": "copy", + "emptyAction": "Create recipe" }, "search": { "title": "Search", @@ -914,10 +925,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Navigation & Modules", + "step2Body": "At the bottom you can directly access Dashboard and Calendar. The ··· button opens additional modules like Kitchen, Notes and Contacts.", + "step3Title": "Get started quickly", + "step3Body": "Use the + FAB button to create new entries anywhere. Swipe list items left or right for quick actions.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -1008,4 +1019,4 @@ "dropzoneHint": "Drag a file into this area, or use the file picker.", "selectedFileLabel": "Selected: {{name}}" } -} +} \ No newline at end of file diff --git a/public/locales/es.json b/public/locales/es.json index eeada7e..5410d31 100644 --- a/public/locales/es.json +++ b/public/locales/es.json @@ -29,7 +29,12 @@ "unknownError": "Error desconocido", "confirm": "Confirmar", "undo": "Deshacer", - "reset": "Restaurar original" + "reset": "Restaurar original", + "errorOffline": "Sin conexión a internet. Por favor, revisa tu red.", + "errorForbidden": "Acceso denegado. Por favor, inicia sesión de nuevo.", + "errorNotFound": "No se encontró el registro.", + "errorServer": "Error del servidor. Por favor, inténtalo más tarde.", + "errorTimeout": "La conexión tardó demasiado. Por favor, inténtalo de nuevo." }, "nav": { "dashboard": "Inicio", @@ -187,7 +192,8 @@ "archiveButton": "Archivar tarea", "archivedToast": "Tarea archivada.", "kanbanArchived": "Archivado", - "reminderNeedsDueDate": "Establece una fecha de vencimiento para activar los recordatorios de tareas." + "reminderNeedsDueDate": "Establece una fecha de vencimiento para activar los recordatorios de tareas.", + "emptyAction": "Crear tarea" }, "shopping": { "title": "Compras", @@ -227,7 +233,8 @@ "catDrinks": "Bebidas", "catHousehold": "Hogar", "catDrugstore": "Droguería", - "catMisc": "Otros" + "catMisc": "Otros", + "emptyAction": "Agregar artículo" }, "meals": { "title": "Plan de comidas", @@ -403,7 +410,8 @@ "formatLink": "Enlace", "formatCode": "Código", "formatQuote": "Cita", - "formatDivider": "Separador" + "formatDivider": "Separador", + "emptyAction": "Crear nota" }, "contacts": { "title": "Contactos", @@ -456,7 +464,8 @@ "categoryInsurance": "Seguro", "categoryCraftsman": "Artesano", "categoryEmergency": "Emergencia", - "categoryOther": "Otros" + "categoryOther": "Otros", + "emptyAction": "Agregar contacto" }, "budget": { "title": "Presupuesto", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Nombre de la nueva categoría:", "newSubcategoryPrompt": "Nombre de la nueva subcategoría:", "categoryAddedToast": "Categoría añadida.", - "subcategoryAddedToast": "Subcategoría añadida." + "subcategoryAddedToast": "Subcategoría añadida.", + "emptyAction": "Agregar entrada" }, "settings": { "title": "Ajustes", @@ -843,7 +853,8 @@ "titleRequired": "El título es obligatorio", "duplicate": "Duplicar", "duplicated": "Receta duplicada.", - "copySuffix": "copia" + "copySuffix": "copia", + "emptyAction": "Crear receta" }, "search": { "title": "Búsqueda", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Navegación y módulos", + "step2Body": "En la parte inferior accedes directamente al Panel y el Calendario. Con el botón ··· abres más módulos como Cocina, Notas y Contactos.", + "step3Title": "Empieza rápido", + "step3Body": "Con el botón + creas nuevas entradas en cualquier lugar. Desliza elementos de la lista a la izquierda o derecha para acciones rápidas.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "Cocina" } -} +} \ No newline at end of file diff --git a/public/locales/fr.json b/public/locales/fr.json index 10a0bfb..9641f44 100644 --- a/public/locales/fr.json +++ b/public/locales/fr.json @@ -29,7 +29,12 @@ "unknownError": "Erreur inconnue", "confirm": "Confirmer", "undo": "Annuler", - "reset": "Réinitialiser" + "reset": "Réinitialiser", + "errorOffline": "Pas de connexion internet. Vérifiez votre réseau.", + "errorForbidden": "Accès refusé. Veuillez vous reconnecter.", + "errorNotFound": "L'entrée n'a pas été trouvée.", + "errorServer": "Erreur serveur. Veuillez réessayer plus tard.", + "errorTimeout": "La connexion a pris trop de temps. Veuillez réessayer." }, "nav": { "dashboard": "Accueil", @@ -187,7 +192,8 @@ "archiveButton": "Archiver la tâche", "archivedToast": "Tâche archivée.", "kanbanArchived": "Archivé", - "reminderNeedsDueDate": "Définissez une date d'échéance pour activer les rappels de tâche." + "reminderNeedsDueDate": "Définissez une date d'échéance pour activer les rappels de tâche.", + "emptyAction": "Créer une tâche" }, "shopping": { "title": "Courses", @@ -227,7 +233,8 @@ "catDrinks": "Boissons", "catHousehold": "Ménage", "catDrugstore": "Pharmacie", - "catMisc": "Divers" + "catMisc": "Divers", + "emptyAction": "Ajouter un article" }, "meals": { "title": "Plan de repas", @@ -403,7 +410,8 @@ "formatLink": "Lien", "formatCode": "Code", "formatQuote": "Citation", - "formatDivider": "Séparateur" + "formatDivider": "Séparateur", + "emptyAction": "Créer une note" }, "contacts": { "title": "Contacts", @@ -456,7 +464,8 @@ "categoryInsurance": "Assurance", "categoryCraftsman": "Artisan", "categoryEmergency": "Urgence", - "categoryOther": "Autre" + "categoryOther": "Autre", + "emptyAction": "Ajouter un contact" }, "budget": { "title": "Budget", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Nom de la nouvelle catégorie :", "newSubcategoryPrompt": "Nom de la nouvelle sous-catégorie :", "categoryAddedToast": "Catégorie ajoutée.", - "subcategoryAddedToast": "Sous-catégorie ajoutée." + "subcategoryAddedToast": "Sous-catégorie ajoutée.", + "emptyAction": "Ajouter une entrée" }, "settings": { "title": "Paramètres", @@ -843,7 +853,8 @@ "titleRequired": "Le titre est requis", "duplicate": "Dupliquer", "duplicated": "Recette dupliquée.", - "copySuffix": "copie" + "copySuffix": "copie", + "emptyAction": "Créer une recette" }, "search": { "title": "Recherche", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Navigation & modules", + "step2Body": "En bas, accédez directement au Tableau de bord et au Calendrier. Le bouton ··· ouvre d'autres modules comme Cuisine, Notes et Contacts.", + "step3Title": "Démarrer rapidement", + "step3Body": "Avec le bouton +, créez de nouvelles entrées n'importe où. Faites glisser les éléments de liste à gauche ou à droite pour des actions rapides.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "Cuisine" } -} +} \ No newline at end of file diff --git a/public/locales/hi.json b/public/locales/hi.json index 7a518d8..e64aa80 100644 --- a/public/locales/hi.json +++ b/public/locales/hi.json @@ -29,7 +29,12 @@ "unknownError": "अज्ञात त्रुटि", "confirm": "पुष्टि करें", "undo": "पूर्ववत करें", - "reset": "मूल पर वापस जाएं" + "reset": "मूल पर वापस जाएं", + "errorOffline": "इंटरनेट कनेक्शन नहीं है। कृपया अपना नेटवर्क जांचें।", + "errorForbidden": "पहुँच अस्वीकृत। कृपया फिर से लॉग इन करें।", + "errorNotFound": "प्रविष्टि नहीं मिली।", + "errorServer": "सर्वर त्रुटि। कृपया बाद में पुनः प्रयास करें।", + "errorTimeout": "कनेक्शन बहुत देर से हुआ। कृपया पुनः प्रयास करें।" }, "nav": { "dashboard": "डैशबोर्ड", @@ -187,7 +192,8 @@ "archiveButton": "कार्य संग्रहित करें", "archivedToast": "कार्य संग्रहित किया गया।", "kanbanArchived": "संग्रहित", - "reminderNeedsDueDate": "कार्य अनुस्मारक सक्षम करने के लिए एक नियत तारीख निर्धारित करें।" + "reminderNeedsDueDate": "कार्य अनुस्मारक सक्षम करने के लिए एक नियत तारीख निर्धारित करें।", + "emptyAction": "कार्य बनाएं" }, "shopping": { "title": "खरीदारी", @@ -227,7 +233,8 @@ "catDrinks": "पेय", "catHousehold": "घरेलू", "catDrugstore": "दवाखाना", - "catMisc": "विविध" + "catMisc": "विविध", + "emptyAction": "आइटम जोड़ें" }, "meals": { "title": "भोजन योजना", @@ -403,7 +410,8 @@ "formatLink": "लिंक", "formatCode": "कोड", "formatQuote": "उद्धरण", - "formatDivider": "विभाजक" + "formatDivider": "विभाजक", + "emptyAction": "नोट बनाएं" }, "contacts": { "title": "संपर्क", @@ -456,7 +464,8 @@ "categoryInsurance": "बीमा", "categoryCraftsman": "कारीगर", "categoryEmergency": "आपातकालीन", - "categoryOther": "विविध" + "categoryOther": "विविध", + "emptyAction": "संपर्क जोड़ें" }, "budget": { "title": "बजट", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "प्रविष्टि जोड़ें" }, "settings": { "title": "सेटिंग्स", @@ -843,7 +853,8 @@ "titleRequired": "शीर्षक आवश्यक है", "duplicate": "डुप्लिकेट", "duplicated": "रेसिपी डुप्लिकेट की गई।", - "copySuffix": "कॉपी" + "copySuffix": "कॉपी", + "emptyAction": "रेसिपी बनाएं" }, "search": { "title": "खोज", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "नेविगेशन और मॉड्यूल", + "step2Body": "नीचे से डैशबोर्ड और कैलेंडर तक सीधी पहुँच। ··· बटन से किचन, नोट्स और संपर्क जैसे अन्य मॉड्यूल खोलें।", + "step3Title": "जल्दी शुरू करें", + "step3Body": "किसी भी जगह नई प्रविष्टियाँ बनाने के लिए + बटन दबाएँ। त्वरित क्रियाओं के लिए सूची आइटम को बाएँ या दाएँ स्वाइप करें।", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "रसोई" } -} +} \ No newline at end of file diff --git a/public/locales/it.json b/public/locales/it.json index d9e3ade..4bb0782 100644 --- a/public/locales/it.json +++ b/public/locales/it.json @@ -29,7 +29,12 @@ "unknownError": "Errore sconosciuto", "confirm": "Conferma", "undo": "Annulla", - "reset": "Ripristina originale" + "reset": "Ripristina originale", + "errorOffline": "Nessuna connessione internet. Controlla la tua rete.", + "errorForbidden": "Accesso negato. Per favore accedi di nuovo.", + "errorNotFound": "La voce non è stata trovata.", + "errorServer": "Errore del server. Riprova più tardi.", + "errorTimeout": "La connessione ha impiegato troppo tempo. Riprova." }, "nav": { "dashboard": "Panoramica", @@ -187,7 +192,8 @@ "archiveButton": "Archivia attività", "archivedToast": "Attività archiviata.", "kanbanArchived": "Archiviato", - "reminderNeedsDueDate": "Imposta una data di scadenza per abilitare i promemoria delle attività." + "reminderNeedsDueDate": "Imposta una data di scadenza per abilitare i promemoria delle attività.", + "emptyAction": "Crea attività" }, "shopping": { "title": "Spesa", @@ -227,7 +233,8 @@ "catDrinks": "Bevande", "catHousehold": "Casa", "catDrugstore": "Drogheria", - "catMisc": "Varie" + "catMisc": "Varie", + "emptyAction": "Aggiungi articolo" }, "meals": { "title": "Piano pasti", @@ -403,7 +410,8 @@ "formatLink": "Link", "formatCode": "Codice", "formatQuote": "Citazione", - "formatDivider": "Divisore" + "formatDivider": "Divisore", + "emptyAction": "Crea nota" }, "contacts": { "title": "Contatti", @@ -456,7 +464,8 @@ "categoryInsurance": "Assicurazione", "categoryCraftsman": "Artigiano", "categoryEmergency": "Emergenza", - "categoryOther": "Altro" + "categoryOther": "Altro", + "emptyAction": "Aggiungi contatto" }, "budget": { "title": "Bilancio", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Nome della nuova categoria:", "newSubcategoryPrompt": "Nome della nuova sottocategoria:", "categoryAddedToast": "Categoria aggiunta.", - "subcategoryAddedToast": "Sottocategoria aggiunta." + "subcategoryAddedToast": "Sottocategoria aggiunta.", + "emptyAction": "Aggiungi voce" }, "settings": { "title": "Impostazioni", @@ -843,7 +853,8 @@ "titleRequired": "Il titolo è obbligatorio", "duplicate": "Duplica", "duplicated": "Ricetta duplicata.", - "copySuffix": "copia" + "copySuffix": "copia", + "emptyAction": "Crea ricetta" }, "search": { "title": "Ricerca", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Navigazione e moduli", + "step2Body": "In basso accedi direttamente alla Dashboard e al Calendario. Con il pulsante ··· apri altri moduli come Cucina, Note e Contatti.", + "step3Title": "Inizia subito", + "step3Body": "Con il pulsante + crei nuove voci ovunque. Scorri gli elementi dell'elenco a sinistra o a destra per azioni rapide.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "Cucina" } -} +} \ No newline at end of file diff --git a/public/locales/ja.json b/public/locales/ja.json index 7b11bb0..2dc64a4 100644 --- a/public/locales/ja.json +++ b/public/locales/ja.json @@ -29,7 +29,12 @@ "unknownError": "不明なエラー", "confirm": "確認", "undo": "元に戻す", - "reset": "元に戻す" + "reset": "元に戻す", + "errorOffline": "インターネット接続がありません。ネットワークを確認してください。", + "errorForbidden": "アクセスが拒否されました。再度サインインしてください。", + "errorNotFound": "エントリが見つかりませんでした。", + "errorServer": "サーバーエラーが発生しました。後でもう一度お試しください。", + "errorTimeout": "接続に時間がかかりすぎました。もう一度お試しください。" }, "nav": { "dashboard": "ダッシュボード", @@ -187,7 +192,8 @@ "archiveButton": "タスクをアーカイブ", "archivedToast": "タスクをアーカイブしました。", "kanbanArchived": "アーカイブ済み", - "reminderNeedsDueDate": "タスクのリマインダーを有効にするには期日を設定してください。" + "reminderNeedsDueDate": "タスクのリマインダーを有効にするには期日を設定してください。", + "emptyAction": "タスクを作成" }, "shopping": { "title": "買い物", @@ -227,7 +233,8 @@ "catDrinks": "飲み物", "catHousehold": "日用品", "catDrugstore": "薬局", - "catMisc": "その他" + "catMisc": "その他", + "emptyAction": "アイテムを追加" }, "meals": { "title": "食事計画", @@ -403,7 +410,8 @@ "formatLink": "リンク", "formatCode": "コード", "formatQuote": "引用", - "formatDivider": "区切り線" + "formatDivider": "区切り線", + "emptyAction": "メモを作成" }, "contacts": { "title": "連絡先", @@ -456,7 +464,8 @@ "categoryInsurance": "保険", "categoryCraftsman": "職人", "categoryEmergency": "緊急連絡先", - "categoryOther": "その他" + "categoryOther": "その他", + "emptyAction": "連絡先を追加" }, "budget": { "title": "家計", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "エントリを追加" }, "settings": { "title": "設定", @@ -843,7 +853,8 @@ "titleRequired": "タイトルが必要です", "duplicate": "複製", "duplicated": "レシピが複製されました。", - "copySuffix": "コピー" + "copySuffix": "コピー", + "emptyAction": "レシピを作成" }, "search": { "title": "検索", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "ナビゲーションとモジュール", + "step2Body": "画面下部からダッシュボードとカレンダーに直接アクセスできます。···ボタンでキッチン、メモ、連絡先などの追加モジュールを開きます。", + "step3Title": "さっそく始めよう", + "step3Body": "+ボタンでどこでも新しいエントリを作成できます。リストアイテムを左右にスワイプして素早く操作できます。", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "キッチン" } -} +} \ No newline at end of file diff --git a/public/locales/pt.json b/public/locales/pt.json index 9ca31e5..612b633 100644 --- a/public/locales/pt.json +++ b/public/locales/pt.json @@ -29,7 +29,12 @@ "unknownError": "Erro desconhecido", "confirm": "Confirmar", "undo": "Desfazer", - "reset": "Restaurar original" + "reset": "Restaurar original", + "errorOffline": "Sem ligação à internet. Por favor, verifique a sua rede.", + "errorForbidden": "Acesso negado. Por favor, inicie sessão novamente.", + "errorNotFound": "O registo não foi encontrado.", + "errorServer": "Erro no servidor. Por favor, tente mais tarde.", + "errorTimeout": "A ligação demorou demasiado. Por favor, tente novamente." }, "nav": { "dashboard": "Painel", @@ -187,7 +192,8 @@ "filterGroupStatus": "Estado", "swipedDoneToast": "Marcado como concluído.", "swipedOpenToast": "Marcado como aberto.", - "reminderNeedsDueDate": "Defina uma data de vencimento para habilitar lembretes da tarefa." + "reminderNeedsDueDate": "Defina uma data de vencimento para habilitar lembretes da tarefa.", + "emptyAction": "Criar tarefa" }, "shopping": { "title": "Compras", @@ -227,7 +233,8 @@ "catDrinks": "Bebidas", "catHousehold": "Casa", "catDrugstore": "Farmácia", - "catMisc": "Outros" + "catMisc": "Outros", + "emptyAction": "Adicionar item" }, "meals": { "title": "Plano de refeições", @@ -403,7 +410,8 @@ "formatLink": "Link", "formatCode": "Código", "formatQuote": "Citação", - "formatDivider": "Divisor" + "formatDivider": "Divisor", + "emptyAction": "Criar nota" }, "contacts": { "title": "Contatos", @@ -456,7 +464,8 @@ "categoryInsurance": "Seguro", "categoryCraftsman": "Artesão", "categoryEmergency": "Emergência", - "categoryOther": "Outros" + "categoryOther": "Outros", + "emptyAction": "Adicionar contato" }, "budget": { "title": "Orçamento", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Nome da nova categoria:", "newSubcategoryPrompt": "Nome da nova subcategoria:", "categoryAddedToast": "Categoria adicionada.", - "subcategoryAddedToast": "Subcategoria adicionada." + "subcategoryAddedToast": "Subcategoria adicionada.", + "emptyAction": "Adicionar entrada" }, "settings": { "title": "Configurações", @@ -843,7 +853,8 @@ "titleRequired": "O título é obrigatório", "duplicate": "Duplicar", "duplicated": "Receita duplicada.", - "copySuffix": "cópia" + "copySuffix": "cópia", + "emptyAction": "Criar receita" }, "search": { "title": "Pesquisa", @@ -914,10 +925,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Navegação e módulos", + "step2Body": "Na parte inferior acessa diretamente o Painel e o Calendário. Com o botão ··· abre módulos adicionais como Cozinha, Notas e Contactos.", + "step3Title": "Comece rapidamente", + "step3Body": "Com o botão + cria novas entradas em qualquer lugar. Deslize itens da lista para a esquerda ou direita para ações rápidas.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -992,4 +1003,4 @@ "shortcuts": { "goKitchen": "Cozinha" } -} +} \ No newline at end of file diff --git a/public/locales/ru.json b/public/locales/ru.json index 6efb147..60e5983 100644 --- a/public/locales/ru.json +++ b/public/locales/ru.json @@ -29,7 +29,12 @@ "unknownError": "Неизвестная ошибка", "confirm": "Подтвердить", "undo": "Отменить", - "reset": "Сбросить к исходному" + "reset": "Сбросить к исходному", + "errorOffline": "Нет подключения к интернету. Проверьте сеть.", + "errorForbidden": "Доступ запрещён. Пожалуйста, войдите снова.", + "errorNotFound": "Запись не найдена.", + "errorServer": "Ошибка сервера. Повторите попытку позже.", + "errorTimeout": "Соединение заняло слишком много времени. Попробуйте снова." }, "nav": { "dashboard": "Обзор", @@ -187,7 +192,8 @@ "archiveButton": "Архивировать задачу", "archivedToast": "Задача архивирована.", "kanbanArchived": "Архивировано", - "reminderNeedsDueDate": "Установите срок выполнения, чтобы включить напоминания о задаче." + "reminderNeedsDueDate": "Установите срок выполнения, чтобы включить напоминания о задаче.", + "emptyAction": "Создать задачу" }, "shopping": { "title": "Покупки", @@ -227,7 +233,8 @@ "catDrinks": "Напитки", "catHousehold": "Хозтовары", "catDrugstore": "Аптека", - "catMisc": "Разное" + "catMisc": "Разное", + "emptyAction": "Добавить товар" }, "meals": { "title": "План питания", @@ -403,7 +410,8 @@ "formatLink": "Ссылка", "formatCode": "Код", "formatQuote": "Цитата", - "formatDivider": "Разделитель" + "formatDivider": "Разделитель", + "emptyAction": "Создать заметку" }, "contacts": { "title": "Контакты", @@ -456,7 +464,8 @@ "categoryInsurance": "Страховая", "categoryCraftsman": "Мастер", "categoryEmergency": "Экстренная помощь", - "categoryOther": "Другое" + "categoryOther": "Другое", + "emptyAction": "Добавить контакт" }, "budget": { "title": "Бюджет", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "Добавить запись" }, "settings": { "title": "Настройки", @@ -843,7 +853,8 @@ "titleRequired": "Название обязательно", "duplicate": "Дублировать", "duplicated": "Рецепт дублирован.", - "copySuffix": "копия" + "copySuffix": "копия", + "emptyAction": "Создать рецепт" }, "search": { "title": "Поиск", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Навигация и модули", + "step2Body": "Внизу доступны Панель управления и Календарь напрямую. Кнопка ··· открывает дополнительные модули: Кухня, Заметки и Контакты.", + "step3Title": "Начните быстро", + "step3Body": "Кнопка + позволяет создавать новые записи везде. Смахните элементы списка влево или вправо для быстрых действий.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "Кухня" } -} +} \ No newline at end of file diff --git a/public/locales/sv.json b/public/locales/sv.json index 04d94e8..27b17e5 100644 --- a/public/locales/sv.json +++ b/public/locales/sv.json @@ -29,7 +29,12 @@ "unknownError": "Okänt fel", "confirm": "Bekräfta", "undo": "Ångra", - "reset": "Återställ till original" + "reset": "Återställ till original", + "errorOffline": "Ingen internetanslutning. Kontrollera ditt nätverk.", + "errorForbidden": "Åtkomst nekad. Logga in igen.", + "errorNotFound": "Posten hittades inte.", + "errorServer": "Serverfel. Försök igen senare.", + "errorTimeout": "Anslutningen tog för lång tid. Försök igen." }, "nav": { "dashboard": "Översikt", @@ -187,7 +192,8 @@ "archiveButton": "Arkivera uppgift", "archivedToast": "Uppgiften arkiverades.", "kanbanArchived": "Arkiverad", - "reminderNeedsDueDate": "Ange ett förfallodatum för att aktivera påminnelser för uppgiften." + "reminderNeedsDueDate": "Ange ett förfallodatum för att aktivera påminnelser för uppgiften.", + "emptyAction": "Skapa uppgift" }, "shopping": { "title": "Shopping", @@ -227,7 +233,8 @@ "catDrinks": "Drycker", "catHousehold": "Hushåll", "catDrugstore": "Apotek", - "catMisc": "Diverse" + "catMisc": "Diverse", + "emptyAction": "Lägg till artikel" }, "meals": { "title": "Måltidsplan", @@ -403,7 +410,8 @@ "formatLink": "Länk", "formatCode": "Kod", "formatQuote": "Citationstecken", - "formatDivider": "Delare" + "formatDivider": "Delare", + "emptyAction": "Skapa anteckning" }, "contacts": { "title": "Kontakter", @@ -456,7 +464,8 @@ "categoryInsurance": "Försäkring", "categoryCraftsman": "Handlare", "categoryEmergency": "Nödsituation", - "categoryOther": "Andra" + "categoryOther": "Andra", + "emptyAction": "Lägg till kontakt" }, "budget": { "title": "Budget", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "Lägg till post" }, "settings": { "title": "Inställningar", @@ -843,7 +853,8 @@ "titleRequired": "Titel krävs", "duplicate": "Duplicera", "duplicated": "Recept duplicerat.", - "copySuffix": "kopia" + "copySuffix": "kopia", + "emptyAction": "Skapa recept" }, "search": { "title": "Sök", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Navigering och moduler", + "step2Body": "Nere på skärmen når du direkt Dashboard och Kalender. Med ···-knappen öppnar du fler moduler som Kök, Anteckningar och Kontakter.", + "step3Title": "Kom igång snabbt", + "step3Body": "Med +-knappen skapar du nya poster var som helst. Svep listobjekt åt vänster eller höger för snabbåtgärder.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "Kök" } -} +} \ No newline at end of file diff --git a/public/locales/tr.json b/public/locales/tr.json index 4cb0715..8cda108 100644 --- a/public/locales/tr.json +++ b/public/locales/tr.json @@ -29,7 +29,12 @@ "unknownError": "Bilinmeyen hata", "confirm": "Onayla", "undo": "Geri al", - "reset": "Orijinale sıfırla" + "reset": "Orijinale sıfırla", + "errorOffline": "İnternet bağlantısı yok. Lütfen ağınızı kontrol edin.", + "errorForbidden": "Erişim reddedildi. Lütfen tekrar giriş yapın.", + "errorNotFound": "Kayıt bulunamadı.", + "errorServer": "Sunucu hatası. Lütfen daha sonra tekrar deneyin.", + "errorTimeout": "Bağlantı çok uzun sürdü. Lütfen tekrar deneyin." }, "nav": { "dashboard": "Genel Bakış", @@ -187,7 +192,8 @@ "archiveButton": "Görevi arşivle", "archivedToast": "Görev arşivlendi.", "kanbanArchived": "Arşivlenmiş", - "reminderNeedsDueDate": "Görev hatırlatıcılarını etkinleştirmek için bir son tarih belirleyin." + "reminderNeedsDueDate": "Görev hatırlatıcılarını etkinleştirmek için bir son tarih belirleyin.", + "emptyAction": "Görev oluştur" }, "shopping": { "title": "Alışveriş", @@ -227,7 +233,8 @@ "catDrinks": "İçecekler", "catHousehold": "Ev Gereçleri", "catDrugstore": "Eczane", - "catMisc": "Diğer" + "catMisc": "Diğer", + "emptyAction": "Öğe ekle" }, "meals": { "title": "Yemek Planı", @@ -403,7 +410,8 @@ "formatLink": "Bağlantı", "formatCode": "Kod", "formatQuote": "Alıntı", - "formatDivider": "Ayırıcı" + "formatDivider": "Ayırıcı", + "emptyAction": "Not oluştur" }, "contacts": { "title": "Kişiler", @@ -456,7 +464,8 @@ "categoryInsurance": "Sigorta", "categoryCraftsman": "Usta", "categoryEmergency": "Acil", - "categoryOther": "Diğer" + "categoryOther": "Diğer", + "emptyAction": "Kişi ekle" }, "budget": { "title": "Bütçe", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "Giriş ekle" }, "settings": { "title": "Ayarlar", @@ -843,7 +853,8 @@ "titleRequired": "Başlık gerekli", "duplicate": "Çoğalt", "duplicated": "Tarif çoğaltıldı.", - "copySuffix": "kopya" + "copySuffix": "kopya", + "emptyAction": "Tarif oluştur" }, "search": { "title": "Arama", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Gezinme ve Modüller", + "step2Body": "Aşağıda Gösterge Paneli ve Takvim'e doğrudan erişebilirsiniz. ···-düğmesiyle Mutfak, Notlar ve Kişiler gibi ek modülleri açabilirsiniz.", + "step3Title": "Hızlıca başlayın", + "step3Body": "+ düğmesiyle her yerde yeni girişler oluşturabilirsiniz. Hızlı işlemler için liste öğelerini sola veya sağa kaydırın.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "Mutfak" } -} +} \ No newline at end of file diff --git a/public/locales/uk.json b/public/locales/uk.json index e4db3cb..272cde9 100644 --- a/public/locales/uk.json +++ b/public/locales/uk.json @@ -29,7 +29,12 @@ "unknownError": "Невідома помилка", "confirm": "Підтвердити", "undo": "Скасувати", - "reset": "Скинути до оригіналу" + "reset": "Скинути до оригіналу", + "errorOffline": "Немає підключення до інтернету. Перевірте мережу.", + "errorForbidden": "Доступ заборонено. Будь ласка, увійдіть знову.", + "errorNotFound": "Запис не знайдено.", + "errorServer": "Помилка сервера. Спробуйте пізніше.", + "errorTimeout": "З'єднання тривало занадто довго. Спробуйте ще раз." }, "nav": { "dashboard": "Огляд", @@ -187,7 +192,8 @@ "archiveButton": "Архівувати завдання", "archivedToast": "Завдання архівовано.", "kanbanArchived": "Архівовано", - "reminderNeedsDueDate": "Встановіть дату виконання, щоб увімкнути нагадування про завдання." + "reminderNeedsDueDate": "Встановіть дату виконання, щоб увімкнути нагадування про завдання.", + "emptyAction": "Створити завдання" }, "shopping": { "title": "Покупки", @@ -227,7 +233,8 @@ "catDrinks": "Напої", "catHousehold": "Господарські товари", "catDrugstore": "Аптека", - "catMisc": "Різне" + "catMisc": "Різне", + "emptyAction": "Додати товар" }, "meals": { "title": "План харчування", @@ -403,7 +410,8 @@ "formatLink": "Посилання", "formatCode": "Код", "formatQuote": "Цитата", - "formatDivider": "Розділювач" + "formatDivider": "Розділювач", + "emptyAction": "Створити нотатку" }, "contacts": { "title": "Контакти", @@ -456,7 +464,8 @@ "categoryInsurance": "Страхування", "categoryCraftsman": "Майстер", "categoryEmergency": "Екстрена служба", - "categoryOther": "Інше" + "categoryOther": "Інше", + "emptyAction": "Додати контакт" }, "budget": { "title": "Бюджет", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "Додати запис" }, "settings": { "title": "Налаштування", @@ -874,7 +884,8 @@ "titleRequired": "Назва обов'язкова", "duplicate": "Дублювати", "duplicated": "Рецепт продубльовано.", - "copySuffix": "копія" + "copySuffix": "копія", + "emptyAction": "Створити рецепт" }, "search": { "title": "Пошук", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "Навігація та модулі", + "step2Body": "Унизу ви маєте прямий доступ до Панелі керування та Календаря. Кнопка ··· відкриває додаткові модулі: Кухня, Нотатки та Контакти.", + "step3Title": "Починайте швидко", + "step3Body": "За допомогою кнопки + створюйте нові записи будь-де. Проведіть пальцем по елементу списку ліворуч або праворуч для швидких дій.", "next": "Next", "done": "Get started", "skip": "Skip" @@ -999,4 +1010,4 @@ "shortcuts": { "goKitchen": "Кухня" } -} +} \ No newline at end of file diff --git a/public/locales/zh.json b/public/locales/zh.json index a16ab3b..e0ef6e8 100644 --- a/public/locales/zh.json +++ b/public/locales/zh.json @@ -29,7 +29,12 @@ "unknownError": "未知错误", "confirm": "确认", "undo": "撤销", - "reset": "重置为原始" + "reset": "重置为原始", + "errorOffline": "无网络连接。请检查您的网络。", + "errorForbidden": "访问被拒绝。请重新登录。", + "errorNotFound": "未找到该条目。", + "errorServer": "服务器错误。请稍后重试。", + "errorTimeout": "连接超时。请重试。" }, "nav": { "dashboard": "概览", @@ -187,7 +192,8 @@ "archiveButton": "归档任务", "archivedToast": "任务已归档。", "kanbanArchived": "已归档", - "reminderNeedsDueDate": "设置截止日期以启用任务提醒。" + "reminderNeedsDueDate": "设置截止日期以启用任务提醒。", + "emptyAction": "创建任务" }, "shopping": { "title": "购物", @@ -227,7 +233,8 @@ "catDrinks": "饮料", "catHousehold": "家居", "catDrugstore": "日化", - "catMisc": "其他" + "catMisc": "其他", + "emptyAction": "添加商品" }, "meals": { "title": "饮食计划", @@ -403,7 +410,8 @@ "formatLink": "链接", "formatCode": "代码", "formatQuote": "引用", - "formatDivider": "分隔线" + "formatDivider": "分隔线", + "emptyAction": "创建笔记" }, "contacts": { "title": "联系人", @@ -456,7 +464,8 @@ "categoryInsurance": "保险", "categoryCraftsman": "技工", "categoryEmergency": "紧急联系", - "categoryOther": "其他" + "categoryOther": "其他", + "emptyAction": "添加联系人" }, "budget": { "title": "预算", @@ -555,7 +564,8 @@ "newCategoryPrompt": "Name of the new category:", "newSubcategoryPrompt": "Name of the new subcategory:", "categoryAddedToast": "Category added.", - "subcategoryAddedToast": "Subcategory added." + "subcategoryAddedToast": "Subcategory added.", + "emptyAction": "添加记录" }, "settings": { "title": "设置", @@ -843,7 +853,8 @@ "titleRequired": "标题必填", "duplicate": "复制", "duplicated": "食谱已复制。", - "copySuffix": "副本" + "copySuffix": "副本", + "emptyAction": "创建食谱" }, "search": { "title": "搜索", @@ -913,10 +924,10 @@ "onboarding": { "step1Title": "Welcome to Oikos", "step1Body": "Your personal family planner. Tasks, calendar, shopping and more – all in one place.", - "step2Title": "Everything at a glance", - "step2Body": "Use the navigation below to reach all modules. The + button creates new entries quickly.", - "step3Title": "Ready to go", - "step3Body": "The dashboard shows you the most important information at a glance. Customize it under \"Customize\".", + "step2Title": "导航与模块", + "step2Body": "底部可直接访问仪表板和日历。点击···按钮可打开厨房、笔记和联系人等更多模块。", + "step3Title": "快速开始", + "step3Body": "点击+按钮可在任意位置创建新条目。向左或向右滑动列表项可执行快捷操作。", "next": "Next", "done": "Get started", "skip": "Skip" @@ -991,4 +1002,4 @@ "shortcuts": { "goKitchen": "厨房" } -} +} \ No newline at end of file diff --git a/public/pages/budget.js b/public/pages/budget.js index 00dfda6..1335266 100644 --- a/public/pages/budget.js +++ b/public/pages/budget.js @@ -332,6 +332,9 @@ function renderBody() { `; if (window.lucide) lucide.createIcons(); + _container.querySelector('#empty-cta-budget')?.addEventListener('click', () => { + document.querySelector('.page-fab')?.click(); + }); stagger(_container.querySelector('#budget-list')?.querySelectorAll('.budget-entry') ?? []); _container.querySelector('#budget-list')?.addEventListener('click', async (e) => { @@ -378,6 +381,10 @@ function renderEntries() {
${t('emptyHint.budget')}
+ `; } diff --git a/public/pages/contacts.js b/public/pages/contacts.js index fee65f3..5e4fcaa 100644 --- a/public/pages/contacts.js +++ b/public/pages/contacts.js @@ -181,9 +181,16 @@ function renderList() {${t('emptyHint.contacts')}
+ `; if (window.lucide) lucide.createIcons(); + container.querySelector('#empty-cta-contacts')?.addEventListener('click', () => { + document.querySelector('.page-fab')?.click(); + }); return; } diff --git a/public/pages/dashboard.js b/public/pages/dashboard.js index 45ff871..ca79eb2 100644 --- a/public/pages/dashboard.js +++ b/public/pages/dashboard.js @@ -19,8 +19,8 @@ const ONBOARDING_KEY = 'oikos-onboarded'; function getOnboardingSteps() { return [ { icon: 'home', title: t('onboarding.step1Title'), body: t('onboarding.step1Body') }, - { icon: 'grid-2x2', title: t('onboarding.step2Title'), body: t('onboarding.step2Body') }, - { icon: 'circle-check', title: t('onboarding.step3Title'), body: t('onboarding.step3Body') }, + { icon: 'navigation', title: t('onboarding.step2Title'), body: t('onboarding.step2Body') }, + { icon: 'plus-circle', title: t('onboarding.step3Title'), body: t('onboarding.step3Body') }, ]; } diff --git a/public/pages/notes.js b/public/pages/notes.js index 2d395da..ffd48d9 100644 --- a/public/pages/notes.js +++ b/public/pages/notes.js @@ -146,10 +146,17 @@ function renderGrid() {${t('emptyHint.notes')}
` : ''} + ${!isFiltered ? `${t('emptyHint.notes')}
+ ` : ''} `; if (window.lucide) lucide.createIcons(); + grid.querySelector('#empty-cta-notes')?.addEventListener('click', () => { + document.querySelector('.page-fab')?.click(); + }); return; } diff --git a/public/pages/recipes.js b/public/pages/recipes.js index b44763e..9f6bcb0 100644 --- a/public/pages/recipes.js +++ b/public/pages/recipes.js @@ -131,8 +131,16 @@ function renderRecipeList() { const emptyHint = document.createElement('p'); emptyHint.className = 'empty-state__hint'; emptyHint.textContent = t('emptyHint.recipes'); - empty.append(emptyTitle, emptyDesc, emptyHint); + const emptyCta = document.createElement('button'); + emptyCta.className = 'btn btn--primary empty-state__cta'; + emptyCta.insertAdjacentHTML('afterbegin', ''); + emptyCta.append(document.createTextNode(t('recipes.emptyAction'))); + emptyCta.addEventListener('click', () => { + document.querySelector('.page-fab')?.click(); + }); + empty.append(emptyTitle, emptyDesc, emptyHint, emptyCta); list.appendChild(empty); + if (window.lucide) window.lucide.createIcons({ el: empty }); return; } diff --git a/public/pages/shopping.js b/public/pages/shopping.js index 1aafa13..3197409 100644 --- a/public/pages/shopping.js +++ b/public/pages/shopping.js @@ -172,6 +172,10 @@ function renderItems() {${t('emptyHint.shopping')}
+ `; } @@ -527,6 +531,9 @@ function updateItemsList(container) { stagger(listEl.querySelectorAll('.shopping-item')); wireSwipeGestures(container); maybeShowSwipeHint(container); + listEl.querySelector('#empty-cta-shopping')?.addEventListener('click', () => { + document.querySelector('.page-fab')?.click(); + }); } // clear-checked Button aktualisieren const checkedCount = state.items.filter((i) => i.is_checked).length; diff --git a/public/pages/tasks.js b/public/pages/tasks.js index 2d513b1..f6e09ff 100644 --- a/public/pages/tasks.js +++ b/public/pages/tasks.js @@ -268,6 +268,10 @@ function renderTaskGroups(tasks, groupMode) {${t('emptyHint.tasks')}
+ `; } @@ -1029,6 +1033,9 @@ function renderTaskList(container) { updateOverdueBadge(); wireSwipeGestures(container); maybeShowSwipeHint(container); + listEl.querySelector('#empty-cta-tasks')?.addEventListener('click', () => { + document.querySelector('.page-fab')?.click(); + }); } function renderFilters(container) { diff --git a/public/router.js b/public/router.js index 011a0a9..abd3748 100644 --- a/public/router.js +++ b/public/router.js @@ -465,7 +465,13 @@ function renderAppShell(container) { const sidebarItems = document.createElement('div'); sidebarItems.className = 'nav-sidebar__items'; sidebarItems.setAttribute('role', 'list'); - navItems().forEach((item) => sidebarItems.appendChild(navItemEl(item))); + navItems() + .filter((item) => !item.kitchenGroup) + .forEach((item) => { + sidebarItems.appendChild(navItemEl(item)); + if (item.path === '/calendar') sidebarItems.appendChild(sidebarKitchenEl()); + }); + if (window.lucide) window.lucide.createIcons({ el: sidebarItems }); sidebar.appendChild(sidebarLogo); sidebar.appendChild(sidebarItems); @@ -521,7 +527,7 @@ function renderAppShell(container) { moreBtn.setAttribute('aria-label', t('nav.more')); moreBtn.setAttribute('aria-expanded', 'false'); const moreBtnIcon = document.createElement('i'); - moreBtnIcon.dataset.lucide = 'grid-2x2'; + moreBtnIcon.dataset.lucide = 'ellipsis'; moreBtnIcon.className = 'nav-item__icon'; moreBtnIcon.setAttribute('aria-hidden', 'true'); const moreBtnLabel = document.createElement('span'); @@ -547,7 +553,7 @@ function renderAppShell(container) { dragHandle.className = 'more-sheet__handle'; dragHandle.setAttribute('aria-hidden', 'true'); moreSheet.insertAdjacentElement('afterbegin', dragHandle); - navItems().filter((i) => !i.sidebarOnly).slice(PRIMARY_NAV).forEach((item) => moreSheet.appendChild(moreItemEl(item))); + navItems().filter((i) => !i.kitchenGroup).slice(PRIMARY_NAV).forEach((item) => moreSheet.appendChild(moreItemEl(item))); const searchOverlay = document.createElement('div'); searchOverlay.className = 'search-overlay'; @@ -945,10 +951,10 @@ function navItems() { { path: '/budget', label: t('nav.budget'), icon: 'wallet' }, { path: '/documents', label: t('nav.documents'), icon: 'folder-lock' }, { path: '/settings', label: t('nav.settings'), icon: 'settings' }, - // Sidebar only (Küche-Gruppe): - { path: '/meals', label: t('nav.meals'), icon: 'utensils', sidebarOnly: true }, - { path: '/recipes', label: t('nav.recipes'), icon: 'book-text', sidebarOnly: true }, - { path: '/shopping', label: t('nav.shopping'), icon: 'shopping-cart', sidebarOnly: true }, + // Kitchen-Gruppe: via Küche-Nav-Button (Bottom-Nav + Sidebar) + kitchen-tabs-bar erreichbar + { path: '/meals', label: t('nav.meals'), icon: 'utensils', kitchenGroup: true }, + { path: '/recipes', label: t('nav.recipes'), icon: 'book-text', kitchenGroup: true }, + { path: '/shopping', label: t('nav.shopping'), icon: 'shopping-cart', kitchenGroup: true }, ]; } @@ -972,6 +978,30 @@ function navItemEl({ path, label, icon }) { return a; } +function sidebarKitchenEl() { + const a = document.createElement('a'); + a.href = '/meals'; + a.id = 'sidebar-kitchen-nav'; + a.className = 'nav-item'; + a.setAttribute('role', 'listitem'); + a.setAttribute('aria-label', t('nav.kitchen')); + a.setAttribute('title', t('nav.kitchen')); + const icon = document.createElement('i'); + icon.dataset.lucide = 'utensils'; + icon.className = 'nav-item__icon'; + icon.setAttribute('aria-hidden', 'true'); + const label = document.createElement('span'); + label.className = 'nav-item__label'; + label.textContent = t('nav.kitchen'); + a.appendChild(icon); + a.appendChild(label); + a.addEventListener('click', (e) => { + e.preventDefault(); + navigate(getLastKitchenRoute()); + }); + return a; +} + function moreItemEl({ path, label, icon }) { const a = document.createElement('a'); a.href = path; @@ -1008,9 +1038,18 @@ function updateNav(path) { kitchenNavBtn.toggleAttribute('aria-current', isKitchen); } + const sidebarKitchenNav = document.querySelector('#sidebar-kitchen-nav'); + if (sidebarKitchenNav) { + if (isKitchenRoute(path)) { + sidebarKitchenNav.setAttribute('aria-current', 'page'); + } else { + sidebarKitchenNav.removeAttribute('aria-current'); + } + } + const moreBtn = document.querySelector('#more-btn'); if (moreBtn) { - const secondaryItems = navItems().filter((i) => !i.sidebarOnly).slice(PRIMARY_NAV); + const secondaryItems = navItems().filter((i) => !i.kitchenGroup).slice(PRIMARY_NAV); const activeSecondary = secondaryItems.find((n) => n.path === path); const inMoreSheet = !!activeSecondary; @@ -1123,6 +1162,20 @@ function showToast(message, type = 'default', duration = 3000, onUndo = null) { // Event-Listener // -------------------------------------------------------- +// -------------------------------------------------------- +// Fehler-Hilfsfunktion +// -------------------------------------------------------- + +function friendlyError(err) { + if (!navigator.onLine) return t('common.errorOffline'); + const status = err?.status ?? err?.response?.status; + if (status === 403) return t('common.errorForbidden'); + if (status === 404) return t('common.errorNotFound'); + if (status >= 500) return t('common.errorServer'); + if (err?.name === 'AbortError' || err?.name === 'TimeoutError') return t('common.errorTimeout'); + return err?.data?.error || err?.message || t('common.errorGeneric'); +} + // -------------------------------------------------------- // Globale Fehler-Handler (Error Boundary) // -------------------------------------------------------- @@ -1138,8 +1191,7 @@ window.addEventListener('unhandledrejection', (e) => { // Auth-Fehler werden bereits von auth:expired behandelt if (e.reason?.status === 401) return; console.error('[Oikos] Unbehandeltes Promise-Rejection:', e.reason); - const msg = e.reason?.message || t('common.errorGeneric'); - showToast(msg, 'danger'); + showToast(friendlyError(e.reason), 'danger'); e.preventDefault(); // Konsolenfehler unterdrücken (bereits geloggt) }); @@ -1189,7 +1241,15 @@ window.addEventListener('locale-changed', () => { if (moreBtnLabel) moreBtnLabel.textContent = t('nav.more'); if (navSidebarItems) { - navSidebarItems.replaceChildren(...navItems().map(navItemEl)); + const sidebarEls = []; + navItems() + .filter((item) => !item.kitchenGroup) + .forEach((item) => { + sidebarEls.push(navItemEl(item)); + if (item.path === '/calendar') sidebarEls.push(sidebarKitchenEl()); + }); + navSidebarItems.replaceChildren(...sidebarEls); + if (window.lucide) window.lucide.createIcons({ el: navSidebarItems }); } if (bottomItems) { const kitchenBtnEl = bottomItems.querySelector('#kitchen-btn'); @@ -1202,7 +1262,7 @@ window.addEventListener('locale-changed', () => { } if (moreSheet) { const handle = moreSheet.querySelector('.more-sheet__handle'); - const newMoreItems = navItems().filter((i) => !i.sidebarOnly).slice(PRIMARY_NAV).map(moreItemEl); + const newMoreItems = navItems().filter((i) => !i.kitchenGroup).slice(PRIMARY_NAV).map(moreItemEl); moreSheet.replaceChildren(handle, ...newMoreItems); } @@ -1294,6 +1354,7 @@ if (/iPhone|iPad|iPod/.test(navigator.userAgent)) { window.oikos = { navigate, showToast, + friendlyError, setThemeColor, applyTheme: (value) => { localStorage.setItem('oikos-theme', value); diff --git a/public/styles/dashboard.css b/public/styles/dashboard.css index ffccae5..9f81af9 100644 --- a/public/styles/dashboard.css +++ b/public/styles/dashboard.css @@ -127,17 +127,21 @@ } .dashboard-metric__title { - font-size: var(--text-xs); + font-size: var(--text-2xs); color: var(--color-text-secondary); + text-transform: uppercase; + letter-spacing: 0.07em; + font-weight: var(--font-weight-medium); } .dashboard-metric__value { - font-size: var(--text-base); - font-weight: var(--font-weight-semibold); + font-size: var(--text-xl); + font-weight: var(--font-weight-bold); color: var(--color-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + line-height: var(--line-height-tight); } .dashboard-metric__hint { diff --git a/public/styles/kitchen-tabs.css b/public/styles/kitchen-tabs.css index 3529844..c099b46 100644 --- a/public/styles/kitchen-tabs.css +++ b/public/styles/kitchen-tabs.css @@ -28,7 +28,7 @@ align-items: center; gap: var(--space-1); padding: 0 var(--space-3); - height: 36px; + height: var(--target-base); border-radius: var(--radius-full); border: none; background: transparent; diff --git a/public/styles/layout.css b/public/styles/layout.css index 4e1f9a0..1947d5d 100755 --- a/public/styles/layout.css +++ b/public/styles/layout.css @@ -287,7 +287,7 @@ background-color: var(--color-surface); z-index: calc(var(--z-nav) + 3); display: flex; - flex-direction: column-reverse; + flex-direction: column; transform: translateY(100%); transition: transform 0.25s var(--ease-out); } @@ -300,8 +300,8 @@ display: flex; align-items: center; gap: var(--space-3); - padding: var(--space-3) var(--space-4) calc(var(--space-4) + var(--safe-area-inset-bottom)); - border-top: 1px solid var(--color-border-subtle); + padding: calc(var(--space-3) + var(--safe-area-inset-top)) var(--space-4) var(--space-3); + border-bottom: 1px solid var(--color-border-subtle); } .search-overlay__input { @@ -343,8 +343,7 @@ .search-overlay__results { flex: 1; overflow-y: auto; - padding: var(--space-4) var(--space-4) var(--space-2); - padding-top: calc(var(--space-4) + var(--safe-area-inset-top)); + padding: var(--space-3) var(--space-4) calc(var(--space-4) + var(--safe-area-inset-bottom)); } .search-overlay__empty { @@ -677,7 +676,7 @@ } /* Tooltip für collapsed Sidebar (nur Icons sichtbar bei 1024–1439px) */ -@media (min-width: 1024px) and (max-width: 1439px) { +@media (min-width: 1024px) and (max-width: 1279px) { .nav-sidebar .nav-item { overflow: visible; } @@ -711,7 +710,7 @@ /* ================================================================ * Sidebar Expanded (≥ 1280px) - Labels sichtbar * ================================================================ */ -@media (min-width: 1440px) { +@media (min-width: 1280px) { :root { --sidebar-width: var(--sidebar-width-expanded); } @@ -1463,6 +1462,10 @@ text-align: center; } +.empty-state__cta { + margin-top: var(--space-2); +} + .empty-state--compact { padding: var(--space-4) var(--space-3); gap: var(--space-2); diff --git a/public/styles/shopping.css b/public/styles/shopping.css index f080d13..da4fe2b 100644 --- a/public/styles/shopping.css +++ b/public/styles/shopping.css @@ -59,7 +59,7 @@ background-color: transparent; color: var(--color-text-secondary); transition: all var(--transition-fast); - min-height: 36px; + min-height: var(--target-base); } .list-tab:hover:not(.list-tab--active) {