数据分析 · 新资源

Palantir Blueprint 设计系统.

使用 Blueprint 构建密集的数据工作区:经验证的字体和意图令牌、可选择的数据集表、审核检查器,以及完整的 React 源码。

OpenDesign 指南8 个章节60 条参考条目原始应用指南
01

Palantir Blueprint 设计系统界面预览

按名称或类型筛选、选择数据集、更改行密度、切换外观,并在更新本地状态前验证审核备注。

数据集表格和审核检查器打开完整示例
原生 Blueprint 6.21.0,搭配 React 18.3.1。原创的响应式工作台布局;没有服务器,也不会保存审核记录。· 实现参考
02

Palantir Blueprint 设计系统设计参考

Blueprint 核心 6.21.0 发布于 CSS,并提供原生 React 组件。此处列出所选的浅色主题令牌值;请使用库的深色主题,不要手动反转这些值。示例 CSS 中标明了应用程序的布局选择。

意图颜色和交互状态

来源
名称 / 规则值 / 配置用途
--bp-intent-primary-rest#2d72d2 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-primary-hover#215db0 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-primary-active#184a90 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-primary-disabled#4c90f0 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-primary-foreground#ffffff 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-success-rest#238551 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-success-hover#1c6e42 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-success-active#165a36 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-success-disabled#32a467 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-success-foreground#ffffff 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-warning-rest#c87619 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-warning-hover#935610 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-warning-active#77450d 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-warning-disabled#ec9a3c 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-warning-foreground#111418 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-danger-rest#cd4246 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-danger-hover#ac2f33 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-danger-active#8e292c 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-danger-disabled#e76a6e 使用指定的语义角色;将状态与前景色搭配使用。
--bp-intent-danger-foreground#ffffff 使用指定的语义角色;将状态与前景色搭配使用。

字体比例和字重

来源
名称 / 规则值 / 配置用途
--bp-typography-size-body-x-small10px正文、标签和辅助数据的字体比例;不要将小号元数据用作主要阅读字号。
--bp-typography-size-body-small12px正文、标签和辅助数据的字体比例;不要将小号元数据用作主要阅读字号。
--bp-typography-size-body-medium14px正文、标签和辅助数据的字体比例;不要将小号元数据用作主要阅读字号。
--bp-typography-size-body-large16px正文、标签和辅助数据的字体比例;不要将小号元数据用作主要阅读字号。
--bp-typography-size-heading-small16px在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-size-heading-medium20px在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-size-heading-large24px在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-size-heading-x-large28px在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-size-heading-display46px在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-size-code-small12px在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-size-code-medium13px在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-size-code-large14px在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-weight-default400在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-weight-bold600在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-line-height-default1.28581在指定的层级应用相应角色;表格数字也可以使用等宽数字。
--bp-typography-line-height-large1.5在指定的层级应用相应角色;表格数字也可以使用等宽数字。

界面表面、边框和语义文本

来源
名称 / 规则值 / 配置用途
--bp-surface-border-color-default#5f6b7c1f使用指定的语义角色;将状态与前景色搭配使用。
--bp-surface-border-color-strong#5f6b7c40使用指定的语义角色;将状态与前景色搭配使用。
--bp-surface-border-width1px使用指定的语义角色;将状态与前景色搭配使用。
--bp-surface-border-radius4px使用指定的语义角色;将状态与前景色搭配使用。
--bp-surface-spacing4px使用指定的语义角色;将状态与前景色搭配使用。
--bp-surface-background-color-default-rest#ffffff 使用指定的语义角色;将状态与前景色搭配使用。
--bp-surface-background-color-default-hover#f6f7f9 使用指定的语义角色;将状态与前景色搭配使用。
--bp-typography-color-default-rest#1c2127 使用指定的语义角色;将状态与前景色搭配使用。
--bp-typography-color-muted#5f6b7c 使用指定的语义角色;将状态与前景色搭配使用。

焦点与动效

