From 0421b540cd602a1111e273ac1783edaa0ea9cb84 Mon Sep 17 00:00:00 2001 From: Ulas Date: Sat, 4 Apr 2026 22:34:29 +0200 Subject: [PATCH] feat(tasks): persist view mode and support ?view=kanban URL parameter View mode (list/kanban) is now saved to localStorage and restored on page load. URL parameter ?view=kanban takes precedence, enabling tablet kiosk setups to default to Kanban view. Toggle buttons reflect the active view correctly on initial render. Closes #17 --- CHANGELOG.md | 7 +++++++ package.json | 2 +- public/pages/tasks.js | 20 +++++++++++++++----- public/sw.js | 6 +++--- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c24a51..1d570e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.9.1] - 2026-04-04 + +### Added +- Persist task view mode (list/kanban) across sessions via localStorage (#17) +- Support URL parameter `?view=kanban` to open tasks directly in Kanban view - ideal for tablet kiosk setups +- View toggle button reflects the persisted/URL-driven view on page load + ## [0.9.0] - 2026-04-04 ### Added diff --git a/package.json b/package.json index 09b4f6e..6e132b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oikos", - "version": "0.9.0", + "version": "0.9.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/pages/tasks.js b/public/pages/tasks.js index 29f6237..b73f5f5 100644 --- a/public/pages/tasks.js +++ b/public/pages/tasks.js @@ -356,7 +356,7 @@ let state = { users: [], filters: { status: '', priority: '', assigned_to: '' }, groupMode: 'category', // 'category' | 'due' - viewMode: 'list', // 'list' | 'kanban' + viewMode: 'list', // 'list' | 'kanban' (resolved at render time) expandedTasks: new Set(), dragTaskId: null, }; @@ -872,6 +872,7 @@ function wireViewToggle(container) { toggle.querySelectorAll('[data-view]').forEach((btn) => { btn.addEventListener('click', () => { state.viewMode = btn.dataset.view; + localStorage.setItem('oikos-tasks-view', state.viewMode); toggle.querySelectorAll('[data-view]').forEach((b) => b.classList.toggle('group-toggle__btn--active', b.dataset.view === state.viewMode) ); @@ -962,23 +963,32 @@ function wireTaskList(container) { // -------------------------------------------------------- export async function render(container, { user }) { - // Initiales Skeleton + // View-Mode: URL-Parameter > localStorage > Default 'list' + const urlView = new URLSearchParams(window.location.search).get('view'); + const savedView = localStorage.getItem('oikos-tasks-view'); + state.viewMode = (urlView === 'kanban' || urlView === 'list') ? urlView + : (savedView === 'kanban' || savedView === 'list') ? savedView + : 'list'; + + const isKanban = state.viewMode === 'kanban'; + + // Initiales Skeleton (all values are from i18n keys or hardcoded constants, no user data) container.innerHTML = `

${t('tasks.title')}

- -
-
+
diff --git a/public/sw.js b/public/sw.js index 8ce6352..7b04d68 100644 --- a/public/sw.js +++ b/public/sw.js @@ -12,9 +12,9 @@ * API: Immer Netzwerk (kein Caching von Nutzerdaten) */ -const SHELL_CACHE = 'oikos-shell-v24'; -const PAGES_CACHE = 'oikos-pages-v24'; -const ASSETS_CACHE = 'oikos-assets-v24'; +const SHELL_CACHE = 'oikos-shell-v25'; +const PAGES_CACHE = 'oikos-pages-v25'; +const ASSETS_CACHE = 'oikos-assets-v25'; const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, ASSETS_CACHE]; // App-Shell: sofort benötigt für ersten Render