Initial commit: Second Brain Platform
Complete platform with unified design system and real API integration. Apps: Dashboard, Fitness, Budget, Inventory, Trips, Reader, Media, Settings Infrastructure: SvelteKit + Python gateway + Docker Compose
This commit is contained in:
165
frontend-v2/src/lib/components/layout/MobileTabBar.svelte
Normal file
165
frontend-v2/src/lib/components/layout/MobileTabBar.svelte
Normal file
@@ -0,0 +1,165 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { LayoutDashboard, DollarSign, Package, Activity, MoreVertical, MapPin, BookOpen, Library, Settings } from '@lucide/svelte';
|
||||
|
||||
let moreOpen = $state(false);
|
||||
|
||||
function isActive(path: string): boolean {
|
||||
if (path === '/') return page.url.pathname === '/';
|
||||
return page.url.pathname.startsWith(path);
|
||||
}
|
||||
|
||||
function closeMore() {
|
||||
moreOpen = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="mobile-tabbar">
|
||||
<div class="mobile-tabbar-inner">
|
||||
<a href="/" class="mobile-tab" class:active={isActive('/')}>
|
||||
<LayoutDashboard size={22} />
|
||||
Dashboard
|
||||
</a>
|
||||
<a href="/budget" class="mobile-tab" class:active={isActive('/budget')}>
|
||||
<DollarSign size={22} />
|
||||
Budget
|
||||
</a>
|
||||
<a href="/inventory" class="mobile-tab" class:active={isActive('/inventory')}>
|
||||
<Package size={22} />
|
||||
Inventory
|
||||
</a>
|
||||
<a href="/fitness" class="mobile-tab" class:active={isActive('/fitness')}>
|
||||
<Activity size={22} />
|
||||
Fitness
|
||||
</a>
|
||||
<button class="mobile-tab" class:active={moreOpen} onclick={() => moreOpen = true}>
|
||||
<MoreVertical size={22} />
|
||||
More
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- More sheet overlay -->
|
||||
{#if moreOpen}
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div class="more-sheet-overlay open" onclick={(e) => { if (e.target === e.currentTarget) closeMore(); }} onkeydown={() => {}}>
|
||||
<div class="more-sheet">
|
||||
<div class="more-sheet-handle"></div>
|
||||
<a href="/trips" class="more-sheet-item" onclick={closeMore}>
|
||||
<MapPin size={20} />
|
||||
Trips
|
||||
</a>
|
||||
<a href="/reader" class="more-sheet-item" onclick={closeMore}>
|
||||
<BookOpen size={20} />
|
||||
Reader
|
||||
</a>
|
||||
<a href="/media" class="more-sheet-item" onclick={closeMore}>
|
||||
<Library size={20} />
|
||||
Media
|
||||
</a>
|
||||
<a href="/settings" class="more-sheet-item" onclick={closeMore}>
|
||||
<Settings size={20} />
|
||||
Settings
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.mobile-tabbar {
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 80;
|
||||
background: var(--nav-bg);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border-top: 1px solid var(--border);
|
||||
padding-bottom: env(safe-area-inset-bottom, 0px);
|
||||
}
|
||||
.mobile-tabbar-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
height: 56px;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.mobile-tab {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--sp-0.5);
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-3);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 500;
|
||||
padding: var(--sp-1) var(--sp-2);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--transition);
|
||||
min-width: 56px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.mobile-tab.active { color: var(--accent); }
|
||||
.mobile-tab:hover { color: var(--text-1); }
|
||||
|
||||
/* More sheet */
|
||||
.more-sheet-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: var(--overlay);
|
||||
z-index: 90;
|
||||
}
|
||||
.more-sheet {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 91;
|
||||
background: var(--surface);
|
||||
border-top-left-radius: 16px;
|
||||
border-top-right-radius: 16px;
|
||||
padding: var(--sp-3) var(--sp-4) var(--sp-8);
|
||||
animation: slideUp 0.3s ease;
|
||||
}
|
||||
@keyframes slideUp {
|
||||
from { transform: translateY(100%); }
|
||||
to { transform: translateY(0); }
|
||||
}
|
||||
.more-sheet-handle {
|
||||
width: 36px;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background: var(--text-4);
|
||||
margin: 0 auto var(--sp-4);
|
||||
}
|
||||
.more-sheet-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-3);
|
||||
padding: 14px var(--sp-3);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: var(--text-md);
|
||||
font-weight: 500;
|
||||
color: var(--text-1);
|
||||
background: none;
|
||||
border: none;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
transition: background var(--transition);
|
||||
text-decoration: none;
|
||||
}
|
||||
.more-sheet-item:hover { background: var(--card-hover); }
|
||||
.more-sheet-item :global(svg) { color: var(--text-3); }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.mobile-tabbar { display: block; }
|
||||
}
|
||||
@media (min-width: 769px) {
|
||||
.mobile-tabbar { display: none !important; }
|
||||
.more-sheet-overlay { display: none !important; }
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user