Repository navigation
Studio 布局重构:Supabase 风格的 TopBar + LeftSidebar + Content #1203
Copy link
Copy link
Closed
Description
Context
当前 Studio 的布局是 Shadcn SidebarProvider + 左侧边栏(GlobalSidebar 或 AppSidebar)+ 每个页面内部再自行 <SiteHeader /> 的模式。问题:
- Org / Env / Package 切换分散在
SiteHeader(Org、Env)和AppSidebar头部(Package),同一认知层级被切成两处。 - 每个路由都要手动 import
SiteHeader,重复且容易漂移(breadcrumb 逻辑、操作按钮样式都不一致)。 - 视觉上缺少 Supabase 那种"顶部全局 chrome + 左侧功能导航 + 右侧纯内容区"的清晰三段式。
目标:改造为 顶部栏(全局 chrome)+ 左侧栏(保留 metadata 树)+ 右侧内容区,让全局身份上下文集中在顶部,页面只关注 body。
方案
1. 新增 TopBar 全局组件
文件:apps/studio/src/components/top-bar.tsx(新建)
承载:
- 左段:Logo +
OrganizationSwitcher(复用components/organization-switcher.tsx)+EnvironmentSwitcher(复用components/environment-switcher.tsx)+ Package 切换器(从app-sidebar.tsx里 SidebarHeader 的 DropdownMenu 抽出,命名为PackageSwitcher,放到components/package-switcher.tsx) - 中段:
SidebarTrigger(折叠左栏)+ 面包屑(吸收SiteHeader的viewLabels/selectedMeta/ API 路径 Badge 逻辑;通过读取useLocation+useParams动态计算,不再需要每页传 props) - 右段:全局搜索框(
⌘K占位,后续接入;暂用 shadcnInput+kbd样式)、环境模式 Badge(config.mode)、ThemeToggle、UserMenu
高度仍为 h-12,border-b,与现有 SiteHeader 对齐以减少视觉跳变。
2. 改造 routes/__root.tsx
- 在
RootComponent的SidebarProvider内部、<Outlet />外层加一个 flex 列容器:<TopBar />在上,下方是<div className="flex flex-1 min-h-0">{sidebar}{outlet}</div>。 TopBar仅在已登录且非 public 路由时渲染(沿用RequireAuth的逻辑)。GlobalSidebar/AppSidebar的选择逻辑保留(isGlobalShellPath),但它们从此只负责"功能导航 + metadata 树",不再承担 Org/Env/Package 切换。global-sidebar.tsx:删除OrgHeader(Org 切换器移到 TopBar),SidebarHeader可直接省略或仅留 Logo。app-sidebar.tsx:删除顶部 Package SwitcherSidebarHeader块,把 Package 下拉菜单抽到新的PackageSwitcher组件给 TopBar 使用。
3. 删除每页 <SiteHeader />
影响文件(共 11 个路由):
routes/index.tsxroutes/api-console.tsxroutes/orgs.index.tsx/orgs.new.tsx/orgs.$orgId.tsxroutes/environments.index.tsx/environments.$environmentId.index.tsx/environments.$environmentId.packages.tsxroutes/environments.$environmentId.$package.index.tsxroutes/environments.$environmentId.$package.objects.$name.tsxroutes/environments.$environmentId.$package.metadata.$type.$name.tsx
每个文件:
- 删除
import { SiteHeader } ...和<SiteHeader ... />。 - 页面顶层容器
<div className="flex h-svh flex-col ...">去掉h-svh(高度交由根布局的 flex container 接管),或者改成flex-1 min-h-0 overflow-auto。 - 原
SiteHeader里传入的selectedObject/selectedMeta/selectedView信息由TopBar通过路由参数自行推断,不再需要页面显式传值。
4. 删除 site-header.tsx
所有用处被 TopBar 吸收后,删除 apps/studio/src/components/site-header.tsx。
5. environments.$environmentId.$package.tsx 调整
当前 <main className="flex min-w-0 flex-1 flex-col h-svh overflow-hidden ..."> 里的 h-svh 会和新的根 flex 冲突,改为 flex min-w-0 flex-1 flex-col overflow-hidden。
关键文件
| 路径 | 操作 |
|---|---|
apps/studio/src/components/top-bar.tsx |
新建 |
apps/studio/src/components/package-switcher.tsx |
新建(从 app-sidebar 抽出) |
apps/studio/src/routes/__root.tsx |
加入 TopBar + flex 列布局 |
apps/studio/src/components/global-sidebar.tsx |
删除 OrgHeader |
apps/studio/src/components/app-sidebar.tsx |
删除顶部 Package Switcher header |
apps/studio/src/components/site-header.tsx |
删除 |
| 上述 11 个路由文件 | 移除 <SiteHeader /> 引用 & 调整外层高度 class |
可复用的既有资产
components/organization-switcher.tsx、components/environment-switcher.tsx、components/environment-badge.tsx、components/theme-toggle.tsx、components/user-menu.tsx全部直接复用。- Shadcn
SidebarProvider/SidebarTrigger保留,继续提供折叠能力。 hooks/useSession、useEnvironmentDetail、useEnvAwarePackages已提供 TopBar 需要的所有上下文。- 面包屑渲染可复用
components/ui/breadcrumb.tsx。
验证
pnpm --filter @objectstack/studio dev启动,依次访问:/login→ 无 TopBar / Sidebar(public 路由)。/environments→ TopBar 显示 Org 切换器 + Env 切换器(Env 未选时 disabled);左侧 GlobalSidebar 仅剩功能入口,不再有 Org 下拉。/environments/:id→ Env 切换器显示当前 env;左侧 GlobalSidebar;无页面级二级 header。/environments/:id/:package/objects/:name→ TopBar 出现 Package Switcher + 面包屑Package › Object › <name>+ API 路径 Badge;左侧 AppSidebar 的 metadata 树正常展开,顶部不再重复 Package 下拉。
- 折叠
SidebarTrigger,右侧内容区无抖动。 - 切换主题、切换 Org、切换 Env、切换 Package 全部通过 TopBar 触发,并正确更新 URL / session。
pnpm --filter @objectstack/studio test通过;全量pnpm build通过(TypeScript 校验会捕获未清理的<SiteHeader />引用)。
Reactions are currently unavailable
Activity