@contentrain/astro-kit

中文文档
0.50.9发布于 2026/11/05MITTypeScriptES Module构建来源已验证近 30 天下载 7744

Copy-in Astro components for Contentrain sites (shadcn model): typed props, tailwind-variants, zero JavaScript by default — with a machine-readable catalog

原始使用文档
文档目录9 节
  1. Components
  2. Measured style
  3. Tokens
  4. Section hooks
  5. API
  6. Mapping tables
  7. Development
  8. Part of the Contentrain ecosystem
  9. License

@contentrain/astro-kit

Copy-in Astro components for Contentrain sites, the shadcn model: a site receives the component source and owns it from then on. Nothing here is a runtime dependency of the site. The package ships the components, a machine-readable catalog, builder mapping tables and a small API to copy components into a project.

The components are made for templates/astro-starter. They read its design tokens and pass its gates: astro check with the strictest preset, knip, a single stylesheet and zero JavaScript by default.

Components

idWhat it isJavaScript
headerBrand, navigation, optional call to actionnone; renders nav
navInline menu with submenus; popover drawer or <details> on phonesnone; a few lines when the menu has submenus
footerBrand, link columns or a link row, social links, copyrightnone
heroPage opener: heading, text, points, actions, imagenone
card-gridGrid of cards (features, services, team)none
post-cardOne post in a listnone
ctaCall-to-action bandnone
faqQuestions as <details>, optional FAQPage JSON-LDnone
tabsTabbed panels; readable as headed sections without JavaScriptZag.js
testimonialQuotes with author and rolenone
galleryImage grid; a click opens a native popover or a lightbox viewernone; the lightbox option adds a few lines, no dependency
sliderCarousel on a scroll-snap row: image, video (a file played only on request, or a YouTube/Vimeo link loaded only on click) or text-card slidesEmbla
contact-formContentrain Studio form in a sectionStudio runtime
newsletterSign-up posting straight to the list provider (Mailchimp, Kit, MailerLite, Brevo, Buttondown)none
embedVideo, map or player loaded on click; a provider link until then (YouTube via nocookie)a few lines, no dependency
paginationWordPress-style /page/N/ linksnone
breadcrumbAncestors, then the current page, optional JSON-LDnone
bandThe styled fallback section: heading, lead, image, a grid of items (figure, title, detail, text, points, link) and buttons, in the measured framenone
dialogA popup the visitor opens: a button and a modal <dialog> with text, buttons and a form slot; never opens by itselfa few lines, no dependency
behaviorA behavior island: a source widget no component carries (slider, tabs, accordion, counter, toggle, filter, in-page dialog, anchor links, image lightbox, a video player kept as a poster link that plays in place on click), kept as its own markup and wired by one vanilla module; static and readable without it_shared/behaviors.ts, no dependency
announcementA one-line notice above the header with an optional link; closed through a <details>none
consentCookie consent bar with accept and decline; consent is denied until the visitor acceptsa few lines, no dependency
contact-detailsEmail, phone, postal address, opening hours and a map link, without a formnone
feature-listShort features, each a title and a line of text with an icon or a checknone
language-switcherLinks to the same page in the site's other languages, as a list or a <details> menunone
logo-cloudClient or partner logos as a grid, a row or an endless stripnone
post-listA list of posts as cards: a grid, stacked rows, a featured first post or a compact listnone
pricingPrice plans side by side, with a featured plannone
proseA rich-text body as the editor wrote it, styled by Tailwind Typography; the fallback for unmapped elementsnone
search-boxA search field that sends the visitor to /search?q=…none
social-linksLinks to the site's profiles on other networksnone
splitAn image beside a block of text and buttonsnone
statsA row of figures with a label each; optionally counts up once in viewa few lines for the count-up, no dependency
stepsAn ordered sequence of steps, as a list or a rownone
teamPortrait, name, role and bio of each personnone

