From 4df04e1a58cc6c5baa7e92de3f0a31a28c1cf85c Mon Sep 17 00:00:00 2001 From: Matt Ciaccio Date: Wed, 29 Apr 2026 14:12:15 +0200 Subject: [PATCH] feat(mobile): add MobileTopbar with title, back-button, and primary-action slots --- .../layout/mobile/mobile-topbar.tsx | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/components/layout/mobile/mobile-topbar.tsx diff --git a/src/components/layout/mobile/mobile-topbar.tsx b/src/components/layout/mobile/mobile-topbar.tsx new file mode 100644 index 0000000..f6e5a40 --- /dev/null +++ b/src/components/layout/mobile/mobile-topbar.tsx @@ -0,0 +1,56 @@ +'use client'; + +import { ChevronLeft } from 'lucide-react'; +import { useRouter, usePathname } from 'next/navigation'; + +import { cn } from '@/lib/utils'; +import { useMobileChrome } from './mobile-layout-provider'; + +/** + * Fixed compact topbar (52px + safe-area top inset). Renders the page title + * (auto-truncating), an optional back button, and an optional primary action + * — all driven by `useMobileChrome()` from the active page. + */ +export function MobileTopbar() { + const { title, primaryAction, showBackButton } = useMobileChrome(); + const router = useRouter(); + const pathname = usePathname(); + + // Fall back to the last path segment (Title Case) if no page-supplied title. + const fallbackTitle = + pathname + .split('/') + .filter(Boolean) + .pop() + ?.replace(/-/g, ' ') + .replace(/\b\w/g, (c) => c.toUpperCase()) ?? 'Port Nimara'; + + return ( +
+ {showBackButton ? ( + + ) : ( +
+ )} + +

+ {title ?? fallbackTitle} +

+ +
{primaryAction}
+
+ ); +}