企业软件 · 新资源

Red Hat PatternFly 设计系统.

使用 PatternFly 构建运维工作区:引用语义令牌、可选择的服务卡片、三态批量选择、范围审核,以及完整的原生 React 代码。

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

Red Hat PatternFly 设计系统界面预览

搜索服务库,选择单个服务或所有可见服务,查看副本总数,检查选择内容,并确认本地计划。

选择服务并查看维护范围打开完整示例
使用原生 PatternFly React 6.6.1 构建,并采用原始 Gallery/Card 和批量选择状态。仅包含示例运营数据。 · 实现参考
02

Red Hat PatternFly 设计系统设计参考

PatternFly React 6.6.1 和 @patternfly/react-tokens 6.6.1。下方展示了选定的已发布浅色主题令牌解析值。原生组件和 pf-v6-theme-dark 会解析深色样式;示例服务数据和布局则由应用自行设定。

语义化界面表面与文本角色

来源
名称 / 规则值 / 配置用途
--pf-t--global--background--color--primary--defaultrgb(255, 255, 255, 0.6000)在当前主题中使用相应的语义角色;品牌强调红色并非通用的主要操作颜色。
--pf-t--global--background--color--secondary--defaultrgb(199, 199, 199, 0.3000)在当前主题中使用相应的语义角色;品牌强调红色并非通用的主要操作颜色。
--pf-t--global--text--color--regular#151515 在当前主题中使用相应的语义角色;品牌强调红色并非通用的主要操作颜色。
--pf-t--global--text--color--subtle#383838 在当前主题中使用相应的语义角色;品牌强调红色并非通用的主要操作颜色。
--pf-t--global--text--color--disabled#a3a3a3 在当前主题中使用相应的语义角色;品牌强调红色并非通用的主要操作颜色。
--pf-t--global--color--brand--default#004d99 在当前主题中使用相应的语义角色;品牌强调红色并非通用的主要操作颜色。
--pf-t--global--color--brand--hover#003366 在当前主题中使用相应的语义角色;品牌强调红色并非通用的主要操作颜色。
--pf-t--global--color--brand--accent--default#ee0000 在当前主题中使用相应的语义角色;品牌强调红色并非通用的主要操作颜色。
--pf-t--global--color--brand--subtle--default#e0f0ff 在当前主题中使用相应的语义角色;品牌强调红色并非通用的主要操作颜色。

状态角色

来源
名称 / 规则值 / 配置用途
--pf-t--global--color--status--success--default#204d00 将状态意图与文字标签搭配使用。这些浅色主题数值不能替代原生 Label 或 Alert 变体。
--pf-t--global--color--status--warning--default#73480b 将状态意图与文字标签搭配使用。这些浅色主题数值不能替代原生 Label 或 Alert 变体。
--pf-t--global--color--status--danger--default#731f00 将状态意图与文字标签搭配使用。这些浅色主题数值不能替代原生 Label 或 Alert 变体。
--pf-t--global--color--status--info--default#3d2785 将状态意图与文字标签搭配使用。这些浅色主题数值不能替代原生 Label 或 Alert 变体。
--pf-t--global--color--status--custom--default#004d4d 将状态意图与文字标签搭配使用。这些浅色主题数值不能替代原生 Label 或 Alert 变体。
--pf-t--global--color--status--unread--default#0066cc 将状态意图与文字标签搭配使用。这些浅色主题数值不能替代原生 Label 或 Alert 变体。

正文与标题字体

来源
名称 / 规则值 / 配置用途
--pf-t--global--font--size--body--default0.875rem有意识地使用字体排印角色和语义标题级别。视觉字号并不决定文档大纲。
--pf-t--global--font--size--body--lg1rem有意识地使用字体排印角色和语义标题级别。视觉字号并不决定文档大纲。
--pf-t--global--font--size--heading--h11.5rem有意识地使用字体排印角色和语义标题级别。视觉字号并不决定文档大纲。
--pf-t--global--font--size--heading--h21.25rem有意识地使用字体排印角色和语义标题级别。视觉字号并不决定文档大纲。
--pf-t--global--font--size--heading--h31.125rem有意识地使用字体排印角色和语义标题级别。视觉字号并不决定文档大纲。
--pf-t--global--font--size--heading--h41rem有意识地使用字体排印角色和语义标题级别。视觉字号并不决定文档大纲。
--pf-t--global--font--size--heading--h51rem有意识地使用字体排印角色和语义标题级别。视觉字号并不决定文档大纲。
--pf-t--global--font--size--heading--h61rem有意识地使用字体排印角色和语义标题级别。视觉字号并不决定文档大纲。

