关于 vunor
vunor 是面向 Vue 3 界面开发者的 UnoCSS 主题预设与组件库。它通过 CSS 变量作用域和快捷方式系统,让主题配置与组件样式保持一致,并支持分别使用两部分。
主要功能
- 01UnoCSS 主题预设
- 02Vue 3 组件库
- 03调色板与间距令牌
- 04基于作用域的主题变量
- 05基于快捷方式的组件样式
- 06基于 Reka UI 的无障碍组件
适用场景
- 01为 Vue 界面创建统一主题
- 02为指定子树应用状态颜色
- 03通过快捷方式自定义组件样式
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mav-rik/ vunor --skill vunor安装后在 Claude Code 中输入/vunor确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/cards.mdcolors.mdcomponents.mdforms.mdrules.mdsetup.mdshortcuts.mdtheme.mdtypography.md详细介绍
Vunor
Vunor 在一个包中包含两部分:
- UnoCSS 设计系统预设(
presetVunor),通过少量数学参数生成完整主题,包括感知色彩调色板、黄金比例排版与间距、分层背景,以及适配字体的外边距修正。 - Vue 3 组件库,包含 30 多个基于 Reka UI 构建的无障碍组件,完全通过 UnoCSS 类设置样式(零 CSS 文件,无作用域样式)。
这两部分相互独立:预设无需组件即可使用,而组件也可通过你为自己的代码使用的同一套快捷方式系统来定制外观。
心智模型
三个层层叠加的层。自上而下阅读,即可理解任意类:
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-primary → 所有后代的 bg-current、c8-filled、surface-100 等都会应用主色调色板。在子树上更改 scope-error → 该子树会变为红色,其他类不受影响。
必备基础:scope
scope-{name} 声明子树中启用的调色板。如果没有启用的 scope,感知颜色的类就没有可渲染的值。 Vunor 的预检会自动在 :root 上安装 scope-neutral,因此开箱即用,界面中不显眼的部分(默认边框、层级背景、闲置状态的文本和图标)都会呈现平和的中性色调。
推荐的做法是将 scope-neutral 作为页面默认值,只在强调元素上选择更鲜明的 scope:
- 品牌色交互元素(主按钮、聚焦的输入框、活动标签页、品牌横幅)→
scope-primary(或使用scope-secondary作为另一种强调色)。 - 表示状态的元素(错误输入框、破坏性按钮、验证消息)→
scope-error。警告使用scope-warn,成功使用scope-good。
这样页面主体保持中性,用户的注意力也会被引导到真正需要关注的元素上。
<body class="layer-0">
<header>…</header>
<button class="scope-primary c8-filled">Save</button>
<VuInput v-model="email" :error="emailError" />
<button class="scope-error c8-flat">Delete account</button>
</body>
有效名称:primary、secondary、good、warn、error、grey、neutral。
快速开始
// uno.config.ts
import { defineConfig } from 'unocss'
import { presetVunor, vunorShortcuts } from 'vunor/theme'
export default defineConfig({
presets: [presetVunor({ palette: { colors: { primary: '#6B4EFF' } } })],
shortcuts: [vunorShortcuts()],
})
// 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 class="scope-primary">
<body class="layer-0">
<VuCard level="h3">
<VuCardHeader>Hello</VuCardHeader>
<VuButton class="c8-filled">Save</VuButton>
</VuCard>
</body>
</html>
完整设置说明请参阅 references/setup.md。
如何使用此技能
只加载所需的参考文件。每个文件都可以独立使用。
| 文件 | 在以下情况下加载…… |
|---|---|
| references/setup.md | 安装 Vunor、配置 Vite 或 Nuxt、查看包导出列表 |
| references/colors.md | 使用 scope-*、layer-*、surface-*、current-*、bg-current;了解浅色/深色模式行为 |
| references/theme.md | 调整调色板(鲜艳度、饱和度、扁平度、layersDepth、lightest/darkest)、定义自定义表面、配置 fingertip、baseRadius、排版和动画 |
| references/typography.md | 选择排版工具类、使用黄金比例间距令牌、应用 text-mt-* / text-mb-* 外边距修正、使用 fingertip-* 设置触控目标尺寸 |
| references/cards.md | 构建卡片:<VuCard>、card 快捷方式、card-{level} 规则、--card-spacing、密度、圆角、标题层级 |
| references/shortcuts.md | 自定义或覆盖组件样式、了解 c8(可点击)和 i8(输入)系统、使用 defineShortcuts / mergeVunorShortcuts / vunorShortcuts |
| references/rules.md | 查找 Vunor 提供的特定 UnoCSS 规则模式(scope-*、current-*、card-*、fingertip-*、i8-*、icon-*、text-m*-*) |
| 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 |
快速参考
// 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>
语义类速查表
<div class="scope-primary | scope-error | scope-good | scope-warn |
scope-secondary | scope-grey | scope-neutral">…</div>
<div class="layer-0">…</div>
<div class="surface-0">…</div>
<div class="surface-50 | surface-100 | … | surface-900">…</div>
<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>
<span class="text-current">primary</span>
<span class="text-current-muted">secondary / placeholder weight</span>
<span class="text-current-hl">accent (scope-color-500)</span>
<button class="border-current hover:border-current-hover hover:bg-current-hover">hover-step</button>
<button class="c8-filled | c8-flat | c8-outlined | c8-light | c8-chrome">…</button>
<div class="i8 i8-filled | i8-flat | i8-round">…</div>
<button class="scope-primary c8-filled btn">Save</button>
<button class="c8-flat btn btn-square"><span class="i--x btn-icon"/></button>
<input class="i8-bare h-fingertip-m px-$m" />
<div class="popup-card w-[14em]">
<button class="menu-item">Row</button>
</div>
<button class="disabled-soft" aria-disabled="true">…</button>
<VuCard level="h3" rounded dense>…</VuCard>
<p class="text-h1 text-mb-$m">Title</p>
<div class="p-$m gap-$s h-fingertip rounded-base">…</div>
基本原则
- 通过
scope-*管理颜色,而不是使用硬编码的调色板名称。 页面框架默认保持中性(:root上预先安装了scope-neutral)。仅在强调元素上应用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,而不是bg-primary-500。这样,父级 scope 变化时,同一组件会自动调整色调(<button class="c8-filled">在任何 scope 中都能正常工作;<button class="bg-primary-500">则不能)。只有确实需要不受 scope 影响的颜色时,才使用特定调色板颜色(bg-primary-500、text-error-700)。 - 不要编写
<style>块或 scoped 样式。 组合使用 UnoCSS 工具类和 Vunor 快捷类。要自定义组件外观,请通过vunorShortcuts(myOverrides)覆盖其快捷类,参见 references/shortcuts.md。 - 图层和表面会为你处理深色模式——浅色模式下读取
--scope-light-*,在.dark/prefers-color-scheme: dark下读取--scope-dark-*。不要给图层/表面工具类添加dark:前缀。 - 间距令牌使用
$前缀:p-$m、gap-$s、m-$l。普通的p-m是不同的(内置 UnoCSS)工具类。 - 触控目标默认使用
--v-fingertip(3em)。 按钮/输入框使用h-fingertip;可通过fingertip-xs|s|m|l|xl按子树覆盖。 scope-{name}只设置变量。 它本身不会绘制任何内容——需与bg-current、layer-*、surface-*、c8-*、i8-*等组合使用。
评论
支持 Markdown