diff --git a/CHANGELOG.md b/CHANGELOG.md index 131de13..0b0b350 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.16.0] - 2026-04-06 + +### Added +- Settings: categorized tab navigation - six tabs (General, Meals, Budget, Shopping, Calendar, Account) replace the flat scrolling layout (#30) +- Settings: active tab persists across page navigations via sessionStorage +- Settings: Calendar tab is automatically activated when returning from a Google/Apple OAuth callback +- Settings: tab bar is sticky so it stays visible while scrolling through tab content +- Settings: all tab labels fully translated in de, en, es, it, sv + ## [0.15.0] - 2026-04-06 ### Changed diff --git a/public/locales/de.json b/public/locales/de.json index 2a0255f..4308d37 100644 --- a/public/locales/de.json +++ b/public/locales/de.json @@ -30,7 +30,6 @@ "confirm": "Bestätigen", "undo": "Rückgängig" }, - "nav": { "dashboard": "Übersicht", "tasks": "Aufgaben", @@ -45,7 +44,6 @@ "navigation": "Navigation", "quickActions": "Schnellaktionen" }, - "dashboard": { "title": "Übersicht", "greetingMorning": "Guten Morgen, {{name}}", @@ -81,7 +79,6 @@ "allDay": "Ganztägig", "shoppingMore": "+{{count}} weitere" }, - "tasks": { "title": "Aufgaben", "newTask": "Neue Aufgabe", @@ -149,7 +146,6 @@ "listView": "Listenansicht", "kanbanView": "Kanban-Ansicht" }, - "shopping": { "title": "Einkauf", "noLists": "Keine Listen", @@ -190,7 +186,6 @@ "catDrugstore": "Drogerie", "catMisc": "Sonstiges" }, - "meals": { "title": "Essensplan", "noMealPlanned": "Kein Essen geplant", @@ -239,7 +234,6 @@ "recipeUrlPlaceholder": "https://…", "openRecipe": "Rezept öffnen" }, - "calendar": { "title": "Kalender", "newEvent": "Neuer Termin", @@ -272,7 +266,7 @@ "locationPlaceholder": "Optional", "assignedLabel": "Zugewiesen an", "assignedNobody": "- Niemand -", - "colorLabel": "Farbe", + "colorLabel": "Farbe {{color}}", "descriptionLabel": "Beschreibung", "descriptionPlaceholder": "Optional…", "popupEdit": "Bearbeiten", @@ -310,10 +304,8 @@ "dayLongThursday": "Donnerstag", "dayLongFriday": "Freitag", "dayLongSaturday": "Samstag", - "timeSuffix": "Uhr", - "colorLabel": "Farbe {{color}}" + "timeSuffix": "Uhr" }, - "notes": { "title": "Pinnwand", "newNote": "Neue Notiz", @@ -352,7 +344,6 @@ "formatQuote": "Zitat", "formatDivider": "Trennlinie" }, - "contacts": { "title": "Kontakte", "newContact": "Neuer Kontakt", @@ -406,7 +397,6 @@ "categoryEmergency": "Notfall", "categoryOther": "Sonstiges" }, - "budget": { "title": "Budget", "newEntry": "Neuer Eintrag", @@ -454,9 +444,15 @@ "catMisc": "Sonstiges", "loadingIndicator": "Lade…" }, - "settings": { "title": "Einstellungen", + "tabGeneral": "Allgemein", + "tabMeals": "Mahlzeiten", + "tabBudget": "Budget", + "tabShopping": "Einkauf", + "tabCalendar": "Kalender", + "tabAccount": "Konto", + "tabsAriaLabel": "Einstellungsbereiche", "sectionDesign": "Design", "sectionShopping": "Einkauf", "shoppingCategoriesLabel": "Einkaufskategorien", @@ -547,7 +543,6 @@ "currencyHint": "Legt die Währung für den gesamten Budget-Bereich fest.", "currencySaved": "Währung gespeichert." }, - "login": { "tagline": "Familienplanung. Sicher. Datenschutzfreundlich. Open Source.", "usernameLabel": "Benutzername", @@ -559,20 +554,17 @@ "tooManyAttempts": "Zu viele Versuche. Bitte warte kurz.", "invalidCredentials": "Ungültige Anmeldedaten." }, - "install": { "title": "Oikos installieren", "subtitle": "Zur App hinzufügen", "iosTip1": "Tippe auf ", - "iosTip2": " \u2192 \"Zum Home-Bildschirm\"", + "iosTip2": " → \"Zum Home-Bildschirm\"", "installButton": "Installieren", "dismissLabel": "Schließen" }, - "modal": { "closeLabel": "Schließen" }, - "rrule": { "freqNone": "Keine Wiederholung", "freqDaily": "Täglich", @@ -596,4 +588,4 @@ "unitMonth": "Monat", "unitMonths": "Monate" } -} +} \ No newline at end of file diff --git a/public/locales/en.json b/public/locales/en.json index 249993a..1d121ea 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -30,7 +30,6 @@ "confirm": "Confirm", "undo": "Undo" }, - "nav": { "dashboard": "Overview", "tasks": "Tasks", @@ -45,7 +44,6 @@ "navigation": "Navigation", "quickActions": "Quick actions" }, - "dashboard": { "title": "Overview", "greetingMorning": "Good morning, {{name}}", @@ -81,7 +79,6 @@ "allDay": "All day", "shoppingMore": "+{{count}} more" }, - "tasks": { "title": "Tasks", "newTask": "New Task", @@ -149,7 +146,6 @@ "listView": "List view", "kanbanView": "Kanban view" }, - "shopping": { "title": "Shopping", "noLists": "No lists", @@ -190,7 +186,6 @@ "catDrugstore": "Drugstore", "catMisc": "Miscellaneous" }, - "meals": { "title": "Meal Plan", "noMealPlanned": "No meal planned", @@ -239,7 +234,6 @@ "recipeUrlPlaceholder": "https://…", "openRecipe": "Open recipe" }, - "calendar": { "title": "Calendar", "newEvent": "New Event", @@ -272,7 +266,7 @@ "locationPlaceholder": "Optional", "assignedLabel": "Assigned to", "assignedNobody": "- Nobody -", - "colorLabel": "Color", + "colorLabel": "Color {{color}}", "descriptionLabel": "Description", "descriptionPlaceholder": "Optional…", "popupEdit": "Edit", @@ -310,10 +304,8 @@ "dayLongThursday": "Thursday", "dayLongFriday": "Friday", "dayLongSaturday": "Saturday", - "timeSuffix": "", - "colorLabel": "Color {{color}}" + "timeSuffix": "" }, - "notes": { "title": "Board", "newNote": "New Note", @@ -352,7 +344,6 @@ "formatQuote": "Quote", "formatDivider": "Divider" }, - "contacts": { "title": "Contacts", "newContact": "New Contact", @@ -406,7 +397,6 @@ "categoryEmergency": "Emergency", "categoryOther": "Other" }, - "budget": { "title": "Budget", "newEntry": "New Entry", @@ -454,9 +444,15 @@ "catMisc": "Miscellaneous", "loadingIndicator": "Loading…" }, - "settings": { "title": "Settings", + "tabGeneral": "General", + "tabMeals": "Meals", + "tabBudget": "Budget", + "tabShopping": "Shopping", + "tabCalendar": "Calendar", + "tabAccount": "Account", + "tabsAriaLabel": "Settings sections", "sectionDesign": "Appearance", "sectionShopping": "Shopping", "shoppingCategoriesLabel": "Shopping Categories", @@ -547,7 +543,6 @@ "currencyHint": "Sets the currency used throughout the budget section.", "currencySaved": "Currency saved." }, - "login": { "tagline": "Family planning. Secure. Privacy-friendly. Open source.", "usernameLabel": "Username", @@ -559,7 +554,6 @@ "tooManyAttempts": "Too many attempts. Please wait a moment.", "invalidCredentials": "Invalid credentials." }, - "install": { "title": "Install Oikos", "subtitle": "Add to home screen", @@ -568,11 +562,9 @@ "installButton": "Install", "dismissLabel": "Close" }, - "modal": { "closeLabel": "Close" }, - "rrule": { "freqNone": "No recurrence", "freqDaily": "Daily", @@ -596,4 +588,4 @@ "unitMonth": "month", "unitMonths": "months" } -} +} \ No newline at end of file diff --git a/public/locales/es.json b/public/locales/es.json index 5452eea..e4594e6 100644 --- a/public/locales/es.json +++ b/public/locales/es.json @@ -30,7 +30,6 @@ "confirm": "Confirmar", "undo": "Deshacer" }, - "nav": { "dashboard": "Inicio", "tasks": "Tareas", @@ -45,7 +44,6 @@ "navigation": "Navegación", "quickActions": "Acciones rápidas" }, - "dashboard": { "title": "Inicio", "greetingMorning": "Buenos días, {{name}}", @@ -81,7 +79,6 @@ "allDay": "Todo el día", "shoppingMore": "+{{count}} más" }, - "tasks": { "title": "Tareas", "newTask": "Nueva tarea", @@ -149,7 +146,6 @@ "listView": "Vista de lista", "kanbanView": "Vista Kanban" }, - "shopping": { "title": "Compras", "noLists": "Sin listas", @@ -190,7 +186,6 @@ "catDrugstore": "Droguería", "catMisc": "Otros" }, - "meals": { "title": "Plan de comidas", "noMealPlanned": "Sin comida planificada", @@ -239,7 +234,6 @@ "recipeUrlPlaceholder": "https://…", "openRecipe": "Abrir receta" }, - "calendar": { "title": "Calendario", "newEvent": "Nuevo evento", @@ -272,7 +266,7 @@ "locationPlaceholder": "Opcional", "assignedLabel": "Asignado a", "assignedNobody": "- Nadie -", - "colorLabel": "Color", + "colorLabel": "Color {{color}}", "descriptionLabel": "Descripción", "descriptionPlaceholder": "Opcional…", "popupEdit": "Editar", @@ -310,10 +304,8 @@ "dayLongThursday": "Jueves", "dayLongFriday": "Viernes", "dayLongSaturday": "Sábado", - "timeSuffix": "", - "colorLabel": "Color {{color}}" + "timeSuffix": "" }, - "notes": { "title": "Notas", "newNote": "Nueva nota", @@ -352,7 +344,6 @@ "formatQuote": "Cita", "formatDivider": "Separador" }, - "contacts": { "title": "Contactos", "newContact": "Nuevo contacto", @@ -406,7 +397,6 @@ "categoryEmergency": "Emergencia", "categoryOther": "Otros" }, - "budget": { "title": "Presupuesto", "newEntry": "Nueva entrada", @@ -454,9 +444,15 @@ "catMisc": "Otros", "loadingIndicator": "Cargando…" }, - "settings": { "title": "Ajustes", + "tabGeneral": "General", + "tabMeals": "Comidas", + "tabBudget": "Presupuesto", + "tabShopping": "Compras", + "tabCalendar": "Calendario", + "tabAccount": "Cuenta", + "tabsAriaLabel": "Secciones de configuración", "sectionDesign": "Diseño", "sectionShopping": "Compras", "shoppingCategoriesLabel": "Categorías de compra", @@ -547,7 +543,6 @@ "currencyHint": "Establece la moneda para toda la sección de presupuesto.", "currencySaved": "Moneda guardada." }, - "login": { "tagline": "Planificación familiar. Segura. Privada. Código abierto.", "usernameLabel": "Nombre de usuario", @@ -559,7 +554,6 @@ "tooManyAttempts": "Demasiados intentos. Por favor, espera un momento.", "invalidCredentials": "Credenciales incorrectas." }, - "install": { "title": "Instalar Oikos", "subtitle": "Añadir a la pantalla de inicio", @@ -568,11 +562,9 @@ "installButton": "Instalar", "dismissLabel": "Cerrar" }, - "modal": { "closeLabel": "Cerrar" }, - "rrule": { "freqNone": "Sin repetición", "freqDaily": "Diariamente", @@ -596,4 +588,4 @@ "unitMonth": "mes", "unitMonths": "meses" } -} +} \ No newline at end of file diff --git a/public/locales/it.json b/public/locales/it.json index bc27378..649e728 100644 --- a/public/locales/it.json +++ b/public/locales/it.json @@ -30,7 +30,6 @@ "confirm": "Conferma", "undo": "Annulla" }, - "nav": { "dashboard": "Panoramica", "tasks": "Compiti", @@ -45,7 +44,6 @@ "navigation": "Navigazione", "quickActions": "Azioni rapide" }, - "dashboard": { "title": "Panoramica", "greetingMorning": "Buongiorno, {{name}}", @@ -81,7 +79,6 @@ "allDay": "Tutto il giorno", "shoppingMore": "+{{count}} altri" }, - "tasks": { "title": "Compiti", "newTask": "Nuovo compito", @@ -149,7 +146,6 @@ "listView": "Vista elenco", "kanbanView": "Vista Kanban" }, - "shopping": { "title": "Spesa", "noLists": "Nessuna lista", @@ -190,7 +186,6 @@ "catDrugstore": "Drogheria", "catMisc": "Varie" }, - "meals": { "title": "Piano pasti", "noMealPlanned": "Nessun pasto pianificato", @@ -239,7 +234,6 @@ "recipeUrlPlaceholder": "https://…", "openRecipe": "Apri ricetta" }, - "calendar": { "title": "Calendario", "newEvent": "Nuovo evento", @@ -272,7 +266,7 @@ "locationPlaceholder": "Opzionale", "assignedLabel": "Assegnato a", "assignedNobody": "- Nessuno -", - "colorLabel": "Colore", + "colorLabel": "Colore {{color}}", "descriptionLabel": "Descrizione", "descriptionPlaceholder": "Opzionale…", "popupEdit": "Modifica", @@ -310,10 +304,8 @@ "dayLongThursday": "Giovedì", "dayLongFriday": "Venerdì", "dayLongSaturday": "Sabato", - "timeSuffix": "", - "colorLabel": "Colore {{color}}" + "timeSuffix": "" }, - "notes": { "title": "Bacheca", "newNote": "Nuova nota", @@ -352,7 +344,6 @@ "formatQuote": "Citazione", "formatDivider": "Divisore" }, - "contacts": { "title": "Contatti", "newContact": "Nuovo contatto", @@ -406,7 +397,6 @@ "categoryEmergency": "Emergenza", "categoryOther": "Altro" }, - "budget": { "title": "Bilancio", "newEntry": "Nuova voce", @@ -454,9 +444,15 @@ "catMisc": "Varie", "loadingIndicator": "Caricamento…" }, - "settings": { "title": "Impostazioni", + "tabGeneral": "Generale", + "tabMeals": "Pasti", + "tabBudget": "Budget", + "tabShopping": "Spesa", + "tabCalendar": "Calendario", + "tabAccount": "Account", + "tabsAriaLabel": "Sezioni impostazioni", "sectionDesign": "Aspetto", "sectionShopping": "Spesa", "shoppingCategoriesLabel": "Categorie spesa", @@ -547,7 +543,6 @@ "currencyHint": "Imposta la valuta utilizzata in tutta la sezione budget.", "currencySaved": "Valuta salvata." }, - "login": { "tagline": "Pianificazione familiare. Sicura. Rispettosa della privacy. Open source.", "usernameLabel": "Nome utente", @@ -559,7 +554,6 @@ "tooManyAttempts": "Troppi tentativi. Attendi un momento.", "invalidCredentials": "Credenziali non valide." }, - "install": { "title": "Installa Oikos", "subtitle": "Aggiungi alla schermata home", @@ -568,8 +562,7 @@ "installButton": "Installa", "dismissLabel": "Chiudi" }, - "modal": { "closeLabel": "Chiudi" } -} +} \ No newline at end of file diff --git a/public/locales/sv.json b/public/locales/sv.json index 0630a78..34eac24 100644 --- a/public/locales/sv.json +++ b/public/locales/sv.json @@ -30,7 +30,6 @@ "confirm": "Bekräfta", "undo": "Ångra" }, - "nav": { "dashboard": "Översikt", "tasks": "Uppgifter", @@ -45,7 +44,6 @@ "navigation": "Navigering", "quickActions": "Snabba åtgärder" }, - "dashboard": { "title": "Översikt", "greetingMorning": "God morgon, {{name}}", @@ -81,7 +79,6 @@ "allDay": "Hela dagen", "shoppingMore": "+{{count}} till" }, - "tasks": { "title": "Uppgifter", "newTask": "Ny uppgift", @@ -149,7 +146,6 @@ "listView": "Listvy", "kanbanView": "Kanban-vy" }, - "shopping": { "title": "Shopping", "noLists": "Inga listor", @@ -190,7 +186,6 @@ "catDrugstore": "Apotek", "catMisc": "Diverse" }, - "meals": { "title": "Måltidsplan", "noMealPlanned": "Ingen måltid planerad", @@ -239,7 +234,6 @@ "recipeUrlPlaceholder": "https://…", "openRecipe": "Öppna recept" }, - "calendar": { "title": "Kalender", "newEvent": "Ny händelse", @@ -272,7 +266,7 @@ "locationPlaceholder": "Frivillig", "assignedLabel": "Tilldelad till", "assignedNobody": "- Ingen -", - "colorLabel": "Färg", + "colorLabel": "Färg {{color}}", "descriptionLabel": "Beskrivning", "descriptionPlaceholder": "Frivillig…", "popupEdit": "Redigera", @@ -310,10 +304,8 @@ "dayLongThursday": "Torsdag", "dayLongFriday": "Fredag", "dayLongSaturday": "Lördag", - "timeSuffix": "", - "colorLabel": "Färg {{color}}" + "timeSuffix": "" }, - "notes": { "title": "Anteckningar", "newNote": "Ny anteckning", @@ -352,7 +344,6 @@ "formatQuote": "Citationstecken", "formatDivider": "Delare" }, - "contacts": { "title": "Kontakter", "newContact": "Ny kontakt", @@ -406,7 +397,6 @@ "categoryEmergency": "Nödsituation", "categoryOther": "Andra" }, - "budget": { "title": "Budget", "newEntry": "Nytt inlägg", @@ -454,9 +444,15 @@ "catMisc": "Diverse", "loadingIndicator": "Laddar…" }, - "settings": { "title": "Inställningar", + "tabGeneral": "Allmänt", + "tabMeals": "Måltider", + "tabBudget": "Budget", + "tabShopping": "Inköp", + "tabCalendar": "Kalender", + "tabAccount": "Konto", + "tabsAriaLabel": "Inställningsavsnitt", "sectionDesign": "Utseende", "sectionShopping": "Inköp", "shoppingCategoriesLabel": "Inköpskategorier", @@ -547,7 +543,6 @@ "currencyHint": "Ställer in valutan som används i hela budgetavsnittet.", "currencySaved": "Valuta sparad." }, - "login": { "tagline": "Familjeplanering. Säker. Sekretessvänlig. Öppen källkod.", "usernameLabel": "Användarnamn", @@ -559,7 +554,6 @@ "tooManyAttempts": "För många försök. Vänta ett ögonblick.", "invalidCredentials": "Ogiltiga användaruppgifter." }, - "install": { "title": "Installera Oikos", "subtitle": "Lägg till på startskärmen", @@ -568,11 +562,9 @@ "installButton": "Installera", "dismissLabel": "Stäng" }, - "modal": { "closeLabel": "Stäng" }, - "rrule": { "freqNone": "Ingen upprepning", "freqDaily": "Dagligen", @@ -596,4 +588,4 @@ "unitMonth": "månad", "unitMonths": "månader" } -} +} \ No newline at end of file diff --git a/public/pages/settings.js b/public/pages/settings.js index 66dbde8..8560c26 100644 --- a/public/pages/settings.js +++ b/public/pages/settings.js @@ -11,6 +11,7 @@ import { esc } from '/utils/html.js'; import '/components/oikos-locale-picker.js'; const SUPPORTED_CURRENCIES = ['AUD', 'CAD', 'CHF', 'CZK', 'DKK', 'EUR', 'GBP', 'HUF', 'JPY', 'NOK', 'PLN', 'SEK', 'USD']; +const SETTINGS_TAB_KEY = 'oikos:settings:tab'; function buildCurrencyOptions(selected) { const display = typeof Intl.DisplayNames !== 'undefined' @@ -67,6 +68,14 @@ export async function render(container, { user }) { ? (appleStatus.lastSync ? t('settings.configuredLastSync', { date: formatDateTime(appleStatus.lastSync) }) : t('settings.configured')) : t('settings.notConnected'); + const activeTab = (syncOk || syncErr) + ? 'calendar' + : (sessionStorage.getItem(SETTINGS_TAB_KEY) ?? 'general'); + + const panelHidden = (id) => id === activeTab ? '' : ' hidden'; + const btnClass = (id) => `settings-tab-btn${id === activeTab ? ' settings-tab-btn--active' : ''}`; + const btnAria = (id) => id === activeTab ? 'true' : 'false'; + container.innerHTML = `
${t('settings.mealTypesHint')}
-${t('settings.currencyHint')}
- -${t('settings.shoppingCategoriesHint')}
-