refactor(layout): single-tree responsive shell (#26)
Pre-fix the dashboard layout mounted BOTH the desktop and mobile shells
to the DOM on every page, hidden via CSS data-shell rules. Two Tabs
providers had data-state="active" concurrently, every fetch fired twice,
every component piece of state lived in two trees, a11y landmarks
duplicated, and half the click attempts hit the wrong layer.
New <AppShell> client wrapper mounts exactly ONE tree based on the
server-classified User-Agent (no hydration mismatch, no first-paint
flash on real mobile devices) plus a runtime matchMedia subscription
that swaps shells when the viewport crosses 1024px (e.g. desktop
browser resized).
Knock-on changes:
- Dashboard layout fetches once and hands the data to AppShell;
AppShell picks Desktop (Sidebar + Topbar + main) or MobileLayout
- Stripped the now-orphan data-shell CSS rules from globals.css —
nothing emits the attribute any more
- MobileLayout drops its data-shell="mobile" attribute (was the lever
the dead CSS rules pulled)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,17 +11,17 @@ import { MobileSearchOverlay } from '@/components/search/mobile-search-overlay';
|
||||
|
||||
/**
|
||||
* Mobile shell: fixed compact topbar + scrollable content + fixed bottom tab
|
||||
* bar. Renders only when CSS reveals it (data-shell="mobile") - both shells
|
||||
* are in the DOM, see src/app/globals.css. The bottom tabs and More sheet
|
||||
* derive the active port slug from the URL themselves, so this layout takes
|
||||
* no portSlug prop.
|
||||
* bar. Mounted by AppShell when the viewport classifies as mobile — never
|
||||
* concurrent with the desktop tree. The bottom tabs and More sheet derive
|
||||
* the active port slug from the URL themselves, so this layout takes no
|
||||
* portSlug prop.
|
||||
*/
|
||||
export function MobileLayout({ children }: { children: ReactNode }) {
|
||||
const [moreOpen, setMoreOpen] = useState(false);
|
||||
const [searchOpen, setSearchOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div data-shell="mobile" className="min-h-[100dvh] bg-background">
|
||||
<div className="min-h-[100dvh] bg-background">
|
||||
<MobileLayoutProvider>
|
||||
<MobileTopbar />
|
||||
<main
|
||||
|
||||
Reference in New Issue
Block a user