Each component lives in components/<id>/:

  • <Name>.astro: the component. Variants use tailwind-variants, props are typed, and every optional prop also accepts undefined.
  • meta.json: its catalog entry. Props are Contentrain FieldDefs with a description; the entry also lists variants, slots, JavaScript, npm dependencies, sources (the builder elements it replaces) and accessibility notes.
  • fixtures.json: the visual-regression cases. Every variant option is covered.

components/_shared/ holds Section, Button, KitImage, measured.ts and the value types (ImageInput, LinkInput, ActionInput, NavItem, MeasuredStyle).

Measured style

A migration can hand a section the style it measured on the source page: measured: MeasuredStyle (the same fields as MeasuredStyle in @contentrain/types): the frame's width (containerPx), padding (padY, padX), the background (bg.color, bg.image with overlay, size, position), item columns at 390, 768 and 1280 px (the kit's base, md and lg; a missing 768 takes the smaller of 2 and the 1280 value, else the 390 value; a missing 1280 takes the 768 value, else the 390 value; a missing 390 is 1), the item gap, the text tone (dark = light text on a dark band; without it a fill's own lightness decides), where the heading and lead sit (align: start, center, end), the card radius and a minHeight.

Absent, a section takes the site's tokens as before. Present, it wins over the tone and columns variants. Section turns it into inline custom properties (--kit-cols-390/768/1280, --kit-gap, --radius-card, --container-page, --spacing-gutter) and the section's own padding, height and fill; a component's item grid reads them through measuredGrid(measured). Every value is checked first (components/_shared/measured.ts): a number out of range, a colour that is not hex, rgb(a), hsl(a), transparent, white or black (an overlay may also be a linear or radial gradient of such colours), an image address that is not http(s) or root-relative, or a position outside its keywords is dropped, never written into a style attribute.

Tokens

Components use colour roles and widths, never raw values. A site defines them in @theme (the starter already does): --color-surface, --color-surface-muted, --color-ink, --color-ink-muted, --color-line, --color-accent, --color-accent-ink, --color-accent-text, --color-accent-text-inverse, --font-sans, --container-prose, --container-page, --container-wide and --radius-card.

Text in the accent (an eyebrow, a category link) reads --color-accent-text, never --color-accent: an accent picked for fills can be too light for text on the page. The starter sets it to the accent; a site whose accent does not reach 4.5:1 on its surface sets a readable one. A dark section (tone="inverse") reads --color-accent-text-inverse in its place.

Quieter text (an intro, a caption, a role, a footer link) is a colour role, never opacity: dimmed text lays its colour over the band, and on a mid-tone band that falls under 4.5:1. It reads --color-ink-muted on a light band, --color-ink-muted-inverse on a dark one (the starter mixes the surface toward the ink; without it, the band's own text colour) and the fill's own ink on an accent or brand band. A light surface inside a band (a card, a form panel, a menu) is back on --color-ink-muted. The classes are in _shared/muted.ts.

Section hooks

Every section component renders its root with an id and data-kit-section="<component id>" (hero, card-grid, slider, …), so a site's theme or a design layer can style one kind of section, or one section, without touching the component. The id is the one the page gives, or the component id counted per page (hero, then hero-2), the same on every build.

A migrated site also carries its theme's type and shape, and components read these with a fallback to the kit's own values, so a site without them looks unchanged:

  • --font-weight-heading: section headings fall back to 700, item titles to 600.
  • --font-weight-body, --text-body, --leading-body and --leading-heading: the body and rich-text type. These are in the starter's CSS.
  • --radius-control: buttons and form controls.
  • --radius-image: images, which fall back to --radius-card.
  • --spacing-gutter: the page frame's side padding, which falls back to 1rem on phones and 2rem from md up.

The theme's type scale and rhythm are not read by components. The site's theme applies them to the kit's markers, and only when the site sets them:

  • --text-heading-1 to --text-heading-3: headings inside main.
  • --text-body: [data-kit-text], the lead and body paragraphs of the section components.
  • --text-nav: the header navigation, [data-cr-part="nav-header"].
  • --text-footer: the footer's text and links, [data-kit-footer] (the kit's own size is text-sm).
  • --spacing-section: the distance between two consecutive sections; each [data-kit-section] gets half of it as vertical padding, except where data-kit-spacing="none".
  • data-kit-brand (the site title in Header and Footer) and data-kit-tagline (Footer) take the theme's own sizes: the title from where it sits (body in the header, a heading in the footer), the tagline from its preset.

The full list is in catalog.json under tokens.

API

pnpm add -D @contentrain/astro-kit
import { copyComponents, KIT_COMPONENTS_DIR, loadCatalog, loadMapping, planCopy, rulesFor } from '@contentrain/astro-kit'

const catalog = await loadCatalog()
const plan = planCopy(catalog, ['header', 'card-grid']) // adds the components they render (nav, search-box), the shared files and the npm packages needed
await copyComponents(plan, KIT_COMPONENTS_DIR, '/path/to/site') // → src/components/kit/<id>/…
// install plan.dependencies in the site

const gutenberg = await loadMapping('gutenberg')
rulesFor(gutenberg, 'core/cover') // → the rule that turns a cover block into a hero, with its prop sources

validateCatalog, componentsForSource, validateMapping and unmappedSources check the catalog and the mapping tables against each other.

Mapping tables

mapping/<builder>.json (gutenberg, elementor, divi, classic) map builder elements to components, with a source for each prop from a small closed set of expressions (see src/mapping.ts). They are versioned, and an element no rule covers stays rich text (fallback: "prose"). When one rule matches an element, the outermost match owns its subtree. defaults lists attribute values a builder leaves out of its data while they are at their default (Elementor saves no video_type for a YouTube video); when.attr and attr: read through them (attrsOf).

Development

pnpm --filter @contentrain/astro-kit catalog   # regenerate catalog.json from meta.json files
pnpm --filter @contentrain/astro-kit test      # catalog, mapping and starter-copy checks
node packages/astro-kit/scripts/visual.mjs --local-sdk [--only <id>] [--update]

visual.mjs copies the starter and installs every component into it. It renders each fixture at /kit/<id>/, type-checking the fixtures against the component props, then runs astro check and a build. Last, it compares screenshots at 390, 768 and 1280 px with visual/<platform>/. The starter carries some kit components in src/components/kit/, and a test keeps those copies identical to the source here.

Part of the Contentrain ecosystem

Contentrain is a content governance ecosystem for teams and AI agents; agents work on the content through the MCP server. This package is one of the open-source tools (docs) and a building block for moving WordPress sites to Astro, which Migrate does as a paid service. Studio is the team surface for review and roles (and runs the forms behind contact-form); Bridge is a free WordPress plugin that exports a site as a Contentrain store.

License

MIT

版本与发布记录

@contentrain/astro-kit 共发布 103 个版本,首次发布于 2026/09/25;过去 12 个月发布了 103 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.50.9latest2026/11/055 天前
0.50.82026/11/046 天前
0.50.72026/11/046 天前
0.50.62026/10/3110 天前
0.50.52026/10/3110 天前
0.50.42026/10/3011 天前

关于 @contentrain/astro-kit 的常见问题

@contentrain/astro-kit 是什么?

Copy-in Astro components for Contentrain sites (shadcn model): typed props, tailwind-variants, zero JavaScript by default — with a machine-readable catalog

如何安装 @contentrain/astro-kit?

在项目目录运行 npm install @contentrain/astro-kit,或使用 pnpm add / yarn add / bun add。

@contentrain/astro-kit 支持 TypeScript 吗?

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

@contentrain/astro-kit 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@contentrain/astro-kit 可以商用吗?

@contentrain/astro-kit 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@contentrain/astro-kit 的下载量有多少?

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

@contentrain/astro-kit 还在维护吗?

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