跳到主要内容

布局

布局

Bolt 中的应用表面由 布局原语 中的一小组 @norbital-ai/ui/layout 组合而成。原语拥有几何;外壳拥有应用区域与文档滚动;每个表面遵循同一个主体约定。编译时检查强制执行这一点——违反规则的表面会构建失败,而不仅仅是审查不通过。

原语

按布局意图选择原语,而不是按哪个看起来最接近:

意图原语说明
纵向节奏Stackgap 的子元素列,可选的 align / justify
一行Inline子元素的一条水平线
自动换行组Cluster会换行的行;标签、徽章、按钮组
两个自适应区域Split具名比例( railsidebarthirdhalfwide )与共享折叠令牌
内禀网格Gridminimum 令牌( compact / card / panel
精确跨度Columns + Column固定数量(2/3/4/6)并带显式 span
顶部、主体、底部Cover在可选的 topbottom
可读度量Center把宽度约束到一个度量( narrow / reading / wide / full
媒体裁剪Frame固定宽高比( square / portrait / landscape / widescreen
局部滚动Bound + Scroll永远成对出现——绝不用裸 overflow

所有原语都接受令牌刻度上的 gappadnonexssmmdlgxl )、一个 as 元素(一组流程容器白名单,如 sectionarticlemainform ),以及各自的具名属性。父级选择布局算法;子级不请求增长。

应用主体约定

每个应用都是一个带 Covertop 标题插槽与恰好一个主体区域:

┌───────────────────────────────────────────────┐
│ Cover  top={pageHeading}                      │
│   ┌─────────────────────────────────────────┐ │
│   │ PageHeader title="Tasks" …              │ │
│   └─────────────────────────────────────────┘ │
│                                               │
│   body region (one of three, below)           │
│   ┌─────────────────────────────────────────┐ │
│   │ Scroll name="tasks" inset               │ │
│   │   ┌───────────────────────────────────┐ │ │
│   │   │ CollectionTable collection="tasks"│ │ │
│   │   └───────────────────────────────────┘ │ │
│   └─────────────────────────────────────────┘ │
└───────────────────────────────────────────────┘

合法的主体区域恰好有三种,每一种都同时拥有滚动与应用内边距:

主体拥有滚动 + 内边距
<Tabs … />,自动
<Scroll name="…" inset> ,用于流式内容
<Bound size="full" inset> ,用于单个自滚动组件
<script lang="ts">
  import { CollectionTable } from '@norbital-ai/ui/collection-table';
  import { Bound, Cover, Scroll } from '@norbital-ai/ui/layout';
  import { PageHeader } from '@norbital-ai/ui/page-header';
</script>

<svelte:head>
  <title>Tasks</title>
  <meta name="bolt:icon" content="lucide:list-todo" />
</svelte:head>

{#snippet pageHeading()}
  <PageHeader title="Tasks" description="Everything the team is working on." />
{/snippet}

<Cover as="main" top={pageHeading}>
  <Scroll name="tasks-scroll" inset>
    <CollectionTable collection="tasks">
      {#snippet columns({ Column })}
        <Column name="title" />
        <Column name="status" />
      {/snippet}
    </CollectionTable>
  </Scroll>
</Cover>

滚动:每个轴一个属主

外壳拥有文档滚动;每个局部滚动区域都是显式的 Bound + Scroll 对。每个祖先链有 每个轴一个滚动属主与一个内边距属主 ;兄弟面板可以拥有各自的。由此得出的规则在编译时强制执行:

  • 不允许泛化的 overflow 包装器、 overflow-hidden 裁剪或裸 flex/min-size 滚动链。
  • 不允许裸的结构性 flex/grid 容器,也不允许兄弟之间的 margin——间距是原语的 gap .
  • 不允许字面的 px-4 sm:px-6 风格类——应用内边距是原语的 inset .
  • 布局原语上不允许 style 属性——使用它的具名属性。
  • 裁剪只对文本截断、 Frame 媒体或经过审计的弹窗/抽屉边界有效。

无需断点配方的响应式

  • Split 接受 collapsestackswitchnone )与共享的 collapseAt 令牌,而不是任意宽度。
  • Grid 是内禀的:它从 minimum 令牌按可用空间自动适配单元格。只有在精确数量或跨度重要时才用 Columns
  • Center 无需手工媒体查询即可保持阅读宽度。优先使用内禀布局与共享容器查询令牌,而不是视口断点配方。
强制执行,而非建议
编译器在每个表面上校验布局约定:未知布局属性、裸裁剪、滚动链与原语上的内联样式都是诊断项,位于 src/apps/ 之外的编写源码也以同样的方式检查。表单如何融入表面参见 UI 组件
  • 应用 ——应用元数据与客户端访问
  • UI 组件 ——主体区域内的集合表面
  • 导航状态 ——记录详情栈与侧边抽屉