feat(mobile): Sidebar drawer <1024px + Modal/Sheet fullscreen <880px
Per design_handoff_ordinis_mdm/README.md responsive table (line 464-465):
- ≤1024px: Sidebar becomes overlay drawer (hamburger в TopBar)
- ≤880px: Drawers и modals fullscreen (100vw × 100dvh, no border-radius)
Implementation:
src/components/layout/Sidebar.tsx
- Extracted SidebarContent (logo + nav + user block) для DRY
- Desktop <Sidebar /> wraps SidebarContent в hidden lg:flex aside
- New <MobileSidebar open onClose /> — Sheet с тем же содержимым,
260px wide, slides from left
- SidebarLink принимает onClick → drawer auto-close при navigate
src/components/layout/TopBar.tsx
- Optional onMenuClick prop — рендерит hamburger button (Menu icon
из lucide-react) с lg:hidden
- VersionBadge скрыт <md (768px) — diagnostic info, не critical UX
src/routes/__root.tsx
- useState mobileNavOpen, передаём в MobileSidebar + TopBar
src/ui/components/dialog.tsx
- SIZE_CLASSES получили prefix (arbitrary Tailwind v4
breakpoint per handoff exact 880px). На mobile <880px modal становится
fullscreen (inset-0 w-full h-full no rounded), ≥880px — centered с
translate + max-w из SIZE_CLASSES.
src/ui/components/sheet.tsx
- size variants: sm:max-w-* → min-[880px]:max-w-*. На mobile <880px
sheet берёт w-full (fullscreen drawer per handoff).
src/components/record/RecordDrawer.tsx
- max-width переключатель 520/880 теперь применяется только ≥880px.
На mobile drawer всегда fullscreen.
src/ui/components/language-switch.tsx
- Display fallback: opt.short → opt.label → uppercase id.
Previously показывал id ('ru-RU', 'en-US') когда short не был задан —
теперь использует label ('RU', 'EN') как fallback.
Browser-verified в preview viewport 375×812:
- Hamburger ☰ visible, click открывает Sheet с nav items
- Backdrop fade + slide-from-left animation
- TopBar fits в 375px (RU/EN compact, Sign in visible)
- LoadingBlock + Alert text-wrap correctly
This commit is contained in:
@@ -1,33 +1,41 @@
|
||||
import { createRootRouteWithContext, Outlet } from '@tanstack/react-router'
|
||||
import type { QueryClient } from '@tanstack/react-query'
|
||||
import { Sidebar } from '@/components/layout/Sidebar'
|
||||
import { useState } from 'react'
|
||||
import { Sidebar, MobileSidebar } from '@/components/layout/Sidebar'
|
||||
import { TopBar } from '@/components/layout/TopBar'
|
||||
import { UpdateBanner } from '@/components/version/UpdateBanner'
|
||||
|
||||
/**
|
||||
* Root layout (Stage 3.1 design handoff):
|
||||
* Root layout (Stage 3.1 + 3.x mobile responsive):
|
||||
*
|
||||
* ┌─ Sidebar 220px (lg:flex) ──┬─ main column (flex-1) ────────────┐
|
||||
* │ logo │ UpdateBanner (when applicable) │
|
||||
* │ nav rail с counters │ TopBar h=56 sticky │
|
||||
* │ user profile │ Outlet (route content) │
|
||||
* └────────────────────────────┴───────────────────────────────────┘
|
||||
* ≥1024px (lg+):
|
||||
* ┌─ Sidebar 220px ──┬─ main column (flex-1) ────┐
|
||||
* │ logo │ TopBar (sticky) │
|
||||
* │ nav rail │ Outlet (route content) │
|
||||
* │ user profile │ │
|
||||
* └──────────────────┴───────────────────────────┘
|
||||
*
|
||||
* Responsive: на <1024px sidebar скрывается (hidden lg:flex). Main grid
|
||||
* растягивается на весь viewport. Mobile hamburger drawer — TODO Stage 3.x.
|
||||
* <1024px:
|
||||
* ┌─ main column (flex-1) ────────────────────────┐
|
||||
* │ TopBar [☰] (hamburger toggles MobileSidebar) │
|
||||
* │ Outlet │
|
||||
* └───────────────────────────────────────────────┘
|
||||
* MobileSidebar — overlay Sheet (slide-in left, 260px).
|
||||
*/
|
||||
export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({
|
||||
component: RootLayout,
|
||||
})
|
||||
|
||||
function RootLayout() {
|
||||
const [mobileNavOpen, setMobileNavOpen] = useState(false)
|
||||
return (
|
||||
<div className="h-screen flex flex-col bg-bg text-ink overflow-hidden">
|
||||
<UpdateBanner />
|
||||
<div className="flex-1 flex min-h-0">
|
||||
<Sidebar />
|
||||
<MobileSidebar open={mobileNavOpen} onClose={() => setMobileNavOpen(false)} />
|
||||
<div className="flex-1 flex flex-col min-w-0">
|
||||
<TopBar />
|
||||
<TopBar onMenuClick={() => setMobileNavOpen(true)} />
|
||||
<main className="flex-1 overflow-y-auto px-4 sm:px-6 py-4 sm:py-6">
|
||||
<div className="max-w-7xl mx-auto w-full">
|
||||
<Outlet />
|
||||
|
||||
Reference in New Issue
Block a user