@cloudgrid-io/ui

中文文档
0.51.1发布于 2026/11/10TypeScriptCommonJS近 30 天下载 1.6万

CloudGrid design system: React components, brand design tokens, Tailwind theme, self-hosted fonts.

原始使用文档
文档目录14 节
  1. Install
  2. Use a component
  3. Import the CSS, in this order
  4. The docs site (Starlight)
  5. Point Tailwind at the package
  6. Surfaces flip
  7. The install panel
  8. Entry points
  9. The CloudGrid sign as files
  10. The empty creations state
  11. Pictures in a component: embed or resolve
  12. The email layout
  13. Versioning
  14. Licence

@cloudgrid-io/ui

The CloudGrid design system: CSS custom properties, a Tailwind v4 theme, self-hosted fonts, and the same values as machine-readable JSON.

47 React components, built on Base UI, styled only through tokens and carrying no hardcoded colour.

Install

npm install @cloudgrid-io/ui

The three font families come with it and are self-hosted, so there is no request to a font CDN in your critical path.

Use a component

import { Button, Card, PricingTiers } from "@cloudgrid-io/ui"

Components are shipped compiled, one module per component, with type declarations. The 20 that need it keep their "use client" directive, so a React Server Component app gets exactly the client boundaries the source declares.

React is an optional peer dependency: take the stylesheets alone and nothing pulls in a component tree.

Import the CSS, in this order

@import "tailwindcss";

@import "@cloudgrid-io/ui/fonts.css";
@import "@cloudgrid-io/ui/tokens.css";
@import "@cloudgrid-io/ui/console.css";   /* optional, see below */
@import "@cloudgrid-io/ui/theme.css";
@import "@cloudgrid-io/ui/shadcn.css";

The order matters, and getting it wrong fails quietly rather than loudly.

  • theme.css maps Tailwind utilities onto the tokens. Before tokens.css has run there is nothing to map, so every utility resolves to nothing and the page renders unstyled instead of erroring.
  • console.css is a product preset, not part of the base. It re-declares the body face as the UI face, Manrope, and leaves the display face on Tanker, as the CloudGrid 2026 Figma has it (#371). The CloudGrid Console imports it; so should any product whose body type is the UI face. Everyone else leaves the line out and keeps the default. It also sets the body and label sizes to 14px (--cg-body-sm, --cg-label-size), so every library piece set in body text matches the Console's own 14px text; the caption stays 13px, and every product without the preset keeps 15px (#440). The Console's five type roles, as tokens: Body text-body-sm (14 / 1.46), Body Bold text-body-sm font-bold, Small text-caption (13 / 1.46), H4 text-heading-lg font-medium (22 / 1.2), Headline font-display (Tanker). A page picks a role, not a size. It has to sit after tokens.css, which is what it re-declares: import it before tokens.css and the default face wins at equal specificity, silently. Its position relative to theme.css does not matter. theme.css is @theme inline, so the utilities it emits are live var() references that resolve wherever the token ends up, and Tailwind hoists theme output above plain CSS anyway; measured with Tailwind 4, console.css before or after theme.css compiles byte-identical. The order above is still the recommended one, because it keeps the presets beside the tokens they change.
  • shadcn.css must come after whatever :root your own shadcn init wrote, because it overrides those values. Put it earlier and the stock grey palette wins.

Not using the Console's face: skip the console.css line. Not using shadcn: skip the last line. Not using Tailwind: tokens.css alone gives you every value as a custom property.

The docs site (Starlight)

The docs site is not Tailwind. It takes three stylesheets through Starlight's customCss, in this order, and the code-block configuration in one line:

import { cloudgridExpressiveCode } from "@cloudgrid-io/ui/expressive-code"

starlight({
  customCss: [
    "@cloudgrid-io/ui/fonts.css",
    "@cloudgrid-io/ui/tokens.css",
    "@cloudgrid-io/ui/docs.css",
  ],
  expressiveCode: cloudgridExpressiveCode,
})

docs.css maps Starlight's --sl-* variables onto the tokens and adds a few targeted rules. It is light only: it styles no dark scope, so the site must force the light theme and drop the theme picker (override Starlight's ThemeProvider and ThemeSelect). It has to come after tokens.css, which every value in it reads.

Point Tailwind at the package

Tailwind v4 ignores node_modules when it scans for classes, so utilities used only inside a component are never generated:

@source "../node_modules/@cloudgrid-io/ui/dist";

Adjust the path to your layout. Skipping this fails quietly — the build succeeds, the page renders, and the components come out unstyled.

Surfaces flip

Put data-cg-surface on a container and every semantic token inside it resolves to its on-surface value. Borders, backgrounds, focus rings and component internals follow, with no dark: variants and no second stylesheet.

