feat(fase-5.12): detail-view chrome — hide MobileTopBar, sticky contextual headers
On /lists/[id], /tasks/[id], /notes/[id], /lists/[id]/session the global
MobileTopBar (hamburger + collective + avatar) is hidden on mobile. The
route's own contextual header (back + title + actions) becomes the only
top chrome and is now sticky with glassmorphism, matching the look of
the MobileTopBar it replaces. BottomTabBar stays visible so the user can
still hop between sections.
Detection: a regex over the path — /^\/(lists\/[uuid](\/session)?|
tasks\/[uuid]|notes\/[uuid])\/?$/ — in (app)/+layout.svelte.
Headers touched:
- apps/web/src/routes/(app)/lists/[id]/+page.svelte (px-4 on mobile,
px-8 on md+, transparent/no-border on md+ since the masthead
provides its own spacing)
- apps/web/src/routes/(app)/tasks/[id]/+page.svelte
- apps/web/src/routes/(app)/notes/[id]/+page.svelte
Tests
tests/e2e/mobile-shell.test.ts gains M-08: on /lists/bbbb..., the
mobile-hamburger element has count 0 (MobileTopBar removed) while the
detail's back link + BottomTabBar remain visible. All 5 shell tests
green.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import { isAuthenticated, authLoading } from '$lib/stores/auth';
|
||||
import { login } from '$lib/auth';
|
||||
import DesktopSidebar from '$lib/components/layout/DesktopSidebar.svelte';
|
||||
@@ -13,6 +14,14 @@
|
||||
|
||||
let drawerOpen = $state(false);
|
||||
|
||||
// Detail routes render their own contextual header (back + title). On mobile
|
||||
// we hide the global MobileTopBar for those paths so the contextual header
|
||||
// becomes the only top chrome. BottomTabBar stays visible (user can still
|
||||
// jump between sections). Modo Compra covers everything with its own z-50
|
||||
// overlay, so it effectively hides bottom too — handled locally.
|
||||
const detailRoutePattern = /^\/(lists\/[0-9a-f-]+(?:\/session)?|tasks\/[0-9a-f-]+|notes\/[0-9a-f-]+)\/?$/;
|
||||
const isDetailRoute = $derived(detailRoutePattern.test($page.url.pathname));
|
||||
|
||||
// When auth resolves as unauthenticated, redirect to Keycloak.
|
||||
// This runs after onAuthStateChange fires (authLoading = false), so there
|
||||
// is no race with Supabase's async localStorage initialisation.
|
||||
@@ -33,7 +42,9 @@
|
||||
<div class="flex h-screen flex-col overflow-hidden bg-background md:flex-row">
|
||||
<DesktopSidebar />
|
||||
|
||||
<MobileTopBar onMenu={() => (drawerOpen = true)} />
|
||||
{#if !isDetailRoute}
|
||||
<MobileTopBar onMenu={() => (drawerOpen = true)} />
|
||||
{/if}
|
||||
<MobileDrawer bind:open={drawerOpen} />
|
||||
|
||||
<main class="flex flex-1 flex-col overflow-hidden bg-background pb-16 md:pb-0">
|
||||
|
||||
@@ -386,8 +386,10 @@
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-1 flex-col overflow-hidden">
|
||||
<!-- Header -->
|
||||
<header class="flex items-center gap-3 px-8 pb-4 pt-8">
|
||||
<!-- Header — sticky so it stays in view when the list is long.
|
||||
(app)/+layout.svelte hides the global MobileTopBar on detail routes,
|
||||
so this is the ONLY top chrome on mobile. -->
|
||||
<header class="sticky top-0 z-30 flex items-center gap-3 border-b border-black/5 bg-surface/80 px-4 py-3 backdrop-blur-xl md:border-b-0 md:bg-transparent md:backdrop-blur-0 md:px-8 md:pb-4 md:pt-8 dark:border-white/5">
|
||||
<a
|
||||
href="/lists"
|
||||
class="rounded-md p-1.5 text-text-muted hover:bg-black/5 dark:hover:bg-white/5"
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
<svelte:head><title>{title || m.notes_title()} — Colectivo</title></svelte:head>
|
||||
|
||||
<div class={`flex h-full flex-col overflow-hidden ${colorBg(note?.color ?? null)}`}>
|
||||
<header class="flex h-14 flex-shrink-0 items-center gap-2 border-b border-black/5 px-6 dark:border-white/5">
|
||||
<header class="sticky top-0 z-30 flex h-14 flex-shrink-0 items-center gap-2 border-b border-black/5 bg-surface/80 px-4 backdrop-blur-xl md:px-6 dark:border-white/5">
|
||||
<a
|
||||
href="/notes"
|
||||
class="rounded p-1 text-text-secondary hover:bg-black/5 dark:hover:bg-white/5"
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
<svelte:head><title>{list?.name ?? m.tasks_title()} — Colectivo</title></svelte:head>
|
||||
|
||||
<div class="flex h-full flex-col overflow-hidden">
|
||||
<header class="flex h-14 items-center gap-2 border-b border-black/5 px-6 dark:border-white/5">
|
||||
<header class="sticky top-0 z-30 flex h-14 items-center gap-2 border-b border-black/5 bg-surface/80 px-4 backdrop-blur-xl md:px-6 dark:border-white/5">
|
||||
<a href="/tasks" class="rounded p-1 text-text-secondary hover:bg-black/5 dark:hover:bg-white/5" aria-label={m.notes_back_to_board()}>
|
||||
<ArrowLeft size={18} strokeWidth={1.5} />
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user