| name | write-component-docs |
| description | Write bilingual (zh + en) documentation for any Vue component in the pixelium-design monorepo, following the project's VitePress doc template system. Use when asked to write or update docs for a component (e.g. "为 xxx 写文档", "write docs for xxx", "参照其他组件写文档"), or to add an example preview / API block / sidebar entry for a component. |
Write Pixelium Component Docs
This skill explains how to write documentation for any Vue component in the pixelium-design monorepo. It is distilled from the completed timeline doc work plus the patterns found across all existing component docs (button, tab, input, table, card, menu, dialog, drawer, etc.). Follow it to avoid the corrections the user repeatedly made during review.
1. System architecture (understand before editing)
- Component source:
packages/web-vue/lib/<component>/ — each component folder has type.ts (JSDoc-annotated prop/event/slot types), index.vue, index.less, and test/.
- Doc template source (EDIT THESE):
packages/document/template/ — *.md files plus example *.vue preview files, grouped in category folders: common/, data-input/, data-display/, layout/, navigation/, feedback/, base/, config/, fabulous-idea/, guide/.
- Reusable doc fragments:
packages/document/slice/ — every .md file in this folder is a reusable fragment referenced by [[[slice ...]]] blocks (e.g. percent.md, rest-attrs.md, emit-event.md, option.md, date-format.md, value-with-device-width.md).
- Generated output (DO NOT hand-edit):
packages/document/zh/ and packages/document/en/ — regenerated by the build script.
- Build script:
packages/document/script/gen-doc.mts; API resolver: packages/document/script/resolve-api.mts.
- Sidebar: auto-generated at runtime by
packages/document/.vitepress/dfs-4-md.ts. To register a NEW! badge or Chinese/English nav titles, edit packages/document/.vitepress/share.ts. Do NOT hand-edit sidebar files.
2. Step 1 — Read the component source
- Read
<component>/type.ts — the exported type names are what matter:
${CompName}Props, ${CompName}Events, ${CompName}Slots are auto-grouped by the resolver into 属性/类型/可选/默认值/描述/版本, 事件/参数/描述/版本, and 插槽/参数/描述/版本 tables.
- Read every prop/event/slot's JSDoc to write accurate descriptions.
- Read
<component>/index.vue to understand behavior and caveats (e.g. for timeline, the last item renders no connector line — never demonstrate line-variant on the last item).
- Check sibling sub-components (e.g.
timeline-item, tab-panel, collapse-item, grid-item) — each needs its own [[[api <name> ...]]] block.
- Determine the category folder by comparing with existing components (button→
common, tab→navigation, timeline→data-display, input→data-input, dialog→feedback, ...).
- Confirm the registered component names from the lib entry (
px- kebab-case in templates, e.g. px-timeline, px-timeline-item; PascalCase Timeline in prose).
3. Step 2 — Write the .md file
Create packages/document/template/<category>/<component>.md.
Language blocks
Wrap every prose section in language blocks:
[[[zh
## 标题
中文说明
]]]
[[[en
## English Heading
English explanation
]]]
The doc starts with an H1 in each language block (# Timeline), then a one-line description.
Preview blocks
<preview path="./xxx.vue"></preview>
Place one preview after each usage section. The referenced .vue file lives in the same template folder.
API blocks
Add ## API (NOT wrapped in language blocks) then:
## API
[[[api zh
propName: Description.
events.eventName: Description.
slots.slotName: Description.
exposeName.method: Description.
]]]
[[[api en
propName: Description.
events.eventName: Description.
slots.slotName: Description.
exposeName.method: Description.
]]]
[[[api <lang>]] with no component name resolves from the file basename (kebab-case) to ../web-vue/lib/<basename>/type.ts.
[[[api <sub-component> <lang>]] (e.g. [[[api timeline-item zh]]) resolves ../web-vue/lib/timeline-item/type.ts. The sub-component name is kebab-case.
- Description keys (how the resolver matches them to table rows):
- Props: the plain prop name (
direction), or optionally CompName.prop. Unmatched props render with an empty description cell.
- Events:
events.<event> (e.g. events.update:modelValue).
- Slots:
slots.<slot> (e.g. slots.default, slots.icon).
- Expose methods: plain key like
inputExpose.focus (no events./slots. prefix).
- List events/slots on their own lines; blank lines inside a block are fine (they're skipped).
- The build merges these descriptions with the JSDoc types/defaults from
type.ts into the final tables. You do NOT write types/defaults yourself.
Slice blocks
[[[slice <name>]]]
Every .md file in packages/document/slice/ is a reusable fragment (currently: percent, rest-attrs, emit-event, option, option-list, group-option, date-format, quick-access-option, value-with-device-width). The script reads ./slice/<name>.md. Prefer these over rewriting common explanations; if a shared concept is missing, add a new .md file there instead of inlining it.
API description rules (user-mandated)
- Descriptions describe ONLY the meaning of the property/event/slot — NO types, NO default values, NO code-related details.
- Refer to the component with its own PascalCase name (
Timeline, TimelineItem) when the word means the component — never lowercase, never the Chinese name — in BOTH zh and en blocks.
- zh example:
direction: Timeline 的排列方向。
- en example:
direction: The arrangement direction of Timeline.
- Slot wording example:
slots.icon: TimelineItem 节点处的图标。 / slots.icon: The icon at the node of TimelineItem.
Terminology rules (user-mandated)
- Use the canonical Chinese component name from
share.ts additionMapZh (e.g. "时间线", NOT "时间轴"). Verify, don't assume.
- In Chinese prose, refer to components by PascalCase component names (
Timeline, TimelineItem), not Chinese translations like 时间线/时间线项.
- In English prose, also use PascalCase (
Timeline, TimelineItem) where the word refers to the component.
- Prop names in prose: backticked camelCase (
theme, lineVariant, contentPlacement); in Vue templates use kebab-case (line-variant, content-placement, default-active).
- Use accurate component terminology for the concept (e.g. "自定义节点" not "自定义圆点").
- When describing component-exposed methods/props in prose, simply say the component "暴露 X 方法 / exposes X methods" — do NOT mention
ref (e.g. do NOT write "通过 ref 暴露", "exposes ... via ref"). The docs describe the component's API, not how it is accessed in a template.
4. Step 3 — Write example preview .vue files
Create one *.vue per usage section, referenced by <preview path="./xxx.vue"></preview>.
Required conventions (each is a user-mandated fix)
- No Chinese in code — all strings, comments, and values in
.vue files must be English.
- Use
px- prefix and kebab-case props in templates: <px-button>, <px-tab :default-active="'1'">, <px-timeline-item line-variant="dashed">.
- Icons: import from the icon package, do NOT hand-write glyphs:
<script setup lang="ts">
import { IconHome, IconCog, IconEnvelope } from '@pixelium/web-vue/icon-hn/es'
</script>
<!-- <IconHome></IconHome> inside the relevant #icon slot -->
(See tab-icon.vue for the reference pattern.)
- Fixed colors: use fixed hex colors, not CSS variables like
var(--px-color-warning) (those don't exist). Examples seen in the codebase: #409EFF, #FAE13C, #E956AE, #909399, #0960bd, #00b42a, #d97706, #ff7875, #86909c.
- Vary
theme across items when the component has a theme prop — don't leave everything default (primary, success, warning, info, danger, notice, sakura).
- Visual-caveat props (like
line-variant on a last item that renders no line): never put them on the last item; demonstrate on a middle item followed by a solid one.
- Make the section's feature obvious (e.g.
#icon slot shows <IconX>; #mark slot shows styled content).
- When possible reuse sibling layouts —
px-space wraps multiple items; for grouped sections keep consistent visual density.
5. Step 4 — Register in share.ts
In packages/document/.vitepress/share.ts:
- Add the component's kebab name to
newItems to show the NEW! badge (same format as existing entries, e.g. 'timeline'). Every newly added component MUST be put in the newItems list — this is a required step, not optional.
- Add
<component>: '<中文名>' to additionMapZh (e.g. timeline: '时间线'). Add an English title to additionMapEn/titleMapEn only if the auto-derived title is wrong.
order controls the display order of top-level categories (folder names, e.g. common, data-input, data-display, ...) and guideOrder controls the order of the guide sub-pages — only touch them when adding a brand-new category/guide page. Adding a component does NOT require editing them: within a category, component pages are simply ordered by the filesystem listing (alphabetical).
The sidebar itself is auto-generated — do NOT hand-edit it.
6. Step 5 — Verify the build
- Run
npm run build inside packages/document/ (runs gen-doc.mts) to regenerate zh//en/ and confirm the md/API/slice blocks resolve without errors.
- If the user previously declined a build, don't rerun it — just report that the generated folders hold stale content until a build runs.
- Note: the full VitePress build may fail on a PRE-EXISTING unrelated dependency issue (
parsnip-kit missing wait export). Don't chase it; it's not caused by doc edits.
7. Final self-check before presenting