间距比例

来源
名称 / 规则值 / 配置用途
--pf-t--global--spacer--xs0.25rem使用指定的间距比例设置分组和控件之间的间距;rem 值会随用户根字号变化。
--pf-t--global--spacer--sm0.5rem使用指定的间距比例设置分组和控件之间的间距;rem 值会随用户根字号变化。
--pf-t--global--spacer--md1rem使用指定的间距比例设置分组和控件之间的间距;rem 值会随用户根字号变化。
--pf-t--global--spacer--lg1.5rem使用指定的间距比例设置分组和控件之间的间距;rem 值会随用户根字号变化。
--pf-t--global--spacer--xl2rem使用指定的间距比例设置分组和控件之间的间距;rem 值会随用户根字号变化。
--pf-t--global--spacer--2xl3rem使用指定的间距比例设置分组和控件之间的间距;rem 值会随用户根字号变化。
--pf-t--global--spacer--3xl4rem使用指定的间距比例设置分组和控件之间的间距;rem 值会随用户根字号变化。
--pf-t--global--spacer--4xl5rem使用指定的间距比例设置分组和控件之间的间距;rem 值会随用户根字号变化。

形状与焦点

来源
名称 / 规则值 / 配置用途
--pf-t--global--border--radius--tiny4px根据具体组件选择合适的形状,不要将胶囊形圆角应用到所有界面表面。
--pf-t--global--border--radius--small6px根据具体组件选择合适的形状,不要将胶囊形圆角应用到所有界面表面。
--pf-t--global--border--radius--medium16px根据具体组件选择合适的形状,不要将胶囊形圆角应用到所有界面表面。
--pf-t--global--border--radius--large24px根据具体组件选择合适的形状,不要将胶囊形圆角应用到所有界面表面。
--pf-t--global--border--radius--pill999px根据具体组件选择合适的形状,不要将胶囊形圆角应用到所有界面表面。
--pf-t--global--border--radius--control--form-element6px根据具体组件选择合适的形状,不要将胶囊形圆角应用到所有界面表面。
--pf-t--global--border--radius--action--default999px根据具体组件选择合适的形状,不要将胶囊形圆角应用到所有界面表面。
03

Red Hat PatternFly 设计系统完整指南

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

DESIGN-red-hat-patternfly.md

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

下载指南

Red Hat PatternFly 设计系统运营布局

带有持久运营上下文的集合

服务库让运营人员可以比较服务的运行状况、位置和利用率,同时由独立的范围面板记录所选服务。所选内容并不等同于当前搜索结果。即使某项服务因筛选而隐藏,它仍会保持选中,直到有人主动将其移除。对于影响范围超出当前可见界面的大批量操作,这一区别至关重要。

摘自本 OpenDesign 指南

使用原生组件层级

Gallery 负责响应式卡片列布局,Card 用于区分各项服务,Label 用于标识状态,Progress 则通过标题展示示例百分比。此页面不会用随意的彩色矩形模仿基础设施控制台。完整的 React 示例实现了相应的数据模型、控件和审核状态。

Red Hat PatternFly 设计系统语义颜色与主题角色

主要品牌色与红色强调色彼此不同

PatternFly v6 导出了彼此独立的品牌、强调、文本、背景和状态角色。所选的浅色主题快照包含默认蓝色品牌色和默认红色品牌强调色。如果将所有醒目的操作都视为红帽红色,就会混淆这些角色。原生 Button 和 Label 组件会根据各自变体使用适当的系统角色。

在文档级别解析深色主题

此示例在 document 元素上切换 pf-v6-theme-dark。应用界面表面和文本使用 --pf-t--global 语义变量,因此主题也能正确解析它们的颜色。不要在自定义卡片中固定使用浅色值,再指望 document 主题类来修正颜色。

Red Hat PatternFly 设计系统字体与服务元数据

将视觉尺寸与标题语义分开

Title 的 headingLevel h1 用于确立页面标题,而 size 控制视觉强调程度。在此软件包快照中,Body-default 为 0.875rem。卡片标签、状态和利用率数值都应保持易读,但不必把每个值都设为标题。元数据定义列表会明确列出副本数量和服务 ID。

避免使用含义模糊的操作标签

