mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
♻️ refactor(todo,contacts): remove sidebar mode from PillNavigation
Simplify navigation by removing unused sidebar mode from both apps: Todo App: - Remove isSidebarMode state, handlers, and localStorage persistence - Remove sidebar-related CSS classes and styles - Simplify TodoToolbar to pure wrapper component Contacts App: - Remove isSidebarMode state, handlers, and localStorage persistence - Remove sidebar-related CSS from ContactsToolbar and ContactAlphabetView - Always show view-mode-pill (no longer conditional on sidebar mode) This removes ~250 lines of unused code across 5 files.
This commit is contained in:
parent
12a900346c
commit
bf0e788cba
5 changed files with 66 additions and 322 deletions
|
|
@ -7,11 +7,10 @@
|
||||||
import type { Contact } from '$lib/api/contacts';
|
import type { Contact } from '$lib/api/contacts';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isSidebarMode?: boolean;
|
|
||||||
contacts: Contact[];
|
contacts: Contact[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let { isSidebarMode = false, contacts }: Props = $props();
|
let { contacts }: Props = $props();
|
||||||
|
|
||||||
// Use store for collapsed state
|
// Use store for collapsed state
|
||||||
let isCollapsed = $derived(contactsFilterStore.isToolbarCollapsed);
|
let isCollapsed = $derived(contactsFilterStore.isToolbarCollapsed);
|
||||||
|
|
@ -25,7 +24,6 @@
|
||||||
<ExpandableToolbar
|
<ExpandableToolbar
|
||||||
{isCollapsed}
|
{isCollapsed}
|
||||||
onCollapsedChange={handleCollapsedChange}
|
onCollapsedChange={handleCollapsedChange}
|
||||||
{isSidebarMode}
|
|
||||||
collapsedTitle="Filter & Optionen"
|
collapsedTitle="Filter & Optionen"
|
||||||
expandedTitle="Schließen"
|
expandedTitle="Schließen"
|
||||||
>
|
>
|
||||||
|
|
@ -33,58 +31,56 @@
|
||||||
</ExpandableToolbar>
|
</ExpandableToolbar>
|
||||||
|
|
||||||
<!-- View Mode Pill - positioned to the LEFT of the FAB -->
|
<!-- View Mode Pill - positioned to the LEFT of the FAB -->
|
||||||
{#if !isSidebarMode}
|
<div class="view-mode-pill" class:toolbar-expanded={!isCollapsed}>
|
||||||
<div class="view-mode-pill" class:expanded={!isCollapsed}>
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
class="view-btn"
|
||||||
class="view-btn"
|
class:active={viewModeStore.mode === 'grid'}
|
||||||
class:active={viewModeStore.mode === 'grid'}
|
onclick={() => viewModeStore.setMode('grid')}
|
||||||
onclick={() => viewModeStore.setMode('grid')}
|
title={$_('views.grid')}
|
||||||
title={$_('views.grid')}
|
>
|
||||||
>
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<path
|
||||||
<path
|
stroke-linecap="round"
|
||||||
stroke-linecap="round"
|
stroke-linejoin="round"
|
||||||
stroke-linejoin="round"
|
stroke-width="2"
|
||||||
stroke-width="2"
|
d="M4 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM14 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1V5zM4 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1v-4zM14 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z"
|
||||||
d="M4 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM14 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1V5zM4 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1v-4zM14 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z"
|
/>
|
||||||
/>
|
</svg>
|
||||||
</svg>
|
</button>
|
||||||
</button>
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
class="view-btn"
|
||||||
class="view-btn"
|
class:active={viewModeStore.mode === 'alphabet'}
|
||||||
class:active={viewModeStore.mode === 'alphabet'}
|
onclick={() => viewModeStore.setMode('alphabet')}
|
||||||
onclick={() => viewModeStore.setMode('alphabet')}
|
title={$_('views.alphabet')}
|
||||||
title={$_('views.alphabet')}
|
>
|
||||||
>
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<path
|
||||||
<path
|
stroke-linecap="round"
|
||||||
stroke-linecap="round"
|
stroke-linejoin="round"
|
||||||
stroke-linejoin="round"
|
stroke-width="2"
|
||||||
stroke-width="2"
|
d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12"
|
||||||
d="M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12"
|
/>
|
||||||
/>
|
</svg>
|
||||||
</svg>
|
</button>
|
||||||
</button>
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
class="view-btn"
|
||||||
class="view-btn"
|
class:active={viewModeStore.mode === 'network'}
|
||||||
class:active={viewModeStore.mode === 'network'}
|
onclick={() => viewModeStore.setMode('network')}
|
||||||
onclick={() => viewModeStore.setMode('network')}
|
title={$_('views.network')}
|
||||||
title={$_('views.network')}
|
>
|
||||||
>
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<path
|
||||||
<path
|
stroke-linecap="round"
|
||||||
stroke-linecap="round"
|
stroke-linejoin="round"
|
||||||
stroke-linejoin="round"
|
stroke-width="2"
|
||||||
stroke-width="2"
|
d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
|
||||||
d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
|
/>
|
||||||
/>
|
</svg>
|
||||||
</svg>
|
</button>
|
||||||
</button>
|
</div>
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* View Mode Pill - positioned to the LEFT of the FAB (which is at right: calc(50% - 350px - 70px)) */
|
/* View Mode Pill - positioned to the LEFT of the FAB (which is at right: calc(50% - 350px - 70px)) */
|
||||||
|
|
@ -109,7 +105,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When toolbar is expanded, move pill up with FAB */
|
/* When toolbar is expanded, move pill up with FAB */
|
||||||
.view-mode-pill.expanded {
|
.view-mode-pill.toolbar-expanded {
|
||||||
bottom: calc(70px + 70px + 9px + env(safe-area-inset-bottom, 0px));
|
bottom: calc(70px + 70px + 9px + env(safe-area-inset-bottom, 0px));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
import type { Contact } from '$lib/api/contacts';
|
import type { Contact } from '$lib/api/contacts';
|
||||||
import type { SortField } from '$lib/components/SortToggle.svelte';
|
import type { SortField } from '$lib/components/SortToggle.svelte';
|
||||||
import { newContactModalStore } from '$lib/stores/new-contact-modal.svelte';
|
import { newContactModalStore } from '$lib/stores/new-contact-modal.svelte';
|
||||||
import { isSidebarMode } from '$lib/stores/navigation';
|
|
||||||
import { contactsFilterStore } from '$lib/stores/filter.svelte';
|
import { contactsFilterStore } from '$lib/stores/filter.svelte';
|
||||||
import { contactsSettings } from '$lib/stores/settings.svelte';
|
import { contactsSettings } from '$lib/stores/settings.svelte';
|
||||||
import AlphabetNavContextMenu from '$lib/components/AlphabetNavContextMenu.svelte';
|
import AlphabetNavContextMenu from '$lib/components/AlphabetNavContextMenu.svelte';
|
||||||
|
|
@ -279,11 +278,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Alphabet FAB (when collapsed) - positioned left of InputBar -->
|
<!-- Alphabet FAB (when collapsed) - positioned left of InputBar -->
|
||||||
<div
|
<div class="alphabet-fab-container" class:toolbar-expanded={isToolbarExpanded}>
|
||||||
class="alphabet-fab-container"
|
|
||||||
class:sidebar-mode={$isSidebarMode}
|
|
||||||
class:toolbar-expanded={isToolbarExpanded}
|
|
||||||
>
|
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<button
|
<button
|
||||||
onclick={toggleAlphabetNav}
|
onclick={toggleAlphabetNav}
|
||||||
|
|
@ -315,11 +310,7 @@
|
||||||
|
|
||||||
<!-- Alphabet Quick Jump (like DateStrip) - hidden when collapsed -->
|
<!-- Alphabet Quick Jump (like DateStrip) - hidden when collapsed -->
|
||||||
{#if !isAlphabetNavCollapsed}
|
{#if !isAlphabetNavCollapsed}
|
||||||
<div
|
<div class="alphabet-nav" class:toolbar-expanded={isToolbarExpanded}>
|
||||||
class="alphabet-nav"
|
|
||||||
class:sidebar-mode={$isSidebarMode}
|
|
||||||
class:toolbar-expanded={isToolbarExpanded}
|
|
||||||
>
|
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<div
|
<div
|
||||||
class="alphabet-nav-container"
|
class="alphabet-nav-container"
|
||||||
|
|
@ -583,16 +574,6 @@
|
||||||
bottom: calc(210px + env(safe-area-inset-bottom, 0px));
|
bottom: calc(210px + env(safe-area-inset-bottom, 0px));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* When PillNav is in sidebar mode, only InputBar at bottom */
|
|
||||||
.alphabet-nav.sidebar-mode {
|
|
||||||
bottom: calc(70px + env(safe-area-inset-bottom, 0px));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sidebar mode + toolbar expanded */
|
|
||||||
.alphabet-nav.sidebar-mode.toolbar-expanded {
|
|
||||||
bottom: calc(140px + env(safe-area-inset-bottom, 0px));
|
|
||||||
}
|
|
||||||
|
|
||||||
.alphabet-nav-container {
|
.alphabet-nav-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
@ -726,11 +707,6 @@
|
||||||
left 0.2s ease;
|
left 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sidebar mode - InputBar is 700px wide, position accordingly */
|
|
||||||
.alphabet-fab-container.sidebar-mode {
|
|
||||||
left: calc(50% - 350px - 8px - 54px); /* Left of 700px InputBar */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive positioning for FAB */
|
/* Responsive positioning for FAB */
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
.alphabet-fab-container {
|
.alphabet-fab-container {
|
||||||
|
|
@ -743,15 +719,6 @@
|
||||||
bottom: calc(140px + 9px + env(safe-area-inset-bottom, 0px));
|
bottom: calc(140px + 9px + env(safe-area-inset-bottom, 0px));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sidebar mode */
|
|
||||||
.alphabet-fab-container.sidebar-mode {
|
|
||||||
bottom: calc(9px + env(safe-area-inset-bottom, 0px));
|
|
||||||
}
|
|
||||||
|
|
||||||
.alphabet-fab-container.sidebar-mode.toolbar-expanded {
|
|
||||||
bottom: calc(70px + 9px + env(safe-area-inset-bottom, 0px));
|
|
||||||
}
|
|
||||||
|
|
||||||
.alphabet-fab {
|
.alphabet-fab {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,6 @@
|
||||||
} from '@manacore/shared-theme';
|
} from '@manacore/shared-theme';
|
||||||
import type { ThemeVariant } from '@manacore/shared-theme';
|
import type { ThemeVariant } from '@manacore/shared-theme';
|
||||||
import { filterHiddenNavItems } from '@manacore/shared-theme';
|
import { filterHiddenNavItems } from '@manacore/shared-theme';
|
||||||
import {
|
|
||||||
isSidebarMode as sidebarModeStore,
|
|
||||||
isNavCollapsed as collapsedStore,
|
|
||||||
} from '$lib/stores/navigation';
|
|
||||||
import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n';
|
import { getLanguageDropdownItems, getCurrentLanguageLabel } from '@manacore/shared-i18n';
|
||||||
import { getPillAppItems } from '@manacore/shared-branding';
|
import { getPillAppItems } from '@manacore/shared-branding';
|
||||||
import { setLocale, supportedLocales } from '$lib/i18n';
|
import { setLocale, supportedLocales } from '$lib/i18n';
|
||||||
|
|
@ -68,11 +64,8 @@
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
let isSidebarMode = $state(false);
|
|
||||||
let isCollapsed = $state(false);
|
|
||||||
|
|
||||||
// Show toolbar only on main contacts page
|
// Show toolbar only on main contacts page
|
||||||
const showContactsToolbar = $derived($page.url.pathname === '/' && !isSidebarMode);
|
const showContactsToolbar = $derived($page.url.pathname === '/');
|
||||||
|
|
||||||
// Check if toolbar is expanded
|
// Check if toolbar is expanded
|
||||||
const isToolbarExpanded = $derived(
|
const isToolbarExpanded = $derived(
|
||||||
|
|
@ -80,9 +73,7 @@
|
||||||
);
|
);
|
||||||
|
|
||||||
// Dynamic bottom offset based on toolbar state
|
// Dynamic bottom offset based on toolbar state
|
||||||
const inputBarBottomOffset = $derived(
|
const inputBarBottomOffset = $derived(isToolbarExpanded ? '140px' : '70px');
|
||||||
isSidebarMode ? '0px' : isToolbarExpanded ? '140px' : '70px'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Use theme store's isDark directly
|
// Use theme store's isDark directly
|
||||||
let isDark = $derived(theme.isDark);
|
let isDark = $derived(theme.isDark);
|
||||||
|
|
@ -181,22 +172,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleModeChange(isSidebar: boolean) {
|
|
||||||
isSidebarMode = isSidebar;
|
|
||||||
sidebarModeStore.set(isSidebar);
|
|
||||||
if (typeof localStorage !== 'undefined') {
|
|
||||||
localStorage.setItem('contacts-nav-sidebar', String(isSidebar));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCollapsedChange(collapsed: boolean) {
|
|
||||||
isCollapsed = collapsed;
|
|
||||||
collapsedStore.set(collapsed);
|
|
||||||
if (typeof localStorage !== 'undefined') {
|
|
||||||
localStorage.setItem('contacts-nav-collapsed', String(collapsed));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleToggleTheme() {
|
function handleToggleTheme() {
|
||||||
theme.toggleMode();
|
theme.toggleMode();
|
||||||
}
|
}
|
||||||
|
|
@ -295,28 +270,6 @@
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to load tags:', e);
|
console.error('Failed to load tags:', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize sidebar mode from localStorage
|
|
||||||
try {
|
|
||||||
const savedSidebar = localStorage?.getItem('contacts-nav-sidebar');
|
|
||||||
if (savedSidebar === 'true') {
|
|
||||||
isSidebarMode = true;
|
|
||||||
sidebarModeStore.set(true);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// localStorage not available (private browsing, quota exceeded, etc.)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize collapsed state from localStorage
|
|
||||||
try {
|
|
||||||
const savedCollapsed = localStorage?.getItem('contacts-nav-collapsed');
|
|
||||||
if (savedCollapsed === 'true') {
|
|
||||||
isCollapsed = true;
|
|
||||||
collapsedStore.set(true);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// localStorage not available
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -327,7 +280,7 @@
|
||||||
<div class="layout-container">
|
<div class="layout-container">
|
||||||
<!-- UI Elements (hidden in immersive mode) -->
|
<!-- UI Elements (hidden in immersive mode) -->
|
||||||
{#if !contactsSettings.immersiveModeEnabled}
|
{#if !contactsSettings.immersiveModeEnabled}
|
||||||
<!-- Floating/Sidebar Pill Navigation (at bottom) -->
|
<!-- Floating Pill Navigation (at bottom) -->
|
||||||
<PillNavigation
|
<PillNavigation
|
||||||
items={navItems}
|
items={navItems}
|
||||||
currentPath={$page.url.pathname}
|
currentPath={$page.url.pathname}
|
||||||
|
|
@ -335,10 +288,6 @@
|
||||||
homeRoute="/"
|
homeRoute="/"
|
||||||
onToggleTheme={handleToggleTheme}
|
onToggleTheme={handleToggleTheme}
|
||||||
{isDark}
|
{isDark}
|
||||||
{isSidebarMode}
|
|
||||||
onModeChange={handleModeChange}
|
|
||||||
{isCollapsed}
|
|
||||||
onCollapsedChange={handleCollapsedChange}
|
|
||||||
desktopPosition="bottom"
|
desktopPosition="bottom"
|
||||||
showThemeToggle={true}
|
showThemeToggle={true}
|
||||||
showThemeVariants={true}
|
showThemeVariants={true}
|
||||||
|
|
@ -381,7 +330,7 @@
|
||||||
|
|
||||||
<!-- Contacts Toolbar (FAB + expandable bar) - only on main page -->
|
<!-- Contacts Toolbar (FAB + expandable bar) - only on main page -->
|
||||||
{#if showContactsToolbar}
|
{#if showContactsToolbar}
|
||||||
<ContactsToolbar {isSidebarMode} contacts={contactsStore.contacts} />
|
<ContactsToolbar contacts={contactsStore.contacts} />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
@ -391,11 +340,9 @@
|
||||||
onToggle={() => contactsSettings.toggleImmersiveMode()}
|
onToggle={() => contactsSettings.toggleImmersiveMode()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Main Content with dynamic padding based on nav mode -->
|
<!-- Main Content -->
|
||||||
<main
|
<main
|
||||||
class="main-content bg-background"
|
class="main-content bg-background"
|
||||||
class:sidebar-mode={isSidebarMode && !isCollapsed}
|
|
||||||
class:floating-mode={!isSidebarMode}
|
|
||||||
class:immersive={contactsSettings.immersiveModeEnabled}
|
class:immersive={contactsSettings.immersiveModeEnabled}
|
||||||
>
|
>
|
||||||
<div class="content-wrapper" class:immersive={contactsSettings.immersiveModeEnabled}>
|
<div class="content-wrapper" class:immersive={contactsSettings.immersiveModeEnabled}>
|
||||||
|
|
@ -429,11 +376,6 @@
|
||||||
padding-bottom: calc(150px + env(safe-area-inset-bottom));
|
padding-bottom: calc(150px + env(safe-area-inset-bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Floating nav mode - nav is at bottom, no top padding needed */
|
|
||||||
.main-content.floating-mode {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extra bottom padding on mobile */
|
/* Extra bottom padding on mobile */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.main-content {
|
.main-content {
|
||||||
|
|
@ -441,11 +383,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sidebar mode - add left padding for sidebar nav */
|
|
||||||
.main-content.sidebar-mode {
|
|
||||||
padding-left: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Immersive mode - fullscreen, no padding */
|
/* Immersive mode - fullscreen, no padding */
|
||||||
.main-content.immersive {
|
.main-content.immersive {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
|
|
||||||
|
|
@ -3,30 +3,17 @@
|
||||||
import TodoToolbarContent from './TodoToolbarContent.svelte';
|
import TodoToolbarContent from './TodoToolbarContent.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isSidebarMode?: boolean;
|
|
||||||
isCollapsed?: boolean;
|
isCollapsed?: boolean;
|
||||||
bottomOffset?: string;
|
bottomOffset?: string;
|
||||||
onModeChange?: (isSidebar: boolean) => void;
|
|
||||||
onCollapsedChange?: (isCollapsed: boolean) => void;
|
onCollapsedChange?: (isCollapsed: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let { isCollapsed = true, bottomOffset = '70px', onCollapsedChange }: Props = $props();
|
||||||
isSidebarMode = false,
|
|
||||||
isCollapsed = true,
|
|
||||||
bottomOffset = '70px',
|
|
||||||
onModeChange,
|
|
||||||
onCollapsedChange,
|
|
||||||
}: Props = $props();
|
|
||||||
|
|
||||||
function toggleSidebarMode() {
|
|
||||||
onModeChange?.(!isSidebarMode);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ExpandableToolbar
|
<ExpandableToolbar
|
||||||
{isCollapsed}
|
{isCollapsed}
|
||||||
{onCollapsedChange}
|
{onCollapsedChange}
|
||||||
{isSidebarMode}
|
|
||||||
{bottomOffset}
|
{bottomOffset}
|
||||||
collapsedTitle="Aufgaben-Optionen"
|
collapsedTitle="Aufgaben-Optionen"
|
||||||
expandedTitle="Schließen"
|
expandedTitle="Schließen"
|
||||||
|
|
@ -42,62 +29,4 @@
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
<TodoToolbarContent />
|
<TodoToolbarContent />
|
||||||
|
|
||||||
{#snippet rightActions()}
|
|
||||||
<button
|
|
||||||
onclick={toggleSidebarMode}
|
|
||||||
class="layout-btn"
|
|
||||||
title={isSidebarMode ? 'Zur Bottom-Navigation' : 'Zur Sidebar-Navigation'}
|
|
||||||
>
|
|
||||||
<svg class="layout-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
{#if isSidebarMode}
|
|
||||||
<!-- Bottom bar layout icon -->
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M3 3h18v9H3V3zm0 12h18v6H3v-6z"
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<!-- Sidebar layout icon -->
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="2"
|
|
||||||
d="M3 3h7v18H3V3zm9 0h9v18h-9V3z"
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
{/snippet}
|
|
||||||
</ExpandableToolbar>
|
</ExpandableToolbar>
|
||||||
|
|
||||||
<style>
|
|
||||||
/* Layout toggle button - app-specific style */
|
|
||||||
.layout-btn {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 0.5rem;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
color: hsl(var(--color-muted-foreground));
|
|
||||||
border-radius: 9999px;
|
|
||||||
transition: all 0.15s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-btn:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.05);
|
|
||||||
color: hsl(var(--color-foreground));
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.dark) .layout-btn:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.layout-icon {
|
|
||||||
width: 1rem;
|
|
||||||
height: 1rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,7 @@
|
||||||
import { labelsStore } from '$lib/stores/labels.svelte';
|
import { labelsStore } from '$lib/stores/labels.svelte';
|
||||||
import { tasksStore } from '$lib/stores/tasks.svelte';
|
import { tasksStore } from '$lib/stores/tasks.svelte';
|
||||||
import { theme } from '$lib/stores/theme';
|
import { theme } from '$lib/stores/theme';
|
||||||
import {
|
import { isToolbarCollapsed as toolbarCollapsedStore } from '$lib/stores/navigation';
|
||||||
isSidebarMode as sidebarModeStore,
|
|
||||||
isNavCollapsed as collapsedStore,
|
|
||||||
isToolbarCollapsed as toolbarCollapsedStore,
|
|
||||||
} from '$lib/stores/navigation';
|
|
||||||
import TodoToolbar from '$lib/components/TodoToolbar.svelte';
|
import TodoToolbar from '$lib/components/TodoToolbar.svelte';
|
||||||
import {
|
import {
|
||||||
THEME_DEFINITIONS,
|
THEME_DEFINITIONS,
|
||||||
|
|
@ -106,8 +102,6 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let isSidebarMode = $state(false);
|
|
||||||
let isCollapsed = $state(false);
|
|
||||||
let isToolbarCollapsed = $state(true);
|
let isToolbarCollapsed = $state(true);
|
||||||
|
|
||||||
// Use theme store's isDark directly
|
// Use theme store's isDark directly
|
||||||
|
|
@ -166,28 +160,10 @@
|
||||||
{ href: '/feedback', label: 'Feedback', icon: 'chat' },
|
{ href: '/feedback', label: 'Feedback', icon: 'chat' },
|
||||||
];
|
];
|
||||||
|
|
||||||
// Navigation items (base items + dynamic label items in sidebar mode, filtered by visibility settings)
|
// Navigation items filtered by visibility settings (with fallback for guest mode)
|
||||||
const navItems = $derived.by(() => {
|
const navItems = $derived(
|
||||||
// Start with base items, filter out hidden ones (with fallback for guest mode)
|
filterHiddenNavItems('todo', baseNavItems, userSettings.nav?.hiddenNavItems || {})
|
||||||
let items = filterHiddenNavItems('todo', baseNavItems, userSettings.nav?.hiddenNavItems || {});
|
);
|
||||||
|
|
||||||
// In sidebar mode, add tags as sub-items if available
|
|
||||||
if (isSidebarMode && labelsStore.labels.length > 0) {
|
|
||||||
const tagItems: PillNavItem[] = labelsStore.labels.slice(0, 5).map((label) => ({
|
|
||||||
href: `/tag/${label.id}`,
|
|
||||||
label: label.name,
|
|
||||||
icon: 'tag',
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Insert tag items after "Tags" nav item
|
|
||||||
const tagsIndex = items.findIndex((i) => i.href === '/tags');
|
|
||||||
if (tagsIndex !== -1 && tagItems.length > 0) {
|
|
||||||
items = [...items];
|
|
||||||
items.splice(tagsIndex + 1, 0, ...tagItems);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Navigation shortcuts (Ctrl+1-6) - use base items for consistent shortcuts
|
// Navigation shortcuts (Ctrl+1-6) - use base items for consistent shortcuts
|
||||||
const navRoutes = baseNavItems.map((item) => item.href);
|
const navRoutes = baseNavItems.map((item) => item.href);
|
||||||
|
|
@ -223,26 +199,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleModeChange(isSidebar: boolean) {
|
|
||||||
isSidebarMode = isSidebar;
|
|
||||||
sidebarModeStore.set(isSidebar);
|
|
||||||
try {
|
|
||||||
localStorage?.setItem('todo-nav-sidebar', String(isSidebar));
|
|
||||||
} catch {
|
|
||||||
// localStorage not available or quota exceeded
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCollapsedChange(collapsed: boolean) {
|
|
||||||
isCollapsed = collapsed;
|
|
||||||
collapsedStore.set(collapsed);
|
|
||||||
try {
|
|
||||||
localStorage?.setItem('todo-nav-collapsed', String(collapsed));
|
|
||||||
} catch {
|
|
||||||
// localStorage not available or quota exceeded
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleToolbarCollapsedChange(collapsed: boolean) {
|
function handleToolbarCollapsedChange(collapsed: boolean) {
|
||||||
isToolbarCollapsed = collapsed;
|
isToolbarCollapsed = collapsed;
|
||||||
toolbarCollapsedStore?.set(collapsed);
|
toolbarCollapsedStore?.set(collapsed);
|
||||||
|
|
@ -292,28 +248,6 @@
|
||||||
goto(userSettings.startPage, { replaceState: true });
|
goto(userSettings.startPage, { replaceState: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize sidebar mode from localStorage (with error handling for private browsing)
|
|
||||||
try {
|
|
||||||
const savedSidebar = localStorage?.getItem('todo-nav-sidebar');
|
|
||||||
if (savedSidebar === 'true') {
|
|
||||||
isSidebarMode = true;
|
|
||||||
sidebarModeStore.set(true);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// localStorage not available (private browsing, quota exceeded, etc.)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize collapsed state from localStorage
|
|
||||||
try {
|
|
||||||
const savedCollapsed = localStorage?.getItem('todo-nav-collapsed');
|
|
||||||
if (savedCollapsed === 'true') {
|
|
||||||
isCollapsed = true;
|
|
||||||
collapsedStore.set(true);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// localStorage not available
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize toolbar collapsed state from localStorage
|
// Initialize toolbar collapsed state from localStorage
|
||||||
try {
|
try {
|
||||||
const savedToolbarCollapsed = localStorage?.getItem('todo-toolbar-collapsed');
|
const savedToolbarCollapsed = localStorage?.getItem('todo-toolbar-collapsed');
|
||||||
|
|
@ -365,10 +299,6 @@
|
||||||
homeRoute="/"
|
homeRoute="/"
|
||||||
onToggleTheme={handleToggleTheme}
|
onToggleTheme={handleToggleTheme}
|
||||||
{isDark}
|
{isDark}
|
||||||
{isSidebarMode}
|
|
||||||
onModeChange={handleModeChange}
|
|
||||||
{isCollapsed}
|
|
||||||
onCollapsedChange={handleCollapsedChange}
|
|
||||||
desktopPosition={userSettings.nav?.desktopPosition || 'bottom'}
|
desktopPosition={userSettings.nav?.desktopPosition || 'bottom'}
|
||||||
showThemeToggle={true}
|
showThemeToggle={true}
|
||||||
showThemeVariants={true}
|
showThemeVariants={true}
|
||||||
|
|
@ -410,10 +340,8 @@
|
||||||
|
|
||||||
<!-- Todo Toolbar (ExpandableToolbar FAB) -->
|
<!-- Todo Toolbar (ExpandableToolbar FAB) -->
|
||||||
<TodoToolbar
|
<TodoToolbar
|
||||||
{isSidebarMode}
|
|
||||||
isCollapsed={isToolbarCollapsed}
|
isCollapsed={isToolbarCollapsed}
|
||||||
onCollapsedChange={handleToolbarCollapsedChange}
|
onCollapsedChange={handleToolbarCollapsedChange}
|
||||||
onModeChange={handleModeChange}
|
|
||||||
bottomOffset="70px"
|
bottomOffset="70px"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
@ -424,12 +352,7 @@
|
||||||
onToggle={() => todoSettings.toggleImmersiveMode()}
|
onToggle={() => todoSettings.toggleImmersiveMode()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<main
|
<main class="main-content bg-background" class:immersive={todoSettings.immersiveModeEnabled}>
|
||||||
class="main-content bg-background"
|
|
||||||
class:sidebar-mode={isSidebarMode && !isCollapsed}
|
|
||||||
class:floating-mode={!isSidebarMode && !isCollapsed}
|
|
||||||
class:immersive={todoSettings.immersiveModeEnabled}
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="content-wrapper"
|
class="content-wrapper"
|
||||||
class:full-width={$page.url.pathname === '/kanban'}
|
class:full-width={$page.url.pathname === '/kanban'}
|
||||||
|
|
@ -455,14 +378,6 @@
|
||||||
padding-bottom: calc(80px + env(safe-area-inset-bottom));
|
padding-bottom: calc(80px + env(safe-area-inset-bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-content.floating-mode {
|
|
||||||
padding-top: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-content.sidebar-mode {
|
|
||||||
padding-left: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Immersive mode - fullscreen, no padding */
|
/* Immersive mode - fullscreen, no padding */
|
||||||
.main-content.immersive {
|
.main-content.immersive {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue