mcpField
P
primer-design

primer-design

github.com/bas设计与 UI036 次安装40 周前更新
代码仓库

关于 primer-design

指导实现符合 GitHub Primer 品牌规范的前端界面的设计技能,面向构建组件、页面或应用的开发者。内容涵盖 Primer React 组件、Octicons、布局样式、无障碍要求及测试步骤。

主要功能

  1. 01遵循 Primer 品牌规范
  2. 02使用 Primer React 组件
  3. 03使用 Octicons 图标
  4. 04提供布局与样式指导
  5. 05涵盖无障碍检查
  6. 06要求构建和运行测试

适用场景

  1. 01按 Primer 规范构建前端页面
  2. 02使用 Primer 组件实现界面布局
  3. 03为交互界面检查无障碍要求
  4. 04完成界面改动后的构建与验证

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bas/agent-skills --skill primer-design

安装后在 Claude Code 中输入/primer-design确认已加载。

详细介绍

Primer 设计说明

此技能旨在指导创建符合 HitHub Primer 品牌设计指南的生产级前端界面。编写可实际运行的代码,并格外注重遵循 Primer 设计系统指南、Brand UI、Primer React 组件和 Octicons。

用户会提供前端需求:要构建的组件、页面、应用或界面。他们可能还会说明用途、受众或技术限制。

设计思路

开始编写代码前,先了解背景并确定清晰的美学方向:

  • 用途:此界面要解决什么问题?谁会使用它?
  • 基调:遵循 GitHub 专业而友好的品牌语调——清晰、亲切,并以开发者为中心
  • 限制:技术要求(框架、性能、无障碍性)
  • 差异化:如何让界面令人印象深刻?着重于简洁、实用的设计和明确的视觉层次

重要:选择清晰的概念方向,并精准执行。Primer 设计系统强调清晰易用,而非装饰性。

然后编写可实际运行的代码,要求:

  • 达到生产级质量且功能完善
  • 视觉清晰、易于使用
  • 符合 Primer 的设计原则
  • 精心打磨每个细节

限制

始终遵循品牌指南:https://brand.github.com/。

从这里开始:https://primer.style/brand/introduction/getting-started/。

安装与设置
  1. 安装所需的软件包:
npm install @primer/react-brand @primer/octicons-react
  1. 重要:在根布局/应用文件中导入 Primer CSS:
import "@primer/react-brand/lib/css/main.css";
  1. 重要:处理 Vite/React Router 的 CommonJS 兼容性。使用默认导入并进行解构:
// ✅ CORRECT - Use default import with destructuring for CommonJS compatibility
import pkg from "@primer/react-brand";
const { ThemeProvider, Button, Hero, Heading, Text, Grid, Stack } = pkg;
  1. 在根节点使用 ThemeProvider 包装应用:
import pkg from "@primer/react-brand";
const { ThemeProvider } = pkg;

function App() {
  return (
    <ThemeProvider>
      <div>...</div>
    </ThemeProvider>
  )
}
使用 Primer React 组件

始终使用官方 Primer React Brand 组件,不要使用自定义 HTML/CSS。关键组件:

Hero 组件

使用 className 属性进行自定义样式设置,或使用 Box 组件控制内边距/外边距:

import pkg from "@primer/react-brand";
const { Hero, Box } = pkg;

// ✅ OPTION 1: Using className with custom CSS
<Hero className="custom-hero-padding" align="center">
  <Hero.Label>Label</Hero.Label>
  <Hero.Heading>This is my super sweet hero heading</Hero.Heading>
  <Hero.Description>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  </Hero.Description>
  <Hero.PrimaryAction href="#">Primary action</Hero.PrimaryAction>
  <Hero.SecondaryAction href="#">Secondary action</Hero.SecondaryAction>
  <Hero.Image src="/path/to/image.png" alt="Description" />
</Hero>