<div data-cg-surface="panel" class="bg-panel text-ink">
  <!-- everything in here is now on brand purple -->
</div>

<div data-cg-surface="ink" class="bg-code text-ink">
  <!-- and everything in here is on near-black -->
</div>

Three surfaces: the default white page, panel on brand purple, and ink on near-black.

Text is the exception. Children inherit a colour their ancestor already resolved, so a container that sets data-cg-surface must also declare a token-based text colour — that is what text-ink is doing above. Borders and backgrounds flip on their own. Text does not.

There is no dark mode here, and this is not a substitute for one. Dark surfaces are a property of a container, never a page-level theme.

The install panel

Every CloudGrid install panel comes from this package, content and design both. Nothing is fetched.

import { CloudGridInstall, INSTALL_PRESETS, installToolPreset } from "@cloudgrid-io/ui"

<CloudGridInstall />                                    // the whole panel
<CloudGridInstall preset={INSTALL_PRESETS.onboarding} onValueChange={recordTool} />
<CloudGridInstall preset={installToolPreset("cursor")} />

There are no props for the words. A page chooses what is on screen (tools, methods, defaultTool, defaultMethod, showFetchPrompt, showFooter, or a preset) and what only it can know (the selected tool and method, the heading level, a Continue action). Tool values are stable identifiers, safe to record: claude-code, cursor, codex, antigravity, gemini, chatgpt, claude-web.

CloudGridFetchPrompt and CloudGridInstallFooter render on their own. Without React, take the strings from @cloudgrid-io/ui/install-content (INSTALL_TOOLS, INSTALL_COMMANDS and the rest).

Entry points

@cloudgrid-io/ui/tokens.cssevery value as a CSS custom property
@cloudgrid-io/ui/console.cssproduct preset: body type set to Manrope at 14px (label 14px), headlines stay Tanker
@cloudgrid-io/ui/docs.cssproduct preset: the Starlight docs site, light only, see below
@cloudgrid-io/ui/expressive-codethe docs site's code blocks: Expressive Code theme and overrides, monochrome on ink
@cloudgrid-io/ui/theme.cssmaps Tailwind utilities onto the tokens
@cloudgrid-io/ui/shadcn.cssmaps shadcn's variables onto the tokens
@cloudgrid-io/ui/fonts.cssthe three self-hosted families
@cloudgrid-io/ui/prose.csslong-form text
@cloudgrid-io/ui/tokens.jsonthe same values, machine-readable
@cloudgrid-io/ui/install-contentthe install content as plain data, no React
@cloudgrid-io/ui/emailrenderEmail: the CloudGrid email layout, content in, { html, text } out, no React
@cloudgrid-io/ui/chartshadcn's chart (ChartContainer, ChartTooltip, ChartTooltipContent, ChartLegend, ChartLegendContent, ChartStyle) on Recharts, set to the library's defaults. Not in the root import, so a page that never draws a chart never loads Recharts
@cloudgrid-io/ui/line-chartLineChart: one or more series over a date axis, on the chart above. Not in the root import, for the same reason

The JSON sets under tokens/ are DTCG and are the source the CSS is compiled from.

The CloudGrid sign as files