来源
名称 / 规则值 / 配置用途
--bp-emphasis-transition-duration100ms使用指定的语义角色;将状态与前景色搭配使用。
--bp-emphasis-ease-defaultcubic-bezier(0.4, 1, 0.75, 0.9)使用指定的语义角色;将状态与前景色搭配使用。
--bp-emphasis-ease-bouncecubic-bezier(0.54, 1.12, 0.38, 1.11)使用指定的语义角色;将状态与前景色搭配使用。
--bp-emphasis-focus-color#2d72d2 使用指定的语义角色;将状态与前景色搭配使用。
--bp-emphasis-focus-width2px使用指定的语义角色;将状态与前景色搭配使用。
--bp-emphasis-focus-offset2px使用指定的语义角色;将状态与前景色搭配使用。
--bp-emphasis-motion-reduced0使用指定的语义角色;将状态与前景色搭配使用。

数据集工作台中使用的原生组件

来源
名称 / 规则值 / 配置用途
HTMLTablestriped · interactive · condensed原生语义化表格;condensed 属性可调整密度,而不改变数据。
InputGroupvalue · onChange · intent受控搜索和审核备注;应用程序验证会设置 danger 意图。
FormGrouplabelFor · helperText · intent关联可见的字段标签,并说明备注无效的原因。
HTMLSelectoptions · value · onChange用于少量固定数据集类型的原生选择框。
Tagminimal · intent将状态文本与 success 或 warning 样式搭配使用。
Buttonintent="primary" · type="submit"通过真实表单提交本地审核;选择按钮保持次要地位。
Switchchecked · onChange相互独立的外观和密度控件。
Calloutintent · title说明无结果的情况或操作结果;不要只用颜色传达状态。
03

Palantir Blueprint 设计系统完整指南

实用指南,介绍如何为真实界面选择、应用和评审此系统。

DESIGN-palantir-blueprint.md

完整指导、实现起点和源代码链接。

下载指南

围绕数据构建的 Palantir Blueprint 设计系统工作区

密集控件与明确的阅读顺序

当屏幕需要同时展示集合、筛选器、状态和上下文操作时,Blueprint 尤其适用。此示例将数据集表格放在左侧,将选中的记录放在右侧。读者无需为查看每条记录而打开新页面,即可进行比较。检查器中包含可编辑的审核备注;表格则作为浏览区域。

摘自本 OpenDesign 指南

使用 v6 软件包约定

此示例使用 @blueprintjs/core 6.21.0 编译。其 CSS 命名空间为 bp6,已发布的语义令牌以 --bp- 开头。旧版 bp5 样式表不能替代 v6 组件的 CSS。请在应用入口处仅导入一次该软件包的样式表,然后将应用布局规则限定在单独的类中。

Palantir Blueprint 设计系统的意图与颜色角色

将记录状态与选择状态分开

警告 Tag 表示数据集需要审核;带主色调的行表示该记录已选中。两者含义彼此独立。将某行标记为已审核后,其标签和意图会变为成功状态,而选择仍保留在同一数据集上。表格为每种状态保留文字说明,避免仅靠颜色传达全部含义。

在组件边界处理深色模式

此示例在包装元素上添加 bp6-dark,使原生组件能够应用对应的深色样式。上方的浅色主题值只是参考快照,并不意味着要覆盖每个组件。引入 Dialog 等门户组件时,请确保其渲染内容也能获得相同的主题上下文;仅靠不包含门户的包装元素并不足够。

Palantir Blueprint 记录与元数据的设计系统排版

先了解正文的字号层级,再选择标题

已发布的正文字号包括 10、12、14 和 16px;中号正文为 14px。数据集名称保持在主要阅读层级。ID 和记录类型使用辅助文本,记录数量则使用等宽数字,便于比较变化中的数值。本指南不建议将 10px 用于主要内容。

为检查器建立紧凑的层级

检查器使用 20px 标题和定义列表展示 ID、所有者、类型与数量。标签和值采用稳定的两列对齐方式。审核备注放在这些信息之后,并用分隔线隔开,避免用户误以为该操作会筛选表格。

Palantir Blueprint 设计系统表格、筛选器与检查器

保留表格语义

HTMLTable 提供采用 Blueprint 样式的原生表格。首列中的按钮用于选择记录,并且可通过键盘访问;示例不会将仅支持指针操作的行事件处理程序作为唯一的选择方式。interactive 属性提供行悬停样式,condensed 则独立控制密度,不影响筛选。

清晰呈现受控数据流

  1. 按显示名称查找数据集。
  2. 使用类型选择器缩小同一集合的范围。
  3. 选择名称按钮以加载检查器。
  4. 输入审核备注并提交本地审核。

