From a872ac52a98df4a4007b59ee5d8865236ea64c0b Mon Sep 17 00:00:00 2001 From: Ulas Kalayci Date: Wed, 29 Apr 2026 19:03:04 +0200 Subject: [PATCH] chore: release v0.33.1 Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 7 ++++ package-lock.json | 4 +-- package.json | 2 +- public/router.js | 77 +++++++++++----------------------------- public/styles/layout.css | 46 +++++++++++++++++++++--- 5 files changed, 73 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41583e8..4ae24a6 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.33.1] - 2026-04-29 + +### Changed +- Navigation: removed the dedicated Search button from the bottom bar; the bottom bar now shows three primary module links plus the More button +- Navigation: the More sheet now opens with a full-width pill-shaped search trigger at the top, replacing the grid-cell search item +- Search: the search overlay input field is now positioned at the bottom of the screen (thumb zone) instead of the top + ## [0.33.0] - 2026-04-29 ### Added diff --git a/package-lock.json b/package-lock.json index 59cdcfd..e648175 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "oikos", - "version": "0.33.0", + "version": "0.33.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "oikos", - "version": "0.33.0", + "version": "0.33.1", "license": "MIT", "dependencies": { "bcrypt": "^6.0.0", diff --git a/package.json b/package.json index ac8c542..1f39977 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oikos", - "version": "0.33.0", + "version": "0.33.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/router.js b/public/router.js index 2e2b9a9..b2d17ef 100644 --- a/public/router.js +++ b/public/router.js @@ -478,20 +478,6 @@ function renderAppShell(container) { const bottomItems = document.createElement('div'); bottomItems.className = 'nav-bottom__items'; navItems().slice(0, PRIMARY_NAV).forEach((item) => bottomItems.appendChild(navItemEl(item))); - const searchNavBtn = document.createElement('button'); - searchNavBtn.className = 'nav-item nav-item--search'; - searchNavBtn.id = 'search-nav-btn'; - searchNavBtn.setAttribute('aria-label', t('search.title')); - const searchNavIcon = document.createElement('i'); - searchNavIcon.dataset.lucide = 'search'; - searchNavIcon.className = 'nav-item__icon'; - searchNavIcon.setAttribute('aria-hidden', 'true'); - const searchNavLabel = document.createElement('span'); - searchNavLabel.className = 'nav-item__label'; - searchNavLabel.textContent = t('search.title'); - searchNavBtn.appendChild(searchNavIcon); - searchNavBtn.appendChild(searchNavLabel); - bottomItems.appendChild(searchNavBtn); const moreBtn = document.createElement('button'); moreBtn.className = 'nav-item nav-item--more'; moreBtn.id = 'more-btn'; @@ -520,19 +506,20 @@ function renderAppShell(container) { moreSheet.setAttribute('role', 'dialog'); moreSheet.setAttribute('aria-label', t('nav.more')); moreSheet.setAttribute('aria-hidden', 'true'); - const searchBtn = document.createElement('button'); - searchBtn.className = 'more-item'; - searchBtn.id = 'search-btn'; - const searchIcon = document.createElement('i'); - searchIcon.dataset.lucide = 'search'; - searchIcon.className = 'more-item__icon'; - searchIcon.setAttribute('aria-hidden', 'true'); - const searchLabel = document.createElement('span'); - searchLabel.className = 'more-item__label'; - searchLabel.textContent = t('search.title'); - searchBtn.appendChild(searchIcon); - searchBtn.appendChild(searchLabel); - moreSheet.appendChild(searchBtn); + const searchTrigger = document.createElement('button'); + searchTrigger.className = 'more-sheet__search-trigger'; + searchTrigger.id = 'search-btn'; + searchTrigger.setAttribute('aria-label', t('search.title')); + const searchTriggerIcon = document.createElement('i'); + searchTriggerIcon.dataset.lucide = 'search'; + searchTriggerIcon.className = 'more-sheet__search-trigger-icon'; + searchTriggerIcon.setAttribute('aria-hidden', 'true'); + const searchTriggerText = document.createElement('span'); + searchTriggerText.className = 'more-sheet__search-trigger-placeholder'; + searchTriggerText.textContent = t('search.placeholder'); + searchTrigger.appendChild(searchTriggerIcon); + searchTrigger.appendChild(searchTriggerText); + moreSheet.appendChild(searchTrigger); navItems().slice(PRIMARY_NAV).forEach((item) => moreSheet.appendChild(moreItemEl(item))); const searchOverlay = document.createElement('div'); @@ -763,9 +750,8 @@ function initMoreSheet(container) { * Initialisiert die Suchfunktion (Overlay + API-Calls). */ function initSearch(container) { - const searchBtn = container.querySelector('#search-btn'); - const searchNavBtn = container.querySelector('#search-nav-btn'); - const searchClose = container.querySelector('#search-close'); + const searchBtn = container.querySelector('#search-btn'); + const searchClose = container.querySelector('#search-close'); const overlay = container.querySelector('#search-overlay'); const input = container.querySelector('#search-input'); const results = container.querySelector('#search-results'); @@ -812,7 +798,6 @@ function initSearch(container) { } searchBtn.addEventListener('click', openSearch); - if (searchNavBtn) searchNavBtn.addEventListener('click', openSearch); searchClose.addEventListener('click', closeSearch); document.addEventListener('keydown', (e) => { @@ -1137,34 +1122,14 @@ window.addEventListener('locale-changed', () => { if (bottomItems) { const moreBtn = bottomItems.querySelector('#more-btn'); const newItems = navItems().slice(0, PRIMARY_NAV).map(navItemEl); - // Such-Button neu erstellen (wird durch replaceChildren entfernt) - const newSearchBtn = document.createElement('button'); - newSearchBtn.className = 'nav-item nav-item--search'; - newSearchBtn.id = 'search-nav-btn'; - newSearchBtn.setAttribute('aria-label', t('search.title')); - const newSearchIcon = document.createElement('i'); - newSearchIcon.dataset.lucide = 'search'; - newSearchIcon.className = 'nav-item__icon'; - newSearchIcon.setAttribute('aria-hidden', 'true'); - const newSearchLbl = document.createElement('span'); - newSearchLbl.className = 'nav-item__label'; - newSearchLbl.textContent = t('search.title'); - newSearchBtn.appendChild(newSearchIcon); - newSearchBtn.appendChild(newSearchLbl); - bottomItems.replaceChildren(...newItems, newSearchBtn, moreBtn); - // Event-Listener auf neuen Such-Button - if (newSearchBtn) { - newSearchBtn.addEventListener('click', () => { - if (window._openSearch) window._openSearch(); - }); - } + bottomItems.replaceChildren(...newItems, moreBtn); } if (moreSheet) { - const searchBtn = moreSheet.querySelector('#search-btn'); - const searchLbl = searchBtn?.querySelector('.more-item__label'); - if (searchLbl) searchLbl.textContent = t('search.title'); + const searchTrig = moreSheet.querySelector('#search-btn'); + const searchTrigPlaceholder = searchTrig?.querySelector('.more-sheet__search-trigger-placeholder'); + if (searchTrigPlaceholder) searchTrigPlaceholder.textContent = t('search.placeholder'); const newMoreItems = navItems().slice(PRIMARY_NAV).map(moreItemEl); - moreSheet.replaceChildren(searchBtn, ...newMoreItems); + moreSheet.replaceChildren(searchTrig, ...newMoreItems); } document.querySelectorAll('[data-route]').forEach((el) => { diff --git a/public/styles/layout.css b/public/styles/layout.css index 79f43ae..5fa3072 100755 --- a/public/styles/layout.css +++ b/public/styles/layout.css @@ -268,6 +268,43 @@ line-height: 1.2; } +/* ── More-Sheet Suchtrigger ── */ +.more-sheet__search-trigger { + grid-column: 1 / -1; + display: flex; + align-items: center; + gap: var(--space-2); + padding: 0 var(--space-4); + height: var(--target-lg); + border-radius: var(--radius-full); + border: 1.5px solid var(--color-border); + background-color: var(--color-surface-elevated); + color: var(--color-text-tertiary); + cursor: pointer; + font-family: inherit; + font-size: var(--text-sm); + text-align: left; + width: 100%; + -webkit-tap-highlight-color: transparent; + transition: background-color var(--transition-fast), border-color var(--transition-fast); +} + +.more-sheet__search-trigger:active { + background-color: var(--color-surface-hover); + border-color: var(--color-accent); + transform: scale(0.98); +} + +.more-sheet__search-trigger-icon { + width: var(--space-4); + height: var(--space-4); + flex-shrink: 0; +} + +.more-sheet__search-trigger-placeholder { + flex: 1; +} + /* ── Such-Overlay ── */ .search-overlay { position: fixed; @@ -275,7 +312,7 @@ background-color: var(--color-surface); z-index: calc(var(--z-nav) + 3); display: flex; - flex-direction: column; + flex-direction: column-reverse; transform: translateY(100%); transition: transform 0.25s var(--ease-out); } @@ -288,8 +325,8 @@ display: flex; align-items: center; gap: var(--space-3); - padding: calc(var(--space-4) + var(--safe-area-inset-top)) var(--space-4) var(--space-3); - border-bottom: 1px solid var(--color-border-subtle); + padding: var(--space-3) var(--space-4) calc(var(--space-4) + var(--safe-area-inset-bottom)); + border-top: 1px solid var(--color-border-subtle); } .search-overlay__input { @@ -331,7 +368,8 @@ .search-overlay__results { flex: 1; overflow-y: auto; - padding: var(--space-4); + padding: var(--space-4) var(--space-4) var(--space-2); + padding-top: calc(var(--space-4) + var(--safe-area-inset-top)); } .search-overlay__empty {