// ✅ OPTION 2: Using Box component for layout
<Box paddingBlockStart={128} paddingBlockEnd={128}>
  <Hero align="center">
    <Hero.Label>Label</Hero.Label>
    <Hero.Heading>This is my super sweet hero heading</Hero.Heading>
    <Hero.Description>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </Hero.Description>
    <Hero.PrimaryAction href="#">Primary action</Hero.PrimaryAction>
  </Hero>
</Box>
使用 Octicons 的 Button 组件

参考:https://primer.style/brand/components/Button/react/

import pkg from "@primer/react-brand";
const { Button } = pkg;
import { PackageIcon, SearchIcon } from "@primer/octicons-react";

// ✅ CORRECT - Use leadingVisual/trailingVisual props for icons
<Button 
  variant="primary"
  leadingVisual={<PackageIcon />}
  hasArrow={false}
  block
>
  Add to Cart
</Button>

// Available variants: 'primary', 'secondary', 'subtle', 'accent'
// Available sizes: 'small', 'medium', 'large'
// Props: block, hasArrow, leadingVisual, trailingVisual

// ✅ Octicons support fill, className, and style props
<Button leadingVisual={<PackageIcon fill="#0969da" />}>
  Add to Cart
</Button>

// ✅ Also valid - using className
<Button leadingVisual={<PackageIcon className="custom-icon" />}>
  Add to Cart
</Button>

// ✅ Also valid - wrapping in div for additional styling
<Button leadingVisual={<div style={{ color: "#0969da" }}><PackageIcon /></div>}>
  Add to Cart
</Button>
布局组件
import pkg from "@primer/react-brand";
const { Grid, Stack, Box } = pkg;

// Grid for responsive layouts
<Grid>
  <Grid.Column span={{ medium: 4 }}>Content</Grid.Column>
  <Grid.Column span={{ medium: 8 }}>Content</Grid.Column>
</Grid>

// Stack for consistent spacing
<Stack direction="vertical" gap="normal" padding="spacious">
  <div>Item 1</div>
  <div>Item 2</div>
</Stack>

// Box for padding, margin, background, and borders
<Box 
  paddingBlockStart={64} 
  paddingBlockEnd={64}
  backgroundColor="subtle"
  borderRadius="medium"
>
  <Heading>Content with spacing</Heading>
</Box>

Box 组件:使用 Box 替代 div 进行布局,并设置适当的间距:

  • 内边距属性:padding、paddingBlockStart、paddingBlockEnd、paddingInlineStart、paddingInlineEnd
  • 外边距属性:margin、marginBlockStart、marginBlockEnd、marginInlineStart、marginInlineEnd
  • 值:使用间距比例(8、16、24、32、40、48、64、80、96、128)或响应式对象
  • 背景:backgroundColor="default" 或 "subtle"
  • 边框:borderColor、borderRadius、borderStyle
排版组件
import pkg from "@primer/react-brand";
const { Heading, Text } = pkg;

<Heading as="h1" size="1">Main Heading</Heading>
<Heading as="h2" size="3">Section Heading</Heading>
<Text size="300" weight="semibold">Body text</Text>
使用 Octicons 图标

任何图标都必须使用来自 @primer/octicons-react 的 Octicons:

import { SearchIcon, PackageIcon, ChevronDownIcon } from "@primer/octicons-react";

// Use with Button leadingVisual/trailingVisual
<Button leadingVisual={<SearchIcon />}>Search</Button>

图标列表:https://primer.style/octicons/

