AppShell
반응형 헤더, 사이드바, 레일, 모바일 탐색 영역을 조합해요.
타입이 있는 header, sidebar, main, outline 파트를 반응형 rail 또는 modal drawer 탐색, route progress, 스크롤 복원과 함께 조합해요.
핵심 속성
| 속성 | 설명 |
|---|---|
| 헤더 높이 | 애플리케이션 크롬에서 TRAppShellHeader는 TRMeasurements.headerHeight에 서고, comfortable 밀도에서는 TRSpacing.large만큼 더 높아져 TRPaneHeader와 높이가 맞아요. 고정 높이가 아니라 기준 높이라서, 큰 텍스트 배율에서 줄바꿈된 제목처럼 내용이 더 크면 잘리지 않고 바가 늘어나요. 높이를 정확히 고정하려면 height를 전달하세요. |
설치
패키지를 추가한 뒤 공개 라이브러리를 가져오세요.
flutter pub add tinyrack_uiimport 'package:tinyrack_ui/tinyrack_ui.dart';플레이그라운드
사용법
import 'package:material_ui/material_ui.dart';
import 'package:tinyrack_ui/tinyrack_ui.dart';
TRAppShell(
breakpoint: TRAppShellBreakpoint.sm,
layout: TRAppShellLayout.sidebarFirst,
controller: controller,
header: TRAppShellHeader(children: [brand, actions]),
sidebar: TRAppShellSidebar(child: navigation),
main: const TRAppShellMain(child: Workspace()),
)파트와 상태
TRAppShell은 TRAppShellHeader, TRAppShellSidebar, TRAppShellMain과 선택적인 TRAppShellOutline을 받습니다. Brand와 Actions는 header를 정렬하고, SidebarLabel은 rail에서 시각적으로 숨겨져도 접근 가능한 이름을 유지해요. 외부 상태가 필요하면 하나의 TRAppShellController로 mobileOpen과 sidebarMode를 제어하세요.
final controller = TRAppShellController(
mobileOpen: false,
sidebarMode: TRAppShellSidebarMode.expanded,
);
TRAppShell(
controller: controller,
onMobileOpenChanged: handleOpen,
onSidebarModeChanged: handleSidebarMode,
header: TRAppShellHeader(children: [
TRAppShellTrigger(
icon: const Icon(Icons.menu),
label: 'Open navigation',
),
TRAppShellBrand(child: const Text('Orbit Ops')),
]),
sidebar: TRAppShellSidebar(child: navigation),
main: const TRAppShellMain(child: Workspace()),
)반응형 레이아웃과 포커스
sm은 768px, lg는 1024px viewport 경계예요. headerFirst는 header를 전체 너비에 두고 sidebarFirst는 sidebar를 전체 높이에 둡니다. 모바일 drawer는 논리적 start 또는 end에서 열리는 Navigator route라서 배경 클릭, Escape와 시스템 뒤로 가기로 닫히며 포커스를 내부에 가두고 trigger로 복원해요. mobileSidebar를 rail로 설정하면 64px 탐색을 계속 표시합니다.
반응형 pane 레이아웃
TRAdaptiveNavigationLayout과 TRAdaptiveListDetailLayout을 조합하면 600px 미만에서는 content만, 600–1199px에서는 navigation과 content를, 1200px 이상에서는 navigation, collection, detail을 배치할 수 있어요. 두 레이아웃은 navigation 상태를 소유하지 않아요. Navigator와 Page가 history, 시스템 뒤로 가기, Android predictive Back, 중단된 전환을 담당하도록 구성하세요. 같은 key를 가진 content Navigator를 singlePane과 detailPane에 전달하면 breakpoint가 바뀌어도 상태를 유지할 수 있어요. 하위 pane은 TRAdaptiveLayoutScope에서 전체 viewport의 width class를 읽습니다.
final contentNavigator = Navigator(
key: contentNavigatorKey,
pages: contentPages,
onDidRemovePage: handleRemovedPage,
);
TRAdaptiveNavigationLayout(
navigationPane: TRNavigationPane(children: navigationSections),
contentPane: TRAdaptiveListDetailLayout(
singlePane: contentNavigator,
collectionPane: const ProjectList(),
detailPane: contentNavigator,
),
)소프트웨어 키보드
TRAppShell은 기본적으로 header, sidebar와 main을 소프트웨어 키보드 위에 유지하면서 배경은 viewport 끝까지 그려요. 의도적으로 키보드 뒤에 인터랙티브 콘텐츠를 그려야 할 때만 resizeToAvoidBottomInset을 false로 설정하세요.
TRAppShell(
resizeToAvoidBottomInset: false,
main: const TRAppShellMain(child: ImmersiveCanvas()),
)sidebar 너비와 접기
TRAppShellSidebar는 자기 너비를 스스로 가집니다. 기본값은 현재 모드의 shell 너비이고 width로 덮어쓸 수 있어요. 펼침, 접힘, rail 전환 같은 모든 너비 변화는 TRMotion.normal 동안 애니메이션되고, 그동안 내용은 목표 너비로 배치된 채 잘려요. collapsed를 주면 접히기 시작하는 즉시 포커스, 포인터, 시맨틱스에서 빠지고 애니메이션이 끝나면 트리에서 제거됩니다. 고정 너비 SizedBox로 감싸지 마세요. 접근성 설정에서 애니메이션을 끄면 즉시 전환돼요.
TRAppShell(
sidebar: TRAppShellSidebar(
collapsed: navigationCollapsed,
child: navigation,
),
main: const TRAppShellMain(child: Workspace()),
)문서 chrome과 스크롤
docs는 48px header, 선택적 outline과 route progress를 제공합니다. pendingPath가 currentPath와 다르면 Main이 busy 상태가 됩니다. container는 Main 내부 scroll area를 사용하고 primary는 현재 Flutter route의 primary scroller를 사용해요. PUSH와 REPLACE는 위로 이동하고 POP은 locationKey의 위치를 복원하며 hash는 anchorTargets의 GlobalKey로 이동합니다.
TRAppShell(
chrome: TRAppShellChrome.docs,
currentPath: route.path,
pendingPath: navigation.pendingPath,
locationKey: route.key,
navigationKind: TRAppShellNavigationKind.pop,
hash: route.hash,
anchorTargets: {'install': installHeadingKey},
pageScroll: TRAppShellPageScroll.container,
header: TRAppShellHeader(children: [brand, actions]),
sidebar: TRAppShellSidebar(child: docsNavigation),
outline: TRAppShellOutline(child: tableOfContents),
main: TRAppShellMain(scroll: true, child: article),
)예시
컨트롤 appearance 고유 링크
Trigger, Close, SidebarToggle은 32px small 컨트롤이며 solid, outline, ghost appearance를 공유해요.
문서 chrome과 스크롤 복원 고유 링크
docs chrome은 48px header와 route progress를 추가하고 Main이 이름 있는 container scroll을 소유해요.
공통 pane chrome 고유 링크
PaneHeader는 앞쪽 탐색, density에 맞는 제목, 보조 설명, 줄바꿈되는 action, 본문 divider를 정렬해요.
API
AppShell는 Flutter의 네이티브 상태와 콜백을 유지하고 Tinyrack 토큰을 기본값으로 사용해요.