Palantir Blueprint 设计系统间距、界面表面与密度

采用更小的间距单位,但不必让所有间隔都变得很小

已发布的界面表面间距令牌为 4px。工作台使用该单位的倍数进行布局:筛选控件之间为 12px,集合与检查器之间为 20px,桌面示例周围为 24px。这些是 CSS 中展示的组合布局决策。4px 的圆角令牌让控件和界面的几何形态保持克制。

先调整布局,再考虑缩减标签

在示例应用设置的 800px 断点处,检查器会移至集合下方。筛选器会换行,主区域内边距缩至 16px;必要时,表格会使用独立的水平滚动容器。此断点仅适用于本工作台,并非 Blueprint 官方通用断点。

Palantir Blueprint 设计系统审核与空状态

在审核操作中进行验证

提交空备注时,InputGroup 和 FormGroup 会设置为 danger 意图,显示说明性辅助文本,并将焦点移至该字段。输入文字后,错误提示会清除。有效提交只会更改所选的本地记录、清空备注,并显示明确说明未发送任何数据的成功 Callout。

在空集合旁提供恢复操作

无结果 Callout 提供“清除筛选条件”操作,会同时重置搜索查询和类型选择器,从而恢复完整集合。此操作不会删除行,也不会更改检查器。以下状态边界均为有意设计:

  • 选择操作会更改检查器中显示的记录,不会更改其审核状态。
  • 紧凑模式只会改变密度,不会调整记录顺序。
  • 主题只会改变视觉外观,不会更改当前筛选条件。
  • 本地审核成功后,只会更改一条记录,并会告知用户结果。

Palantir Blueprint 设计系统焦点与无障碍组件使用

为每个原生控件添加标签

InputGroup 为搜索框设置无障碍名称,并为带标签的审核字段设置 id。HTMLSelect 具有自己的名称,Switch 会显示可见标签,每条记录则通过真正的按钮打开。请使用这些库 API,而不要用经过样式处理的 div 替代控件。

保留清晰可见的焦点样式

软件包参考中包含 2px 的焦点宽度和 2px 的偏移。请确保焦点指示在 Card 和选中行上清晰可见。键盘用户应能按文档顺序访问筛选器、行按钮和审核表单。示例中的状态段落和成功 Callout 会传达操作结果,无须将用户带到另一个屏幕。

Palantir Blueprint 设计系统安装与应用边界

运行与示例相同的源代码

下方提供完整的 App 源代码和应用 CSS。App 会挂载到 Vite React 模板生成的根元素中。安装指定版本的 core 软件包即可使用原生组件和软件包 CSS;这个纯文本示例不需要任何隐藏的设计资源。

通过实际持久化约定扩展审核功能

Palantir Blueprint 设计系统组件示例

main.jsx — 完整的数据集审核应用

完整的原生组合示例,包含筛选、选择、密度、主题、字段验证和本地审核结果。