组件和页脚都将示例利用率标记为示例数据。单独的进度条容易被误认为部署任务或加载操作。说明文字会解释百分比的含义,状态 Label 则单独说明容量是“健康”还是“需检查”。

Red Hat PatternFly 设计系统图库与批量选择

使用复选框的三种状态

所有可见服务均已选中时,“选择可见项”控件的值为 true;未选中任何服务时,值为 false;仅选中部分服务时,值为 null。PatternFly Checkbox 支持表示不确定状态的 null 值。应用会根据经过筛选的集合计算此状态,而不是使用可能与各行选择状态不一致的独立布尔值。

  1. 选择一个服务,查看部分选中状态。
  2. 选择当前所有可见服务。
  3. 搜索一个名称,确认隐藏的已选项仍保留在范围内。
  4. 检查确切的选择集和副本总数。
  5. 确认本地计划并查看结果。

以选择集作为唯一数据源

Red Hat PatternFly 设计系统间距与响应式卡片

使用语义令牌构建页面外壳

示例中的背景、常规文本和次要元数据使用已发布令牌包中的语义 CSS 属性。原生间距比例从 xs 延伸至 4xl,而此应用在集合与范围面板之间使用 24px 的间距。这个明确指定的组合间距值与令牌引用不同。

优先调整图库布局,而不是压缩内容

图库项的最小宽度为 230px,并设有间距。在应用的 850px 断点处,范围面板会移至集合下方。在 500px 处,页面内边距调整为 16px,搜索框占满工具栏宽度。这些是本示例的布局决策,并不意味着所有 PatternFly 产品都使用这些断点。

Red Hat PatternFly 设计系统审核与选择状态

选择操作不应直接执行任务

勾选服务只会将其添加到范围中。点击“审核选择”会显示信息提示 Alert 和确认操作。“确认本地计划”会报告所选服务和副本总数,但不会启动维护任务。更改选择时会关闭审核状态,避免意外确认已过时的选择集。

将搜索恢复与选择状态分开处理

未匹配到结果时,会显示一条内联信息提示 Alert,其中包含“清除搜索”操作。此操作只会清除查询,不会更改已选服务。因此,工具栏中的选中数量和范围面板仍保持一致。如果搜索结果为空就顺带重置选择,这会构成一种隐蔽的破坏性行为。

Red Hat PatternFly 设计系统无障碍控件与状态

为选择控件添加标签并使用原生控件

每个 Checkbox 都有稳定的 id 和可见的服务标签。SearchInput 具有无障碍名称,Switch 用于标识外观设置;选择集为空时,“审核选择”处于禁用状态。原生 Progress 会传达其数值和标题。页面不依赖卡片中仅悬停时才出现的操作。

用文字明确呈现状态

选择数量使用 polite 实时区域;服务状态以文字显示在 Label 中;最终 Alert 会说明发生了什么。不要仅用颜色表示选择范围或健康状态。键盘测试应涵盖部分选择、筛选掉已选服务,以及返回完整集合等情况。

  • 已选中的复选框表示纳入选择,而不是成功状态。
  • 状态 Label 描述的是服务状态,而非服务是否已选中。
  • Progress 表示示例利用率,而非操作完成进度。

Red Hat PatternFly 设计系统 React 集成

仅在入口处导入一次重置样式和组件样式

此示例在入口文件中导入 @patternfly/react-core/dist/styles/base.css。原生 React 组件通过软件包提供自身的组件样式。应用的 CSS 作用域限定为 pf-example,并引用当前的 --pf-t--global 命名空间;它不会覆盖组件内部样式。

仅通过服务契约添加真正的调度功能

Red Hat PatternFly 设计系统组件示例

main.jsx — 服务图库与批量审核

完整的原生 Gallery/Card/Checkbox/Progress 组合,包含派生的选择范围和本地确认。

