feat: restructure bottom-nav — search as primary slot, sidebar tooltips for collapsed mode

This commit is contained in:
Ulas Kalayci
2026-04-29 13:12:56 +02:00
parent 9b7909f690
commit 50b224eaef
2 changed files with 83 additions and 14 deletions
+41 -4
View File
@@ -131,7 +131,7 @@ let _pendingLoginRedirect = false;
const ROUTE_ORDER = ['/', '/tasks', '/calendar', '/birthdays', '/meals', '/recipes', '/shopping',
'/notes', '/contacts', '/budget', '/documents', '/settings'];
const PRIMARY_NAV = 4;
const PRIMARY_NAV = 3;
const DEFAULT_APP_NAME = 'Oikos';
const APP_NAME_STORAGE_KEY = 'oikos-app-name';
@@ -478,6 +478,20 @@ 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';
@@ -750,6 +764,7 @@ function initMoreSheet(container) {
*/
function initSearch(container) {
const searchBtn = container.querySelector('#search-btn');
const searchNavBtn = container.querySelector('#search-nav-btn');
const searchClose = container.querySelector('#search-close');
const overlay = container.querySelector('#search-overlay');
const input = container.querySelector('#search-input');
@@ -762,6 +777,7 @@ function initSearch(container) {
let _searchTrapHandler = null;
function openSearch() {
window._openSearch = openSearch;
if (window._closeMoreSheet) window._closeMoreSheet();
overlay.setAttribute('aria-hidden', 'false');
overlay.classList.add('search-overlay--visible');
@@ -796,6 +812,7 @@ function initSearch(container) {
}
searchBtn.addEventListener('click', openSearch);
if (searchNavBtn) searchNavBtn.addEventListener('click', openSearch);
searchClose.addEventListener('click', closeSearch);
document.addEventListener('keydown', (e) => {
@@ -872,11 +889,11 @@ function navItems() {
return [
{ path: '/', label: t('nav.dashboard'), icon: 'layout-dashboard' },
{ path: '/tasks', label: t('nav.tasks'), icon: 'check-square' },
{ path: '/birthdays', label: t('nav.birthdays'), icon: 'cake' },
{ path: '/calendar', label: t('nav.calendar'), icon: 'calendar' },
{ path: '/shopping', label: t('nav.shopping'), icon: 'shopping-cart' },
{ path: '/meals', label: t('nav.meals'), icon: 'utensils' },
{ path: '/recipes', label: t('nav.recipes'), icon: 'book-text' },
{ path: '/shopping', label: t('nav.shopping'), icon: 'shopping-cart' },
{ path: '/birthdays', label: t('nav.birthdays'), icon: 'cake' },
{ path: '/notes', label: t('nav.notes'), icon: 'sticky-note' },
{ path: '/contacts', label: t('nav.contacts'), icon: 'book-user' },
{ path: '/budget', label: t('nav.budget'), icon: 'wallet' },
@@ -1120,7 +1137,27 @@ window.addEventListener('locale-changed', () => {
if (bottomItems) {
const moreBtn = bottomItems.querySelector('#more-btn');
const newItems = navItems().slice(0, PRIMARY_NAV).map(navItemEl);
bottomItems.replaceChildren(...newItems, moreBtn);
// 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();
});
}
}
if (moreSheet) {
const searchBtn = moreSheet.querySelector('#search-btn');
+32
View File
@@ -663,6 +663,38 @@
}
}
/* Tooltip für collapsed Sidebar (nur Icons sichtbar bei 10241439px) */
@media (min-width: 1024px) and (max-width: 1439px) {
.nav-sidebar .nav-item {
overflow: visible;
}
.nav-sidebar .nav-item::after {
content: attr(title);
position: absolute;
left: calc(var(--sidebar-width) + var(--space-2));
top: 50%;
transform: translateY(-50%);
background: var(--color-surface);
color: var(--color-text-primary);
padding: var(--space-1) var(--space-3);
border-radius: var(--radius-sm);
box-shadow: var(--shadow-md);
border: 1px solid var(--color-border-subtle);
white-space: nowrap;
font-size: var(--text-sm);
font-weight: var(--font-weight-medium);
pointer-events: none;
opacity: 0;
transition: opacity 0.15s ease;
z-index: calc(var(--z-nav) + 10);
}
.nav-sidebar .nav-item:hover::after {
opacity: 1;
}
}
/* ================================================================
* Sidebar Expanded (≥ 1280px) - Labels sichtbar
* ================================================================ */