jsx
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import {
  Button,
  Card,
  Callout,
  FormGroup,
  HTMLSelect,
  HTMLTable,
  InputGroup,
  Switch,
  Tag,
} from "@blueprintjs/core";
import "@blueprintjs/core/lib/css/blueprint.css";
import "./blueprint.css";
const initial = [
  {
    id: "D-1042",
    name: "Harbor sensors",
    type: "Telemetry",
    rows: "18,420",
    owner: "Maya",
    status: "Reviewed",
  },
  {
    id: "D-1043",
    name: "Transit stops",
    type: "Reference",
    rows: "842",
    owner: "Alex",
    status: "Needs review",
  },
  {
    id: "D-1044",
    name: "Water samples",
    type: "Field survey",
    rows: "2,608",
    owner: "Sam",
    status: "Reviewed",
  },
  {
    id: "D-1045",
    name: "Street survey",
    type: "Field survey",
    rows: "4,120",
    owner: "Lee",
    status: "Needs review",
  },
];
function App() {
  const [dark, setDark] = useState(false),
    [compact, setCompact] = useState(false),
    [query, setQuery] = useState(""),
    [rows, setRows] = useState(initial),
    [selected, setSelected] = useState(initial[1]),
    [note, setNote] = useState(""),
    [notice, setNotice] = useState(""),
    [error, setError] = useState(false),
    [type, setType] = useState("All");
  const visible = rows.filter(
    (r) =>
      r.name.toLowerCase().includes(query.toLowerCase()) &&
      (type === "All" || r.type === type),
  );
  function review(e) {
    e.preventDefault();
    if (!note.trim()) {
      setError(true);
      document.getElementById("review-note").focus();
      return;
    }
    const updated = { ...selected, status: "Reviewed" };
    setRows(rows.map((r) => (r.id === selected.id ? updated : r)));
    setSelected(updated);
    setNotice(
      `${selected.name} marked reviewed in this local example. No data was sent.`,
    );
    setNote("");
    setError(false);
  }
  return (
    <main className={"specimen " + (dark ? "bp6-dark" : "")}>
      <header>
        <div>
          <span className="eyebrow">BLUEPRINT · DATA WORKSPACE</span>
          <h1 className="bp6-heading">Dataset review</h1>
          <p className="bp6-text-muted">
            Inspect a record and attach a review note.
          </p>
        </div>
        <Switch
          label="Dark theme"
          checked={dark}
          onChange={(e) => setDark(e.target.checked)}
        />
      </header>
      <div className="workbench">
        <Card className="collection">
          <div className="toolbar">
            <InputGroup
              aria-label="Find a dataset"
              placeholder="Find a dataset…"
              value={query}
              onChange={(e) => setQuery(e.target.value)}
            />
            <HTMLSelect
              aria-label="Dataset type"
              value={type}
              onChange={(e) => setType(e.target.value)}
              options={["All", "Telemetry", "Reference", "Field survey"]}
            />
            <Switch
              label="Compact rows"
              checked={compact}
              onChange={(e) => setCompact(e.target.checked)}
            />
          </div>
          <p className="bp6-text-small bp6-text-muted" role="status">
            {visible.length} matching datasets
          </p>
          <div className="table-scroll">
            <HTMLTable
              striped
              interactive
              condensed={compact}
              style={{ width: "100%" }}
            >
              <thead>
                <tr>
                  <th>Name</th>
                  <th>Records</th>
                  <th>Status</th>
                </tr>
              </thead>
              <tbody>
                {visible.map((r) => (
                  <tr
                    key={r.id}
                    className={selected.id === r.id ? "selected" : ""}
                  >
                    <td>
                      <Button
                        variant="minimal"
                        onClick={() => {
                          setSelected(r);
                          setError(false);
                          setNote("");
                        }}
                        text={r.name}
                      />
                      <div className="bp6-text-small bp6-text-muted">
                        {r.id} · {r.type}
                      </div>
                    </td>
                    <td className="numeric">{r.rows}</td>
                    <td>
                      <Tag
                        minimal
                        intent={r.status === "Reviewed" ? "success" : "warning"}
                      >
                        {r.status}
                      </Tag>
                    </td>
                  </tr>
                ))}
              </tbody>
            </HTMLTable>
          </div>
          {!visible.length && (
            <Callout title="No matching datasets">
              Clear the search or choose a different dataset type.
              <Button
                variant="minimal"
                onClick={() => {
                  setQuery("");
                  setType("All");
                }}
              >
                Clear filters
              </Button>
            </Callout>
          )}
        </Card>
        <Card className="inspector">
          <span className="eyebrow">SELECTED DATASET</span>
          <h2 className="bp6-heading">{selected.name}</h2>
          <dl>
            <dt>Dataset ID</dt>
            <dd>
              <code>{selected.id}</code>
            </dd>
            <dt>Owner</dt>
            <dd>{selected.owner}</dd>
            <dt>Type</dt>
            <dd>{selected.type}</dd>
            <dt>Records</dt>
            <dd>{selected.rows}</dd>
          </dl>
          <form onSubmit={review}>
            <FormGroup
              label="Review note"
              labelFor="review-note"
              intent={error ? "danger" : "none"}
              helperText={
                error
                  ? "Add a note describing what you checked."
                  : "A short note keeps the decision understandable."
              }
            >
              <InputGroup
                id="review-note"
                value={note}
                intent={error ? "danger" : "none"}
                aria-invalid={error}
                onChange={(e) => {
                  setNote(e.target.value);
                  setError(false);
                }}
              />
            </FormGroup>
            <Button intent="primary" type="submit" fill>
              Mark reviewed locally
            </Button>
          </form>
          <p className="bp6-text-small bp6-text-muted">
            Selection, filters and review notes exist only in this preview.
          </p>
        </Card>
      </div>
      {notice && (
        <Callout intent="success" role="status">
          {notice}
        </Callout>
      )}
      <footer>
        Native Blueprint 6.21.0 · HTMLTable, Card, FormGroup, InputGroup,
        Switch, Tag and Callout.
      </footer>
    </main>
  );
}
createRoot(document.getElementById("root")).render(<App />);