jsx
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import {
  Alert,
  Button,
  Card,
  CardBody,
  CardTitle,
  Checkbox,
  Gallery,
  GalleryItem,
  Label,
  Progress,
  SearchInput,
  Switch,
  Title,
} from "@patternfly/react-core";
import "@patternfly/react-core/dist/styles/base.css";
import "./patternfly.css";
const services = [
  {
    id: "api",
    name: "Public API",
    region: "eu-west",
    replicas: 6,
    load: 62,
    status: "Healthy",
  },
  {
    id: "jobs",
    name: "Background jobs",
    region: "eu-west",
    replicas: 3,
    load: 81,
    status: "Review capacity",
  },
  {
    id: "search",
    name: "Search index",
    region: "us-east",
    replicas: 4,
    load: 44,
    status: "Healthy",
  },
  {
    id: "events",
    name: "Event stream",
    region: "us-east",
    replicas: 8,
    load: 72,
    status: "Healthy",
  },
];
function App() {
  const [query, setQuery] = useState(""),
    [selected, setSelected] = useState([]),
    [review, setReview] = useState(false),
    [notice, setNotice] = useState(""),
    [dark, setDark] = useState(false);
  const visible = services.filter((x) =>
    x.name.toLowerCase().includes(query.toLowerCase()),
  );
  const picked = services.filter((x) => selected.includes(x.id));
  const allVisible =
    visible.length > 0 && visible.every((x) => selected.includes(x.id));
  const someVisible = visible.some((x) => selected.includes(x.id));
  function choose(id, checked) {
    setSelected((v) =>
      checked ? [...new Set([...v, id])] : v.filter((x) => x !== id),
    );
    setReview(false);
  }
  function selectVisible(checked) {
    setSelected((v) =>
      checked
        ? [...new Set([...v, ...visible.map((x) => x.id)])]
        : v.filter((id) => !visible.some((x) => x.id === id)),
    );
    setReview(false);
  }
  return (
    <main className="pf-example">
      <header>
        <div>
          <span className="overline">PATTERNFLY · SERVICE OPERATIONS</span>
          <Title headingLevel="h1" size="2xl">
            Plan a maintenance review
          </Title>
          <p>
            Select services and inspect the combined scope before creating a
            local plan.
          </p>
        </div>
        <Switch
          id="dark-theme"
          label="Dark theme"
          isChecked={dark}
          onChange={(_, checked) => {
            setDark(checked);
            document.documentElement.classList.toggle(
              "pf-v6-theme-dark",
              checked,
            );
          }}
        />
      </header>
      <div className="service-toolbar">
        <SearchInput
          aria-label="Find a service"
          placeholder="Find a service"
          value={query}
          onChange={(_, value) => setQuery(value)}
          onClear={() => setQuery("")}
        />
        <Checkbox
          id="select-visible"
          label="Select visible"
          isChecked={allVisible ? true : someVisible ? null : false}
          isDisabled={!visible.length}
          onChange={(_, checked) => selectVisible(checked)}
        />
        <span aria-live="polite">{selected.length} selected</span>
        <Button isDisabled={!selected.length} onClick={() => setReview(true)}>
          Review selection
        </Button>
      </div>
      <div className="service-layout">
        <Gallery hasGutter minWidths={{ default: "230px" }}>
          {visible.map((s) => (
            <GalleryItem key={s.id}>
              <Card>
                <CardTitle>
                  <Checkbox
                    id={"select-" + s.id}
                    label={s.name}
                    isChecked={selected.includes(s.id)}
                    onChange={(_, checked) => choose(s.id, checked)}
                  />
                </CardTitle>
                <CardBody>
                  <div className="service-meta">
                    <Label color={s.status === "Healthy" ? "green" : "orange"}>
                      {s.status}
                    </Label>
                    <span>{s.region}</span>
                  </div>
                  <Progress
                    value={s.load}
                    title="Sample utilization"
                    measureLocation="outside"
                  />
                  <dl>
                    <dt>Replicas</dt>
                    <dd>{s.replicas}</dd>
                    <dt>Service ID</dt>
                    <dd>
                      <code>{s.id}</code>
                    </dd>
                  </dl>
                </CardBody>
              </Card>
            </GalleryItem>
          ))}
        </Gallery>
        <aside>
          <Card>
            <CardTitle>Maintenance scope</CardTitle>
            <CardBody>
              <p>
                {picked.length} services ·{" "}
                {picked.reduce((n, s) => n + s.replicas, 0)} replicas
              </p>
              {picked.length ? (
                <ul>
                  {picked.map((s) => (
                    <li key={s.id}>
                      {s.name}
                      <span>{s.region}</span>
                    </li>
                  ))}
                </ul>
              ) : (
                <p className="muted">Select a service to inspect its scope.</p>
              )}
              {review && (
                <div className="review">
                  <Alert
                    isInline
                    variant="info"
                    title="Review the selected services"
                  >
                    This is a fictional plan. No workload will be restarted.
                  </Alert>
                  <Button
                    onClick={() => {
                      setNotice(
                        `Local plan includes ${picked.length} services and ${picked.reduce((n, s) => n + s.replicas, 0)} replicas. No operation was scheduled.`,
                      );
                      setReview(false);
                    }}
                  >
                    Confirm local plan
                  </Button>
                </div>
              )}
            </CardBody>
          </Card>
        </aside>
      </div>
      {!visible.length && (
        <Alert isInline variant="info" title="No services match">
          <Button variant="link" onClick={() => setQuery("")}>
            Clear search
          </Button>
        </Alert>
      )}
      {notice && (
        <Alert isInline variant="success" title="Local plan recorded">
          {notice}
        </Alert>
      )}
      <footer>
        Native PatternFly 6.6.1 · service data and capacity figures are
        fictional, memory-only examples.
      </footer>
    </main>
  );
}
createRoot(document.getElementById("root")).render(<App />);

