feat(mobile): center bottom + FAB, floating header with left logo & right avatar, long-press triage sheet, and large swipeable queue
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m1s

This commit is contained in:
sandrodach committed 2026-10-25 14:10:13 +01:00
1 parent 90a6062c7a
commit c02c7d20de
2 files changed
+585 -190

No files matched your search

+86 -73
View File
@@ -330,24 +330,44 @@ export const App: React.FC = () => {
return (
<div className="min-h-screen bg-canvas text-main flex flex-col font-sans selection:bg-accent/30">
{/* Top Header Bar */}
<header className="sticky top-0 z-30 bg-panel border-b border-border shadow-sm">
{/* Mobile Header: Centered Logo & Instance Title */}
<div className="sm:hidden flex items-center justify-center relative h-11 px-4">
<div
{/* Top Header Bar: Floating on mobile, solid panel on desktop */}
<header className="sticky top-0 z-30 bg-canvas/85 backdrop-blur-md sm:bg-panel sm:border-b sm:border-border sm:shadow-sm">
{/* Mobile Header: Floating Bar with Larger Logo Left (Triage Home) & Profile Avatar Right */}
<div className="sm:hidden flex items-center justify-between h-14 px-4 pt-1">
<button
type="button"
onClick={() => {
triggerHaptic(10);
setActiveTab('triage');
}}
className="flex items-center gap-2 cursor-pointer select-none"
className="h-11 px-2 -ml-2 rounded-xl flex items-center gap-2.5 cursor-pointer select-none active:scale-95 transition-transform"
title="Zur Startseite (Triage)"
>
<div className="w-6 h-6 bg-accent text-on-accent rounded-btn flex items-center justify-center">
<Brain className="w-3.5 h-3.5" />
<div className="w-8 h-8 bg-accent text-on-accent rounded-xl shadow-sm flex items-center justify-center">
<Brain className="w-4 h-4" />
</div>
<span className="font-bold text-sm text-main tracking-tight">
<span className="font-bold text-base text-main tracking-tight">
{authStatus.instanceName || 'MindSift'}
</span>
</div>
</button>
<button
type="button"
onClick={() => {
triggerHaptic(10);
setShowMobileProfile(true);
}}
className={`w-11 h-11 -mr-1.5 rounded-full flex items-center justify-center transition-transform active:scale-95 cursor-pointer ${
activeTab === 'user_settings' || activeTab === 'admin_settings' || activeTab === 'help'
? 'ring-2 ring-accent'
: ''
}`}
title="Profil & Einstellungen"
>
<div className="w-8 h-8 rounded-full bg-accent text-on-accent text-xs font-bold shadow-sm flex items-center justify-center">
{user.displayName ? user.displayName.slice(0, 1).toUpperCase() : 'U'}
</div>
</button>
</div>
{/* Desktop Header: 3-column Layout (Logo, InstantCaptureBar, Profile Pill) */}
@@ -648,113 +668,106 @@ export const App: React.FC = () => {
</ViewErrorBoundary>
</main>
{/* MOBILE BOTTOM NAVIGATION BAR */}
<nav className="sm:hidden fixed bottom-0 left-0 right-0 z-40 bg-panel/95 backdrop-blur-md border-t border-border px-3 py-1 flex items-center justify-around pb-[calc(0.4rem+env(safe-area-inset-bottom))] shadow-panel">
{/* Tab 1: Triage */}
{/* MOBILE BOTTOM NAVIGATION BAR (5 equal columns -> + FAB is dead-center) */}
<nav className="sm:hidden fixed bottom-0 left-0 right-0 z-40 bg-panel/95 backdrop-blur-md border-t border-border px-2 pt-1.5 pb-[calc(0.5rem+env(safe-area-inset-bottom))] grid grid-cols-5 items-center shadow-panel">
{/* Col 1: Triage */}
<button
type="button"
onClick={() => {
triggerHaptic(10);
setActiveTab('triage');
}}
className={`p-2 rounded-btn flex flex-col items-center justify-center transition-colors relative cursor-pointer ${
activeTab === 'triage' ? 'text-accent' : 'text-muted hover:text-main'
className={`min-h-[48px] rounded-xl flex flex-col items-center justify-center gap-0.5 transition-colors relative cursor-pointer active:scale-95 ${
activeTab === 'triage' ? 'text-accent font-semibold' : 'text-muted hover:text-main'
}`}
title="Triage"
>
<Layers className="w-5 h-5" />
{stats.inboxCount > 0 && (
<span className="absolute -top-0.5 -right-0.5 min-w-[15px] h-[15px] px-0.5 rounded-full text-[9px] font-bold leading-none bg-accent text-on-accent flex items-center justify-center shadow-xs pointer-events-none">
{stats.inboxCount}
</span>
)}
<div className="relative">
<Layers className="w-5 h-5" />
{stats.inboxCount > 0 && (
<span className="absolute -top-1.5 -right-2.5 min-w-[16px] h-[16px] px-1 rounded-full text-[9px] font-bold leading-none bg-accent text-on-accent flex items-center justify-center shadow-xs pointer-events-none">
{stats.inboxCount}
</span>
)}
</div>
<span className="text-[10px] leading-tight">Triage</span>
</button>
{/* Tab 2: Aufgaben */}
{/* Col 2: Aufgaben */}
<button
type="button"
onClick={() => {
triggerHaptic(10);
setActiveTab('tasks');
}}
className={`p-2 rounded-btn flex flex-col items-center justify-center transition-colors relative cursor-pointer ${
activeTab === 'tasks' ? 'text-accent' : 'text-muted hover:text-main'
className={`min-h-[48px] rounded-xl flex flex-col items-center justify-center gap-0.5 transition-colors relative cursor-pointer active:scale-95 ${
activeTab === 'tasks' ? 'text-accent font-semibold' : 'text-muted hover:text-main'
}`}
title="Aufgaben"
>
<CheckSquare className="w-5 h-5" />
{stats.tasksOpenCount > 0 && (
<span className="absolute -top-0.5 -right-0.5 min-w-[15px] h-[15px] px-0.5 rounded-full text-[9px] font-bold leading-none bg-accent text-on-accent flex items-center justify-center shadow-xs pointer-events-none">
{stats.tasksOpenCount}
</span>
)}
<div className="relative">
<CheckSquare className="w-5 h-5" />
{stats.tasksOpenCount > 0 && (
<span className="absolute -top-1.5 -right-2.5 min-w-[16px] h-[16px] px-1 rounded-full text-[9px] font-bold leading-none bg-accent text-on-accent flex items-center justify-center shadow-xs pointer-events-none">
{stats.tasksOpenCount}
</span>
)}
</div>
<span className="text-[10px] leading-tight">Aufgaben</span>
</button>
{/* CENTER ACTION: + Quick-Add FAB */}
<button
type="button"
onClick={() => {
triggerHaptic(15);
setShowMobileCapture(true);
}}
className="w-12 h-12 -mt-5 rounded-full bg-accent text-on-accent shadow-lg flex items-center justify-center active:scale-90 transition-transform border-4 border-panel cursor-pointer"
title="Schnell erfassen (+)"
>
<Plus className="w-6 h-6 stroke-[2.5]" />
</button>
{/* Col 3 (EXACT CENTER): + Quick-Add FAB */}
<div className="flex items-center justify-center">
<button
type="button"
onClick={() => {
triggerHaptic(15);
setShowMobileCapture(true);
}}
className="w-14 h-14 -mt-6 rounded-full bg-accent text-on-accent shadow-lg flex items-center justify-center active:scale-90 transition-transform border-4 border-panel cursor-pointer"
title="Schnell erfassen (+)"
>
<Plus className="w-7 h-7 stroke-[2.5]" />
</button>
</div>
{/* Tab 3: Workspace */}
{/* Col 4: Workspace */}
<button
type="button"
onClick={() => {
triggerHaptic(10);
setActiveTab('workspace');
}}
className={`p-2 rounded-btn flex flex-col items-center justify-center transition-colors relative cursor-pointer ${
activeTab === 'workspace' ? 'text-accent' : 'text-muted hover:text-main'
className={`min-h-[48px] rounded-xl flex flex-col items-center justify-center gap-0.5 transition-colors relative cursor-pointer active:scale-95 ${
activeTab === 'workspace' ? 'text-accent font-semibold' : 'text-muted hover:text-main'
}`}
title="Workspace"
>
<FileText className="w-5 h-5" />
{(stats.docsTodosOpenCount ?? 0) > 0 && (
<span className="absolute -top-0.5 -right-0.5 min-w-[15px] h-[15px] px-0.5 rounded-full text-[9px] font-bold leading-none bg-accent text-on-accent flex items-center justify-center shadow-xs pointer-events-none">
{stats.docsTodosOpenCount}
</span>
)}
<div className="relative">
<FileText className="w-5 h-5" />
{(stats.docsTodosOpenCount ?? 0) > 0 && (
<span className="absolute -top-1.5 -right-2.5 min-w-[16px] h-[16px] px-1 rounded-full text-[9px] font-bold leading-none bg-accent text-on-accent flex items-center justify-center shadow-xs pointer-events-none">
{stats.docsTodosOpenCount}
</span>
)}
</div>
<span className="text-[10px] leading-tight">Workspace</span>
</button>
{/* Tab 4: Listen */}
{/* Col 5: Listen */}
<button
type="button"
onClick={() => {
triggerHaptic(10);
setActiveTab('lists');
}}
className={`p-2 rounded-btn flex flex-col items-center justify-center transition-colors relative cursor-pointer ${
activeTab === 'lists' ? 'text-accent' : 'text-muted hover:text-main'
className={`min-h-[48px] rounded-xl flex flex-col items-center justify-center gap-0.5 transition-colors relative cursor-pointer active:scale-95 ${
activeTab === 'lists' ? 'text-accent font-semibold' : 'text-muted hover:text-main'
}`}
title="Listen"
>
<ShoppingCart className="w-5 h-5" />
</button>
{/* User Profile Avatar */}
<button
type="button"
onClick={() => {
triggerHaptic(10);
setShowMobileProfile(true);
}}
className={`p-1.5 rounded-btn flex items-center justify-center transition-colors cursor-pointer ${
activeTab === 'user_settings' || activeTab === 'admin_settings' || activeTab === 'help'
? 'ring-2 ring-accent'
: 'opacity-85 hover:opacity-100'
}`}
title="Profil & Einstellungen"
>
<div className="w-6 h-6 rounded-full bg-accent text-on-accent text-[11px] font-bold flex items-center justify-center">
{user.displayName ? user.displayName.slice(0, 1).toUpperCase() : 'U'}
</div>
<span className="text-[10px] leading-tight">Listen</span>
</button>
</nav>