diff --git a/public/pages/budget.js b/public/pages/budget.js index 81765a6..eefd4c4 100644 --- a/public/pages/budget.js +++ b/public/pages/budget.js @@ -98,6 +98,9 @@ export async function render(container, { user }) {
Lade…
+ `; @@ -131,7 +134,9 @@ function wireNav() { renderBody(); updateLabel(); }); - _container.querySelector('#budget-add').addEventListener('click', () => openModal({ mode: 'create' })); + const addHandler = () => openModal({ mode: 'create' }); + _container.querySelector('#budget-add').addEventListener('click', addHandler); + _container.querySelector('#fab-new-budget').addEventListener('click', addHandler); updateLabel(); } diff --git a/public/pages/calendar.js b/public/pages/calendar.js index e8eceba..b84377e 100644 --- a/public/pages/calendar.js +++ b/public/pages/calendar.js @@ -159,6 +159,9 @@ export async function render(container, { user }) {
+
`; @@ -167,6 +170,8 @@ export async function render(container, { user }) { renderToolbar(); renderView(); + + container.querySelector('#fab-new-event')?.addEventListener('click', () => openEventModal({ mode: 'create' })); } // -------------------------------------------------------- diff --git a/public/pages/contacts.js b/public/pages/contacts.js index 733bfe8..14d740a 100644 --- a/public/pages/contacts.js +++ b/public/pages/contacts.js @@ -61,6 +61,9 @@ export async function render(container, { user }) { `).join('')}
+ `; @@ -92,9 +95,9 @@ export async function render(container, { user }) { }); // Neu - _container.querySelector('#contacts-add-btn').addEventListener('click', () => - openModal({ mode: 'create' }) - ); + const addHandler = () => openModal({ mode: 'create' }); + _container.querySelector('#contacts-add-btn').addEventListener('click', addHandler); + _container.querySelector('#fab-new-contact').addEventListener('click', addHandler); } // -------------------------------------------------------- diff --git a/public/pages/notes.js b/public/pages/notes.js index 09ca433..89599bc 100644 --- a/public/pages/notes.js +++ b/public/pages/notes.js @@ -53,6 +53,9 @@ export async function render(container, { user }) {
+ `; @@ -68,7 +71,9 @@ export async function render(container, { user }) { } renderGrid(); - _container.querySelector('#notes-add-btn').addEventListener('click', () => openModal({ mode: 'create' })); + const addHandler = () => openModal({ mode: 'create' }); + _container.querySelector('#notes-add-btn').addEventListener('click', addHandler); + _container.querySelector('#fab-new-note').addEventListener('click', addHandler); } // -------------------------------------------------------- diff --git a/public/pages/tasks.js b/public/pages/tasks.js index 9d9e87c..479f135 100644 --- a/public/pages/tasks.js +++ b/public/pages/tasks.js @@ -864,10 +864,12 @@ function wireGroupToggle(container) { } function wireNewTaskBtn(container) { - container.querySelector('#btn-new-task')?.addEventListener('click', () => { + const handler = () => { openModal(renderModal({ users: state.users })); wireModalEvents(container); - }); + }; + container.querySelector('#btn-new-task')?.addEventListener('click', handler); + container.querySelector('#fab-new-task')?.addEventListener('click', handler); } function wireModalEvents(container) { @@ -974,6 +976,9 @@ export async function render(container, { user }) {
`).join('')} + `; diff --git a/public/styles/dashboard.css b/public/styles/dashboard.css index 0484b85..de424fa 100644 --- a/public/styles/dashboard.css +++ b/public/styles/dashboard.css @@ -621,7 +621,7 @@ * -------------------------------------------------------- */ .fab-container { position: fixed; - bottom: calc(var(--nav-height-mobile) + var(--safe-area-inset-bottom) + var(--space-4)); + bottom: calc(var(--nav-height-mobile) + 24px + var(--safe-area-inset-bottom)); right: var(--space-4); z-index: calc(var(--z-nav) - 1); display: flex; diff --git a/public/styles/layout.css b/public/styles/layout.css index 1341a7e..def2b7e 100644 --- a/public/styles/layout.css +++ b/public/styles/layout.css @@ -177,6 +177,58 @@ line-height: 1; } +/* -------------------------------------------------------- + * Page FAB — Schwebender Erstellen-Button (nur Mobile/Tablet) + * + * Einheitlicher FAB auf Unterseiten. Auf Desktop versteckt, + * da der Toolbar-Button dort gut erreichbar ist. + * -------------------------------------------------------- */ +.page-fab { + position: fixed; + bottom: calc(var(--nav-height-mobile) + 24px + var(--safe-area-inset-bottom)); + right: var(--space-4); + width: 52px; + height: 52px; + border-radius: var(--radius-full); + background-color: var(--color-accent); + color: #ffffff; + box-shadow: var(--shadow-lg); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border: none; + z-index: calc(var(--z-nav) - 1); + transition: transform var(--transition-base), background-color var(--transition-fast); + -webkit-tap-highlight-color: transparent; +} + +.page-fab:hover { + background-color: var(--color-accent-hover); +} + +.page-fab:active { + transform: scale(0.92); +} + +/* Auf Desktop: FAB verstecken, Toolbar-Button reicht */ +@media (min-width: 1024px) { + .page-fab { + display: none; + } +} + +/* Auf Mobile: Toolbar-"Neu"-Buttons verstecken, FAB übernimmt */ +@media (max-width: 1023px) { + #btn-new-task, + #notes-add-btn, + #contacts-add-btn, + #budget-add, + #cal-add { + display: none !important; + } +} + /* ================================================================ * Sidebar Navigation — Desktop (≥ 1024px) * diff --git a/public/sw.js b/public/sw.js index 3ad0181..fd5eecb 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-v12'; -const PAGES_CACHE = 'oikos-pages-v12'; -const ASSETS_CACHE = 'oikos-assets-v12'; +const SHELL_CACHE = 'oikos-shell-v13'; +const PAGES_CACHE = 'oikos-pages-v13'; +const ASSETS_CACHE = 'oikos-assets-v13'; const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, ASSETS_CACHE]; // App-Shell: sofort benötigt für ersten Render