代码参考

  • 将此文件保存为 src/main.jsx,并将下一个示例保存为 src/blueprint.css。
  • createRoot 调用使用 Vite React index.html 中的根元素。

blueprint.css — 响应式工作台布局

应用布局规则与导入的原生 CSS 相辅相成。800px 断点和 260px 检查器宽度是示例中明确设定的值。

css
* {
  box-sizing: border-box;
}
body {
  margin: 0;
}
.specimen {
  padding: 24px;
  background: #f6f7f9;
  color: #1c2127;
  font-size: 14px;
}
.specimen.bp6-dark {
  background: #252a31;
  color: #f6f7f9;
}
.specimen header {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
  margin-bottom: 24px;
}
.eyebrow {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--bp-typography-color-muted);
}
h1.bp6-heading {
  margin: 8px 0;
  font-size: 28px;
}
.workbench {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 260px;
  gap: 20px;
}
.collection,
.inspector {
  min-width: 0;
}
.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}
.toolbar > .bp6-input-group {
  flex: 1;
  min-width: 150px;
}
.toolbar .bp6-control {
  margin: 0;
}
.table-scroll {
  overflow: auto;
}
table td {
  vertical-align: middle !important;
}
.numeric {
  font-variant-numeric: tabular-nums;
}
tr.selected td {
  background: #2d72d20d !important;
}
.inspector h2 {
  font-size: 20px;
  margin-top: 12px;
}
.inspector dl {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin: 24px 0;
}
.inspector dt {
  color: var(--bp-typography-color-muted);
}
.inspector dd {
  margin: 0;
}
.inspector form {
  border-top: 1px solid var(--bp-surface-border-color-default);
  padding-top: 20px;
}
.inspector p {
  margin: 16px 0 0;
}
.specimen > .bp6-callout {
  margin-top: 20px;
}
.specimen footer {
  font-size: 11px;
  margin-top: 24px;
  color: var(--bp-typography-color-muted);
}
@media (max-width: 800px) {
  .workbench {
    grid-template-columns: 1fr;
  }
  .specimen {
    padding: 16px;
  }
  .specimen header {
    align-items: start;
  }
  .toolbar {
    gap: 16px;
  }
  h1.bp6-heading {
    font-size: 24px;
  }
}
@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
  }
}

.bp6-dark .eyebrow,
.bp6-dark .inspector dt,
.bp6-dark footer {
  color: #abb3bf;
}

代码参考

  • bp6-dark 类会启用库主题;示例画布的背景属于应用 CSS。
04

Palantir Blueprint 设计系统 Agent 设置

实现起点

此原生预览使用 React 18.3.1 和 Blueprint 6.21.0 打包并运行。请使用所选 Vite 版本支持的 Node.js 版本。上文提供了两个应用文件。

sh
npm create vite@latest blueprint-review -- --template react
cd blueprint-review
npm install
npm install [email protected] [email protected] @blueprintjs/[email protected]
# Replace src/main.jsx and add src/blueprint.css using the complete examples.
npm run dev

适用于你项目的提示词

Agent 提示词
使用 Blueprint 6.21.0 构建数据集审核工作区。阅读提供的令牌和完整的 React/CSS 示例。保留原生 HTMLTable、带标签的 InputGroup/FormGroup、状态 Tag,以及可通过键盘操作的行选择。筛选、选择、密度、外观和审核状态应彼此独立。只有在提供 API 后才接入真实的保存服务;显示待处理和失败响应时,不要丢失备注。保留响应式检查器和可见的焦点状态。
05

Palantir Blueprint 设计系统来源与范围

OpenDesign 是一份面向 Blueprint 6.21.0 的应用指南,包含一个原创的数据集审核示例,实际运行 React 包。数据集名称和审核结果均为本地示例数据。工作台布局属于应用代码;参考值来自按版本发布的程序包。