样式设置方法
  1. 优先使用 Primer 组件,而不是自定义 HTML/CSS
  2. 使用 Box 组件设置布局间距(内边距、外边距),不要使用包装 div
  3. 使用 Primer 组件上的 className 属性,通过外部 CSS 设置自定义样式
  4. 尽量少用内联样式——仅在 Box 和 className 不适用时使用
  5. 使用标准 CSS 值(px、#0969da 等颜色),而不是 CSS 变量
  6. 遵循 GitHub 的配色方案:
    • 主蓝色:#0969da
    • 成功绿色:#1f883d
    • 背景:#ffffff(白色)、#f6f8fa(浅灰色)
    • 边框:#d0d7de
    • 文本:#24292f(主要)、#57606a(次要)
常见模式

使用 Box 的页面布局:

import pkg from "@primer/react-brand";
const { Box } = pkg;

<Box backgroundColor="subtle" style={{ minHeight: "100vh" }}>
  <Box 
    as="header" 
    backgroundColor="default" 
    borderColor="default"
    borderStyle="solid-bottom"
    paddingBlockStart={16} 
    paddingBlockEnd={16}
  >
    {/* Navigation */}
  </Box>
  <Box 
    as="main" 
    style={{ maxWidth: "1280px", margin: "0 auto" }}
    paddingBlockStart={48}
    paddingBlockEnd={48}
    paddingInlineStart={24}
    paddingInlineEnd={24}
  >
    {/* Content */}
  </Box>
  <Box 
    as="footer"
    borderColor="default"
    borderStyle="solid-top"
    paddingBlockStart={32}
    paddingBlockEnd={32}
  >
    {/* Footer */}
  </Box>
</Box>

使用 Box 的卡片组件:

<Box
  backgroundColor="default"
  borderColor="default"
  borderStyle="solid"
  borderRadius="medium"
  padding={24}
>
  {/* Card content */}
</Box>

设置图标样式:

// ✅ OPTION 1: Use fill prop directly on icon
<PackageIcon size={24} fill="#0969da" />

// ✅ OPTION 2: Use className prop
<PackageIcon size={24} className="custom-icon" />

// ✅ OPTION 3: Wrap in div (inherits currentColor)
<div style={{ color: "#0969da" }}>
  <PackageIcon size={24} />
</div>

// Octicons support: size, fill, className, style, aria-label, and all SVG props
组件参考

完整的组件文档和 API:

无障碍

始终遵循无障碍指南:https://primer.style/accessibility/

  • 使用语义化 HTML
  • 使用恰当的标题层级
  • 为图片添加替代文本
  • 为交互元素设置焦点状态
  • 必要时添加 ARIA 标签
测试要求

完成工作前,务必构建并测试更改:

  1. 运行 npm run build,检查 TypeScript 错误
  2. 在开发模式下测试应用(npm run dev)
  3. 验证所有路由和导航是否正常工作
  4. 检查响应式行为和无障碍性
  5. 切勿交付无法构建或运行的更改
常见问题与解决方案

问题:“Named export not found”错误或 CommonJS 模块警告

// ❌ WRONG - Named imports fail with CommonJS in dev/SSR
import { Button } from '@primer/react-brand';

// ❌ WRONG - Namespace imports may be undefined
import * as PrimerBrand from "@primer/react-brand";

// ✅ CORRECT - Use default import with destructuring
import pkg from "@primer/react-brand";
const { Button } = pkg;

问题:需要为 Primer 组件设置自定义间距

// ❌ AVOID - Wrapper divs add unnecessary DOM nesting
<div style={{ padding: "80px 24px" }}>
  <Hero>...</Hero>
</div>

// ✅ BETTER - Use className with CSS file
<Hero className="hero-spacing">...</Hero>

// ✅ BEST - Use Box component for layout
<Box paddingBlockStart={80} paddingBlockEnd={80} paddingInlineStart={24} paddingInlineEnd={24}>
  <Hero>...</Hero>
</Box>

问题:Octicon 颜色未生效

// ✅ CORRECT - Use fill prop for icon color
<PackageIcon fill="#0969da" />

// ✅ ALSO CORRECT - Set color on parent (icon inherits via currentColor)
<div style={{ color: "#0969da" }}>
  <PackageIcon />
</div>

// ✅ ALSO CORRECT - Use className
<PackageIcon className="text-blue" />

问题:路由无法正常工作(404 错误)

  • 始终使用 route() 函数将新路由添加到 app/routes.ts
import { type RouteConfig, index, route } from "@react-router/dev/routes";

export default [
  index("routes/home.tsx"),
  route("products", "routes/products.tsx"),
] satisfies RouteConfig;

评论

支持 Markdown