vunor
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVunor
Vunor
Vunor is two things in one package:
- A UnoCSS design-system preset () that derives a complete theme — perceptual color palette, golden-ratio typography/spacing, layered backgrounds, font-aware margin correction — from a few mathematical knobs.
presetVunor - A Vue 3 component library of 30+ accessible components built on Reka UI, styled entirely through UnoCSS classes (zero CSS files, no scoped styles).
The two halves are independent: the preset works without the components, and the components are skinnable through the same shortcut system you'd use for your own code.
Vunor是一个集成了两大功能的包:
- UnoCSS设计系统预设():仅通过几个参数,即可生成完整主题——包含感知调色板、黄金比例排版/间距、分层背景、字体适配的边距修正。
presetVunor - Vue 3组件库:基于Reka UI构建的30+个无障碍组件,完全通过UnoCSS类实现样式(零CSS文件,无作用域样式)。
这两部分相互独立:预设可脱离组件单独使用,组件也可通过与自定义代码相同的快捷方式系统进行样式定制。
Mental model
心智模型
Three layers stack on top of each other. Read top-down to understand any class:
SEMANTIC CLASSES scope-primary, layer-0, surface-100, c8-filled, i8-filled, card
↓ expand to (UnoCSS shortcuts, deep-merged from defineShortcuts() objects)
LOW-LEVEL UTILITIES bg-current, current-bg-scope-color-500, h-fingertip, p-$m
↓ resolve to (UnoCSS rules from presetVunor)
CSS CUSTOM PROPERTIES --scope-color-500, --current-bg, --v-fingertip, --card-spacingEverything that paints, sizes, or themes flows through CSS variables. Set once high in the tree → every descendant , , etc. picks up the primary palette. Change on a subtree → that subtree turns red, no other classes change.
scope-primarybg-currentc8-filledsurface-100scope-error三层结构相互叠加。自上而下阅读即可理解各类的作用:
SEMANTIC CLASSES scope-primary, layer-0, surface-100, c8-filled, i8-filled, card
↓ expand to (UnoCSS shortcuts, deep-merged from defineShortcuts() objects)
LOW-LEVEL UTILITIES bg-current, current-bg-scope-color-500, h-fingertip, p-$m
↓ resolve to (UnoCSS rules from presetVunor)
CSS CUSTOM PROPERTIES --scope-color-500, --current-bg, --v-fingertip, --card-spacing所有涉及着色、尺寸或主题的内容均通过CSS变量传递。 在树形结构的高层设置 → 所有后代的、、等类都会继承主调色板。在子树上修改 → 该子树变为红色,无需修改其他类。
scope-primarybg-currentc8-filledsurface-100scope-errorRequired foundation: scope
必备基础:scope
scope-{name}scope-neutral:rootThe recommended pattern is to keep as the page default and only opt into a stronger scope on accent elements:
scope-neutral- Brand-colored interactive elements (primary buttons, focused inputs, active tabs, brand banners) → (or
scope-primaryfor an alternate accent).scope-secondary - State-bearing elements (error inputs, destructive buttons, validation messages) → . For warnings →
scope-error. For success →scope-warn.scope-good
That way the page chrome stays neutral and the eye is drawn to the elements that genuinely need attention.
html
<!-- Page-level scope is neutral (preflight default — no explicit class needed) -->
<body class="layer-0">
<header>…</header>
<!-- Brand accent: only the button opts into primary -->
<button class="scope-primary c8-filled">Save</button>
<!-- State change: same input, different scope = different visual weight -->
<VuInput v-model="email" :error="emailError" />
<!-- VuInput auto-applies scope-error internally when :error is set -->
<!-- Destructive action: opt into error scope explicitly -->
<button class="scope-error c8-flat">Delete account</button>
</body>Valid names: , , , , , , .
primarysecondarygoodwarnerrorgreyneutralscope-{name}:rootscope-neutral推荐模式:将作为页面默认值,仅在强调元素上启用更醒目的scope:
scope-neutral- 品牌色交互元素(主按钮、聚焦输入框、激活标签页、品牌横幅)→ (或
scope-primary作为备选强调色)。scope-secondary - 状态标识元素(错误输入框、破坏性按钮、验证消息)→ ;警告元素→
scope-error;成功元素→scope-warn。scope-good
这样页面框架保持中性,用户注意力会自然被吸引到真正需要关注的元素上。
html
<!-- 页面级scope为中性(预飞行默认值——无需显式添加类) -->
<body class="layer-0">
<header>…</header>
<!-- 品牌强调:仅按钮启用primary scope -->
<button class="scope-primary c8-filled">保存</button>
<!-- 状态切换:同一输入框,不同scope对应不同视觉权重 -->
<VuInput v-model="email" :error="emailError" />
<!-- 当:error为true时,VuInput会自动在内部应用scope-error -->
<!-- 破坏性操作:显式启用error scope -->
<button class="scope-error c8-flat">删除账户</button>
</body>有效名称:、、、、、、。
primarysecondarygoodwarnerrorgreyneutralQuick start
快速开始
ts
// uno.config.ts
import { defineConfig } from 'unocss'
import { presetVunor, vunorShortcuts } from 'vunor/theme'
export default defineConfig({
presets: [presetVunor({ palette: { colors: { primary: '#6B4EFF' } } })],
shortcuts: [vunorShortcuts()],
})ts
// vite.config.ts — add VunorVueResolver for auto-import of <VuFoo>
import Components from 'unplugin-vue-components/vite'
import { VunorVueResolver } from 'vunor/vite'
plugins: [vue(), UnoCSS(), Components({ resolvers: [VunorVueResolver] })]
// OR, for Nuxt 3
modules: ['vunor/nuxt']html
<!-- App.vue -->
<html class="scope-primary">
<body class="layer-0">
<VuCard level="h3">
<VuCardHeader>Hello</VuCardHeader>
<VuButton class="c8-filled">Save</VuButton>
</VuCard>
</body>
</html>See references/setup.md for the full setup.
ts
// uno.config.ts
import { defineConfig } from 'unocss'
import { presetVunor, vunorShortcuts } from 'vunor/theme'
export default defineConfig({
presets: [presetVunor({ palette: { colors: { primary: '#6B4EFF' } } })],
shortcuts: [vunorShortcuts()],
})ts
// vite.config.ts — 添加VunorVueResolver以自动导入<VuFoo>组件
import Components from 'unplugin-vue-components/vite'
import { VunorVueResolver } from 'vunor/vite'
plugins: [vue(), UnoCSS(), Components({ resolvers: [VunorVueResolver] })]
// 或者,针对Nuxt 3
modules: ['vunor/nuxt']html
<!-- App.vue -->
<html class="scope-primary">
<body class="layer-0">
<VuCard level="h3">
<VuCardHeader>你好</VuCardHeader>
<VuButton class="c8-filled">保存</VuButton>
</VuCard>
</body>
</html>完整设置请查看references/setup.md。
How to use this skill
如何使用此技能
Load only the reference file you need. Each file is self-contained.
| File | Load when... |
|---|---|
| references/setup.md | Installing Vunor, configuring Vite or Nuxt, listing package exports |
| references/colors.md | Using |
| references/theme.md | Tuning palette (vividness, saturation, flatness, layersDepth, lightest/darkest), defining custom surfaces, configuring fingertip, baseRadius, typography, animations |
| references/typography.md | Choosing typography utilities, using golden-ratio spacing tokens, applying |
| references/cards.md | Building cards: |
| references/shortcuts.md | Customizing or overriding component styles, understanding c8 (clickable) and i8 (input) systems, using |
| references/rules.md | Looking up a specific UnoCSS rule pattern provided by Vunor ( |
| references/components.md | Using non-form components: VuCard, VuButton, VuDialog, VuTabs, VuMenu, VuPopover, VuAppLayout, VuAppToasts, VuIcon, VuLoadingIndicator, VuPagination, VuProgressBar |
| references/forms.md | Using form components: VuInput, VuSelect, VuCombobox, VuCheckbox, VuRadioGroup, VuSlider, VuDatePicker |
仅加载所需的参考文件。每个文件都是独立的。
| 文件 | 加载时机 |
|---|---|
| references/setup.md | 安装Vunor、配置Vite或Nuxt、列出包导出内容时 |
| references/colors.md | 使用 |
| references/theme.md | 调优调色板(鲜艳度、饱和度、扁平化程度、分层深度、最亮/最暗值)、定义自定义surface、配置fingertip、baseRadius、排版、动画时 |
| references/typography.md | 选择排版工具类、使用黄金比例间距令牌、应用 |
| references/cards.md | 构建卡片: |
| references/shortcuts.md | 自定义或覆盖组件样式、理解c8(可点击)和i8(输入)系统、使用 |
| references/rules.md | 查找Vunor提供的特定UnoCSS规则模式( |
| references/components.md | 使用非表单组件:VuCard、VuButton、VuDialog、VuTabs、VuMenu、VuPopover、VuAppLayout、VuAppToasts、VuIcon、VuLoadingIndicator、VuPagination、VuProgressBar时 |
| references/forms.md | 使用表单组件:VuInput、VuSelect、VuCombobox、VuCheckbox、VuRadioGroup、VuSlider、VuDatePicker时 |
Quick reference
快速参考
ts
// Preset & shortcuts
import { presetVunor, vunorShortcuts, defineShortcuts,
mergeVunorShortcuts, toUnoShortcut } from 'vunor/theme'
import type { TVunorPaletteOptions, TVunorPaletteColor,
TVunorMainPaletteAdvanced, TVunorLayerPaletteAdvanced,
TVunorSurfaceConfig, TVunorTheme,
TVunorShortcut } from 'vunor/theme'
// PI composables (provide/inject)
import { useInputPi, useInputProps, useInputBaseProps,
useCardPI } from 'vunor'
import { useProvideInject } from 'vunor/utils'
// Vue / Nuxt integration
import { VunorVueResolver } from 'vunor/vite' // unplugin-vue-components resolver
// nuxt.config: modules: ['vunor/nuxt']
// Components (auto-imported when resolver/module is set up)
// <VuButton>, <VuCard>, <VuCardHeader>, <VuCardInner>, <VuDialog>, <VuTabs>,
// <VuMenu>, <VuMenuItem>, <VuPopover>, <VuAppLayout>, <VuAppToasts>,
// <VuIcon>, <VuLoadingIndicator>, <VuInnerLoading>, <VuLabel>, <VuPagination>,
// <VuProgressBar>, <VuOverflowContainer>, <VuCalendar>,
// <VuInput>, <VuInputBase>, <VuSelect>, <VuCombobox>, <VuCheckbox>,
// <VuRadioGroup>, <VuSlider>, <VuDatePicker>, <VuDevTools>ts
// 预设与快捷方式
import { presetVunor, vunorShortcuts, defineShortcuts,
mergeVunorShortcuts, toUnoShortcut } from 'vunor/theme'
import type { TVunorPaletteOptions, TVunorPaletteColor,
TVunorMainPaletteAdvanced, TVunorLayerPaletteAdvanced,
TVunorSurfaceConfig, TVunorTheme,
TVunorShortcut } from 'vunor/theme'
// PI组合式函数(provide/inject)
import { useInputPi, useInputProps, useInputBaseProps,
useCardPI } from 'vunor'
import { useProvideInject } from 'vunor/utils'
// Vue / Nuxt 集成
import { VunorVueResolver } from 'vunor/vite' // unplugin-vue-components 解析器
// nuxt.config: modules: ['vunor/nuxt']
// 组件(配置解析器/模块后自动导入)
// <VuButton>, <VuCard>, <VuCardHeader>, <VuCardInner>, <VuDialog>, <VuTabs>,
// <VuMenu>, <VuMenuItem>, <VuPopover>, <VuAppLayout>, <VuAppToasts>,
// <VuIcon>, <VuLoadingIndicator>, <VuInnerLoading>, <VuLabel>, <VuPagination>,
// <VuProgressBar>, <VuOverflowContainer>, <VuCalendar>,
// <VuInput>, <VuInputBase>, <VuSelect>, <VuCombobox>, <VuCheckbox>,
// <VuRadioGroup>, <VuSlider>, <VuDatePicker>, <VuDevTools>Cheatsheet of semantic classes
语义化类速查表
html
<!-- palette scope -->
<div class="scope-primary | scope-error | scope-good | scope-warn |
scope-secondary | scope-grey | scope-neutral">…</div>
<!-- depth backgrounds (auto light/dark) -->
<div class="layer-0">…</div> <!-- 0 outermost, 4 innermost -->
<!-- colored blocks (semantic background+text+border bundle) -->
<div class="surface-0">…</div> <!-- = layer-0 -->
<div class="surface-50 | surface-100 | … | surface-900">…</div>
<!-- direct CSS-var painting -->
<div class="current-bg-scope-color-500 current-text-white">
<span class="bg-current text-current">…</span>
</div>
<div class="bg-scope-color-500/50 text-scope-light-1">…</div>
<!-- clickable styles -->
<button class="c8-filled | c8-flat | c8-outlined | c8-light | c8-chrome">…</button>
<!-- c8-chrome stays neutral inside any scope (use for Cancel / Select all / None
buttons sitting next to a scoped primary CTA) -->
<!-- input styles -->
<div class="i8 i8-filled | i8-flat | i8-round">…</div>
<!-- card -->
<VuCard level="h3" rounded dense>…</VuCard>
<!-- spacing & typography -->
<p class="text-h1 text-mb-$m">Title</p> <!-- font-aware margin -->
<div class="p-$m gap-$s h-fingertip rounded-base">…</div>html
<!-- 调色板scope -->
<div class="scope-primary | scope-error | scope-good | scope-warn |
scope-secondary | scope-grey | scope-neutral">…</div>
<!-- 分层背景(自动适配明暗模式) -->
<div class="layer-0">…</div> <!-- 0为最外层,4为最内层 -->
<!-- 彩色块(语义化背景+文本+边框组合) -->
<div class="surface-0">…</div> <!-- 等同于layer-0 -->
<div class="surface-50 | surface-100 | … | surface-900">…</div>
<!-- 直接使用CSS变量着色 -->
<div class="current-bg-scope-color-500 current-text-white">
<span class="bg-current text-current">…</span>
</div>
<div class="bg-scope-color-500/50 text-scope-light-1">…</div>
<!-- 可点击样式 -->
<button class="c8-filled | c8-flat | c8-outlined | c8-light | c8-chrome">…</button>
<!-- c8-chrome在任何scope内都保持中性(适用于与带scope的主操作按钮相邻的取消/全选/全不选按钮) -->
<!-- 输入样式 -->
<div class="i8 i8-filled | i8-flat | i8-round">…</div>
<!-- 卡片 -->
<VuCard level="h3" rounded dense>…</VuCard>
<!-- 间距与排版 -->
<p class="text-h1 text-mb-$m">标题</p> <!-- 字体适配边距 -->
<div class="p-$m gap-$s h-fingertip rounded-base">…</div>Ground rules
基本原则
- Manage color through , not hard-coded palette names. The page chrome stays neutral by default (
scope-*is preflight-installed onscope-neutral). Apply:root(orscope-primary) only on accent elements — primary buttons, focused inputs, brand banners. To reflect state, switch toscope-secondaryfor negatives/destructive actions,scope-errorfor warnings,scope-warnfor success.scope-good - Inside components, prefer scope-relative classes over fixed colors. Reach for ,
bg-current,text-current,border-current,text-current-hl, orbg-current/10— notbg-scope-color-500. That way the same component re-tints automatically when its parent scope changes (bg-primary-500works in any scope;<button class="c8-filled">does not). Use specific palette colors (<button class="bg-primary-500">,bg-primary-500) only when you genuinely need a scope-independent color.text-error-700 - Don't write blocks or scoped styles. Compose UnoCSS utilities and Vunor shortcuts. To customize component appearance, override its shortcut via
<style>— see references/shortcuts.md.vunorShortcuts(myOverrides) - Layers and surfaces handle dark mode for you — they read in light mode and
--scope-light-*under--scope-dark-*/.dark. Don't addprefers-color-scheme: darkprefixes to layer/surface utilities.dark: - Spacing tokens use a prefix:
$,p-$m,gap-$s. Plainm-$lis a different (built-in UnoCSS) utility.p-m - Touch targets default to (3em). Buttons/inputs use
--v-fingertip; override per-subtree withh-fingertip.fingertip-xs|s|m|l|xl - only sets variables. It paints nothing on its own — combine with
scope-{name},bg-current,layer-*,surface-*,c8-*, etc.i8-*
- 通过管理颜色,而非硬编码调色板名称。 页面框架默认保持中性(
scope-*已通过预飞行样式添加到scope-neutral)。仅在强调元素上应用:root(或scope-primary)——如主按钮、聚焦输入框、品牌横幅。要体现状态,针对负面/破坏性操作切换为scope-secondary,警告切换为scope-error,成功切换为scope-warn。scope-good - 在组件内部,优先使用与scope关联的类,而非固定颜色。 选择、
bg-current、text-current、border-current、text-current-hl或bg-current/10——而非bg-scope-color-500。这样当父级scope变化时,同一组件会自动重新着色(bg-primary-500可在任意scope中生效;<button class="c8-filled">则不行)。仅在确实需要与scope无关的颜色时,才使用特定调色板颜色(如<button class="bg-primary-500">、bg-primary-500)。text-error-700 - 不要编写块或作用域样式。 组合UnoCSS工具类和Vunor快捷方式。如需自定义组件外观,可通过
<style>覆盖其快捷方式——详见references/shortcuts.md。vunorShortcuts(myOverrides) - Layers和surfaces会自动处理暗色模式——它们在亮色模式下读取,在
--scope-light-*/.dark下读取prefers-color-scheme: dark。无需为layer/surface工具类添加--scope-dark-*前缀。dark: - 间距令牌使用前缀:
$、p-$m、gap-$s。普通的m-$l是另一个(UnoCSS内置的)工具类。p-m - 触摸目标默认大小为(3em)。 按钮/输入框使用
--v-fingertip;可通过h-fingertip在子树级别覆盖。fingertip-xs|s|m|l|xl - 仅设置变量。 自身不会产生任何样式——需与
scope-{name}、bg-current、layer-*、surface-*、c8-*等类组合使用。i8-*