The socket glyph in a rounded square, as static files for a browser tab, a home screen or a web manifest. Two colourways: mark is the brand sign (purple square, white glyph, what the site uses) and mark-inverted is white with a purple glyph (what the Console's tab uses).

@cloudgrid-io/ui/brand/mark.svgSVG favicon, purple
@cloudgrid-io/ui/brand/mark-inverted.svgSVG favicon, white
@cloudgrid-io/ui/brand/mark-32.png, mark-inverted-32.pngPNG favicon fallback
@cloudgrid-io/ui/brand/mark-180.png, mark-inverted-180.pngapple-touch-icon, full bleed: iOS rounds it
@cloudgrid-io/ui/brand/mark-192.png, mark-inverted-192.pngweb manifest
@cloudgrid-io/ui/brand/mark-512.png, mark-inverted-512.pngweb manifest

A browser needs a URL, so copy them into your public folder or import them through your bundler:

// Next.js app router, e.g. app/layout.tsx
import favicon from "@cloudgrid-io/ui/brand/mark-inverted.svg"
import appleTouch from "@cloudgrid-io/ui/brand/mark-inverted-180.png"

export const metadata = {
  title: "CloudGrid",
  icons: { icon: favicon.src, apple: appleTouch.src },
}
<link rel="icon" href="/mark-inverted.svg" type="image/svg+xml">
<link rel="icon" href="/mark-inverted-32.png" sizes="32x32" type="image/png">
<link rel="apple-touch-icon" href="/mark-inverted-180.png">

Inside a page, use the component instead: <LogoMark tone="inverted" size={32} />. It draws the same glyph from the same constant as Logo, and the files are generated from that constant and the brand token by scripts/generate-brand-mark.mjs, so the three cannot drift.

The empty creations state

The new-user empty state for a list of someone's creations: a dashed box, a fan of thumbnails around a "+" tile, "No creations yet", one line and an Add button.

import Link from "next/link"
import { EmptyCreations } from "@cloudgrid-io/ui"

<EmptyCreations href="/drop" linkComponent={Link} level={3} />
<EmptyCreations onAdd={openComposer} />

The words and the four thumbnails come from the package; addLabel and previews override them. It lays out by container query, so it fits whatever width it is given. The thumbnails are inlined in the component, and also ship as files for any other use: @cloudgrid-io/ui/brand/creations/1.webp to 4.webp (164x94, 2 to 5KB each). After replacing a file, run node scripts/generate-creation-previews.mjs.

Pictures in a component: embed or resolve

Two components ship pictures, and they do it two ways on purpose. A new component with pictures picks one by this rule rather than by whichever example its author read last.

  • Embed small decorative defaults that must work with no consumer wiring. The pictures are inlined in the component as data URIs and ship as files under @cloudgrid-io/ui/brand/, with a test that holds the two byte-equal. EmptyCreations is the example: 4 thumbnails, about 13KB of files, about 18KB once inlined in empty-creations-previews.ts. It renders correctly the moment it is imported.
  • Resolve large sets, or any set the consumer is expected to choose. The pictures ship as files only, and the consumer hands the component a URL for each one (resolveSrc, or a src per item) through its own bundler or public folder. ShowcaseScroll is the example: 19 pictures, about 205KB of files. Inlined, they would add over a quarter of a megabyte to every bundle that imports the package barrel, whether or not that page shows them.

Rough line: embed when it is a handful of pictures and under about 20KB in total, and the component is useless without them. Past that, resolve. Base64 grows a file by about a third, and an inlined picture is paid for by every consumer of the barrel rather than only by the page that renders it.

The email layout

import { renderEmail } from "@cloudgrid-io/ui/email"

const { html, text } = renderEmail({
  headline: "expiring-soon",
  title: "Pricing Grid expires in 5 days.",
  points: ["Not opened in 25 days", "Expires Friday, October 16"],
  action: { label: "Keep it", url: "https://my.cloudgrid.io/entities/ent_7a10?action=keep" },
  note: "Kept pages don't expire.",
  footer: { lines: ["You get this because you own Pricing Grid."] },
  assetBaseUrl: "https://assets.example.com/email/", // where YOU serve brand/email/*
})

No dependencies and no React. Tables and inline styles for Gmail, Outlook and Apple Mail, and a plain-text part with every link written out.

The library names no host. Pictures and fonts load only from URLs the sender passes:

  • assetBaseUrl: serve this package's dist/brand/email/* (the wordmark, six headline images, the grid tile) from your own domain and pass that base. Without it the email is image-free for every client: the wordmark and headline are live text, which is also what Outlook for Windows always gets.
  • webFontsUrl: a stylesheet for Space Grotesk and Manrope, on a host you choose (GOOGLE_FONTS_EMAIL_CSS if you accept Google). Without it the system stack renders.
  • items[].imageUrl: your own picture URL, used as given.

Previews of every frame, as Apple Mail, Gmail and Outlook: /gallery/email in the registry.

Versioning

Semver. Token value changes are minor; removals are major.

Licence

See the repository.

版本与发布记录

@cloudgrid-io/ui 共发布 70 个版本,首次发布于 2026/08/20;过去 12 个月发布了 70 个版本。

版本发布日期距今
0.51.1latest2026/11/10今天
0.51.02026/11/10今天
0.50.02026/11/10今天
0.49.02026/11/09今天
0.48.02026/11/091 天前
0.47.02026/11/082 天前

关于 @cloudgrid-io/ui 的常见问题

@cloudgrid-io/ui 是什么?

CloudGrid design system: React components, brand design tokens, Tailwind theme, self-hosted fonts.

如何安装 @cloudgrid-io/ui?

在项目目录运行 npm install @cloudgrid-io/ui,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react-is(^19)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@cloudgrid-io/ui 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cloudgrid-io/ui 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@cloudgrid-io/ui 可以商用吗?

@cloudgrid-io/ui 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@cloudgrid-io/ui 的下载量有多少?

根据 npm 官方下载统计,@cloudgrid-io/ui 在 2026/10/10 – 2026/11/08 这 30 天内被下载 15,789 次,日均约 526 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cloudgrid-io/ui 还在维护吗?

最新版本 0.51.1 发布于 2026/11/10(今天);至今共发布 70 个版本,其中过去 12 个月发布了 70 个;首次发布于 2026/08/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。