代码参考

  • 保存为 src/main.jsx。Checkbox onChange 会接收事件和选中值;集合处于混合选择状态时,isChecked 可以为 null。

patternfly.css — 响应式操作界面外壳

自定义页面布局使用语义化的 v6 令牌,同时保留原生组件样式。

css
body {
  margin: 0;
}
.pf-example {
  padding: 24px;
  background: var(--pf-t--global--background--color--secondary--default);
  color: var(--pf-t--global--text--color--regular);
  font-family: var(--pf-t--global--font--family--body);
}
.pf-example header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  margin-bottom: 24px;
}
.overline {
  font-size: 11px;
  letter-spacing: 0.07em;
  color: var(--pf-t--global--text--color--subtle);
}
.pf-example header h1 {
  margin: 8px 0;
}
.service-toolbar {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 24px;
}
.service-toolbar > .pf-v6-c-search-input {
  width: 280px;
}
.service-toolbar > span {
  margin-left: auto;
}
.service-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  gap: 24px;
  align-items: start;
}
.service-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 12px;
  margin-bottom: 24px;
}
.service-layout dl {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 24px;
  font-size: 12px;
}
.service-layout dd {
  margin: 0;
}
.service-layout ul {
  padding: 0;
  list-style: none;
  margin: 16px 0;
}
.service-layout li {
  padding: 12px 0;
  border-bottom: 1px solid var(--pf-t--global--border--color--default);
}
.service-layout li span {
  display: block;
  font-size: 12px;
  color: var(--pf-t--global--text--color--subtle);
}
.muted {
  color: var(--pf-t--global--text--color--subtle);
  margin-top: 16px;
}
.review > .pf-v6-c-button {
  margin-top: 16px;
}
.pf-example > .pf-v6-c-alert {
  margin-top: 24px;
}
.pf-example footer {
  font-size: 12px;
  color: var(--pf-t--global--text--color--subtle);
  margin-top: 24px;
}
@media (max-width: 850px) {
  .service-layout {
    grid-template-columns: 1fr;
  }
  .pf-example header {
    align-items: start;
  }
  .service-toolbar > span {
    margin-left: 0;
  }
}
@media (max-width: 500px) {
  .pf-example {
    padding: 16px;
  }
  .pf-example header {
    flex-direction: column;
  }
  .service-toolbar {
    gap: 16px;
  }
  .service-toolbar > .pf-v6-c-search-input {
    width: 100%;
  }
}

代码参考

  • 保存为 src/patternfly.css。应用断点是本示例明确指定的一部分。
04

Red Hat PatternFly 设计系统 Agent 设置

实现起点

原生 React 18.3.1 / PatternFly 6.6.1 组合。Vite 需要受支持的 Node.js 版本。实际服务数据和操作 API 仍由应用负责。

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

适用于你项目的提示词

Agent 提示词
使用 PatternFly 6.6.1 原生 Gallery、Card、Checkbox、Progress、Label 和 Alert,构建运维集合。使用提供的语义令牌和完整示例。将筛选后的可见项与已选 ID 分开管理,计算批量选择的部分选中状态,并要求审核确切的受影响对象集合。添加真实的 API 后,应如实反馈待处理、失败或成功状态。确保移动端布局能够重排,并支持键盘操作。
05

Red Hat PatternFly 设计系统的来源与范围

这是由 OpenDesign 编写的应用指南,附带虚构的维护计划示例,使用原生 PatternFly React 6.6.1 运行。利用率、区域和副本数量均为示例数据。确认操作只会更新本地状态;不会重启服务或安排计划。