diff --git a/packages/client/components.d.ts b/packages/client/components.d.ts
index dd1270d..613e14f 100644
--- a/packages/client/components.d.ts
+++ b/packages/client/components.d.ts
@@ -13,7 +13,6 @@ declare module 'vue' {
CookieDemo: typeof import('./src/components/CookieDemo.vue')['default']
DataFetch: typeof import('./src/components/DataFetch.vue')['default']
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
- MazBtn: typeof import('maz-ui/components/MazBtn')['default']
QuillEditor: typeof import('./src/components/QuillEditor/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
diff --git a/packages/client/package.json b/packages/client/package.json
index ad13702..aae169d 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -8,6 +8,7 @@
"check": "vue-tsc"
},
"devDependencies": {
+ "sass-embedded": "^1.93.2",
"unplugin-vue-components": "^29.1.0",
"vue-tsc": "^3.1.0"
},
diff --git a/packages/client/src/App.vue b/packages/client/src/App.vue
index 121ff3d..f32228a 100644
--- a/packages/client/src/App.vue
+++ b/packages/client/src/App.vue
@@ -10,5 +10,3 @@ onServerPrefetch(() => {
-
-
diff --git a/packages/client/src/assets/styles/scss/_global.scss b/packages/client/src/assets/styles/scss/_global.scss
new file mode 100644
index 0000000..5b4dac0
--- /dev/null
+++ b/packages/client/src/assets/styles/scss/_global.scss
@@ -0,0 +1,206 @@
+/*
+ theme-helpers.scss
+ 为主题开发提供的 SCSS 帮助函数 / mixin / 示例
+ 说明(中文注释):
+ - 提供把 SCSS map 转换为 CSS 自定义属性(variables)的 mixin
+ - 提供生成主题(light/dark)选择器的 mixin 示例
+ - 提供读取 CSS 变量的辅助函数 `css-var()`
+ - 提供颜色可读性判断函数 `readable-text()`(基于简单亮度公式)
+ - 提供颜色微调辅助 `tone()`
+
+ 使用方式:在你的主样式中导入此文件并调用 mixin/map。示例在文件底部有注释。
+*/
+
+// -----------------------------
+// CSS 变量相关帮助
+// -----------------------------
+
+// 返回一个 var(...) 字符串,方便在 SCSS 中使用 CSS 变量
+@function css-var($name, $fallback: null) {
+ @if $fallback == null {
+ @return unquote("var(--#{$name})");
+ } @else {
+ @return unquote("var(--#{$name}, #{$fallback})");
+ }
+}
+
+// 将一个 map 转换为 CSS 变量声明,需在选择器块内使用
+// 用法:
+// :root { @include declare-theme-variables($my-theme-map); }
+@mixin declare-theme-variables($map) {
+ @each $token, $val in $map {
+ // 允许传入颜色、字符串或数字
+ --#{$token}: #{$val};
+ }
+}
+
+// 生成主题选择器(selector 可以是 ":root"、":root[data-theme=\"dark\"]" 或 ".theme-dark")
+// 用法:@include generate-theme(':root', $theme-light);
+@mixin generate-theme($selector, $map) {
+ #{$selector} {
+ @include declare-theme-variables($map);
+ }
+}
+
+
+// -----------------------------
+// 颜色工具函数
+// -----------------------------
+
+// 计算近似亮度(0-255)用于对比判定(基于 ITU BT.601 近似)
+@function _luma($color) {
+ // 期望 $color 为 color 类型
+ $r: red($color);
+ $g: green($color);
+ $b: blue($color);
+ @return ($r * 0.299) + ($g * 0.587) + ($b * 0.114);
+}
+
+// 根据背景色返回可读的文字颜色(#000 或 #fff)
+// 示例: color: readable-text(#0d1117);
+@function readable-text($bg, $light: #ffffff, $dark: #000000) {
+ // 如果传入的不是 color 类型,尝试转换(如果是变量字符串则无法计算)
+ @if type-of($bg) != 'color' {
+ // 无法在构建时计算 CSS 变量的对比,默认返回白色以便在暗色环境下可读
+ @return $light;
+ }
+ @if _luma($bg) > 186 {
+ @return $dark;
+ }
+ @return $light;
+}
+
+// 基于 lighten/darken 的简单色调微调函数(正值变亮,负值变暗)
+@function tone($color, $percent) {
+ @if type-of($color) != 'color' {
+ @warn "tone(): first argument is not a color; returned value will be unchanged.";
+ @return $color;
+ }
+ @if $percent == 0 {
+ @return $color;
+ }
+ @if $percent > 0 {
+ @return lighten($color, $percent);
+ } @else {
+ @return darken($color, abs($percent));
+ }
+}
+
+// 使颜色变浅的辅助函数
+// 用法:
+// lighten-by(#0d1117, 20) -> 以 20% 变亮
+// lighten-by(#0d1117, 20%) -> 以 20% 变亮
+// lighten-by(#0d1117, 0.2) -> 以 20% 变亮(小数形式)
+@function lighten-by($color, $amount) {
+ @if type-of($color) != 'color' {
+ @warn "lighten-by(): first argument is not a color; returned value will be unchanged.";
+ @return $color;
+ }
+ @if type-of($amount) != 'number' {
+ @warn "lighten-by(): amount must be a number (e.g. 20, 20% or 0.2). Returning original color.";
+ @return $color;
+ }
+
+ // 规范化为百分比单位(Sass 的 percent 类型)
+ $pct: $amount;
+ @if unit($amount) != '%' {
+ // 无单位数字:如果在 (0,1] 范围内,视为小数比例;否则当作百分比数值
+ @if $amount > 0 and $amount <= 1 {
+ $pct: $amount * 100%;
+ } @else {
+ $pct: $amount * 1%;
+ }
+ }
+
+ @return lighten($color, $pct);
+}
+
+// -----------------------------
+// 常用组件/场景 mixin
+// -----------------------------
+
+// 简单的背景/文字组合,接收背景颜色或变量名
+// 用法:@include bg-fg('color-canvas-default'); // 传入变量名
+// @include bg-fg(#0d1117); // 传入 color 类型
+@mixin bg-fg($bg, $fg: null) {
+ @if type-of($bg) == 'string' {
+ // 假定传入的是变量名,使用 css-var
+ background: css-var($bg);
+ @if $fg == null {
+ // 无法静态计算对比,留空或用户自行指定
+ color: inherit;
+ } else {
+ color: css-var($fg);
+ }
+ } @else if type-of($bg) == 'color' {
+ background: $bg;
+ @if $fg == null {
+ color: readable-text($bg);
+ } @else if type-of($fg) == 'color' {
+ color: $fg;
+ } @else {
+ color: css-var($fg);
+ }
+ } @else {
+ @warn "bg-fg(): unsupported bg type";
+ }
+}
+
+// 一个可重用的按钮样式 mixin,支持传入变量名或颜色
+// 用法:
+// .btn { @include theme-button('color-accent-emphasis'); }
+@mixin theme-button($bg, $fg: null, $radius: 6px, $pad-y: 8px, $pad-x: 12px) {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: $pad-y $pad-x;
+ border-radius: $radius;
+ border: none;
+ cursor: pointer;
+ @if type-of($bg) == 'string' {
+ background: css-var($bg);
+ @if $fg == null { color: css-var('color-fg-default'); } @else { color: css-var($fg); }
+ } @else if type-of($bg) == 'color' {
+ background: $bg;
+ @if $fg == null { color: readable-text($bg); } @else if type-of($fg) == 'color' { color: $fg; } @else { color: css-var($fg); }
+ }
+ // 微交互
+ &:hover { filter: brightness(0.95); }
+ &:active { transform: translateY(1px); }
+}
+
+
+// -----------------------------
+// 示例(注释掉,直接拷贝到你的样式里使用)
+// -----------------------------
+
+// 示例主题 maps:键名与全局 CSS 变量中的命名保持一致(但不包含前缀 --)
+// $theme-light: (
+// 'color-fg-default': #24292f,
+// 'color-fg-muted': #57606a,
+// 'color-canvas-default': #ffffff,
+// 'color-border-default': #d0d7de,
+// 'color-accent-fg': #0969da,
+// );
+//
+// $theme-dark: (
+// 'color-fg-default': #c9d1d9,
+// 'color-fg-muted': #8b949e,
+// 'color-canvas-default': #0d1117,
+// 'color-border-default': #30363d,
+// 'color-accent-fg': #58a6ff,
+// );
+//
+// 生成到 :root 和手动切换器:
+// @include generate-theme(':root', $theme-light);
+// @include generate-theme(':root[data-theme="dark"]', $theme-dark);
+//
+// 使用 CSS 变量:
+// .markdown-body { color: css-var('color-fg-default'); background: css-var('color-canvas-default'); }
+//
+// 使用 mixin 快速为按钮应用主题颜色:
+// .btn { @include theme-button('color-accent-emphasis'); }
+
+// -----------------------------
+// 结束
+// -----------------------------
diff --git a/packages/client/src/assets/styles/scss/_theme-helpers.scss b/packages/client/src/assets/styles/scss/_theme-helpers.scss
new file mode 100644
index 0000000..19e3dcf
--- /dev/null
+++ b/packages/client/src/assets/styles/scss/_theme-helpers.scss
@@ -0,0 +1,190 @@
+
+// 返回一个 var(...) 字符串,方便在 SCSS 中使用 CSS 变量
+@function css-var($name, $fallback: null) {
+ @if $fallback == null {
+ @return unquote("var(--#{$name})");
+ } @else {
+ @return unquote("var(--#{$name}, #{$fallback})");
+ }
+}
+
+// 将一个 map 转换为 CSS 变量声明,需在选择器块内使用
+// 用法:
+// :root { @include declare-theme-variables($my-theme-map); }
+@mixin declare-theme-variables($map) {
+ @each $token, $val in $map {
+ // 允许传入颜色、字符串或数字
+ --#{$token}: #{$val};
+ }
+}
+
+// 生成主题选择器(selector 可以是 ":root"、":root[data-theme=\"dark\"]" 或 ".theme-dark")
+// 用法:@include generate-theme(':root', $theme-light);
+@mixin generate-theme($selector, $map) {
+ #{$selector} {
+ @include declare-theme-variables($map);
+ }
+}
+
+
+// -----------------------------
+// 颜色工具函数
+// -----------------------------
+
+// 计算近似亮度(0-255)用于对比判定(基于 ITU BT.601 近似)
+@function _luma($color) {
+ // 期望 $color 为 color 类型
+ $r: red($color);
+ $g: green($color);
+ $b: blue($color);
+ @return ($r * 0.299) + ($g * 0.587) + ($b * 0.114);
+}
+
+// 根据背景色返回可读的文字颜色(#000 或 #fff)
+// 示例: color: readable-text(#0d1117);
+@function readable-text($bg, $light: #ffffff, $dark: #000000) {
+ // 如果传入的不是 color 类型,尝试转换(如果是变量字符串则无法计算)
+ @if type-of($bg) != 'color' {
+ // 无法在构建时计算 CSS 变量的对比,默认返回白色以便在暗色环境下可读
+ @return $light;
+ }
+ @if _luma($bg) > 186 {
+ @return $dark;
+ }
+ @return $light;
+}
+
+// 基于 lighten/darken 的简单色调微调函数(正值变亮,负值变暗)
+@function tone($color, $percent) {
+ @if type-of($color) != 'color' {
+ @warn "tone(): first argument is not a color; returned value will be unchanged.";
+ @return $color;
+ }
+ @if $percent == 0 {
+ @return $color;
+ }
+ @if $percent > 0 {
+ @return lighten($color, $percent);
+ } @else {
+ @return darken($color, abs($percent));
+ }
+}
+
+// 使颜色变浅的辅助函数
+// 用法:
+// lighten-by(#0d1117, 20) -> 以 20% 变亮
+// lighten-by(#0d1117, 20%) -> 以 20% 变亮
+// lighten-by(#0d1117, 0.2) -> 以 20% 变亮(小数形式)
+@function lighten-by($color, $amount) {
+ @if type-of($color) != 'color' {
+ @warn "lighten-by(): first argument is not a color; returned value will be unchanged.";
+ @return $color;
+ }
+ @if type-of($amount) != 'number' {
+ @warn "lighten-by(): amount must be a number (e.g. 20, 20% or 0.2). Returning original color.";
+ @return $color;
+ }
+
+ // 规范化为百分比单位(Sass 的 percent 类型)
+ $pct: $amount;
+ @if unit($amount) != '%' {
+ // 无单位数字:如果在 (0,1] 范围内,视为小数比例;否则当作百分比数值
+ @if $amount > 0 and $amount <= 1 {
+ $pct: $amount * 100%;
+ } @else {
+ $pct: $amount * 1%;
+ }
+ }
+
+ @return lighten($color, $pct);
+}
+
+// -----------------------------
+// 常用组件/场景 mixin
+// -----------------------------
+
+// 简单的背景/文字组合,接收背景颜色或变量名
+// 用法:@include bg-fg('color-canvas-default'); // 传入变量名
+// @include bg-fg(#0d1117); // 传入 color 类型
+@mixin bg-fg($bg, $fg: null) {
+ @if type-of($bg) == 'string' {
+ // 假定传入的是变量名,使用 css-var
+ background: css-var($bg);
+ @if $fg == null {
+ // 无法静态计算对比,留空或用户自行指定
+ color: inherit;
+ } else {
+ color: css-var($fg);
+ }
+ } @else if type-of($bg) == 'color' {
+ background: $bg;
+ @if $fg == null {
+ color: readable-text($bg);
+ } @else if type-of($fg) == 'color' {
+ color: $fg;
+ } @else {
+ color: css-var($fg);
+ }
+ } @else {
+ @warn "bg-fg(): unsupported bg type";
+ }
+}
+
+// 一个可重用的按钮样式 mixin,支持传入变量名或颜色
+// 用法:
+// .btn { @include theme-button('color-accent-emphasis'); }
+@mixin theme-button($bg, $fg: null, $radius: 6px, $pad-y: 8px, $pad-x: 12px) {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: $pad-y $pad-x;
+ border-radius: $radius;
+ border: none;
+ cursor: pointer;
+ @if type-of($bg) == 'string' {
+ background: css-var($bg);
+ @if $fg == null { color: css-var('color-fg-default'); } @else { color: css-var($fg); }
+ } @else if type-of($bg) == 'color' {
+ background: $bg;
+ @if $fg == null { color: readable-text($bg); } @else if type-of($fg) == 'color' { color: $fg; } @else { color: css-var($fg); }
+ }
+ // 微交互
+ &:hover { filter: brightness(0.95); }
+ &:active { transform: translateY(1px); }
+}
+
+
+// -----------------------------
+// 示例(注释掉,直接拷贝到你的样式里使用)
+// -----------------------------
+
+// 示例主题 maps:键名与全局 CSS 变量中的命名保持一致(但不包含前缀 --)
+// $theme-light: (
+// 'color-fg-default': #24292f,
+// 'color-fg-muted': #57606a,
+// 'color-canvas-default': #ffffff,
+// 'color-border-default': #d0d7de,
+// 'color-accent-fg': #0969da,
+// );
+//
+// $theme-dark: (
+// 'color-fg-default': #c9d1d9,
+// 'color-fg-muted': #8b949e,
+// 'color-canvas-default': #0d1117,
+// 'color-border-default': #30363d,
+// 'color-accent-fg': #58a6ff,
+// );
+//
+// 生成到 :root 和手动切换器:
+// @include generate-theme(':root', $theme-light);
+// @include generate-theme(':root[data-theme="dark"]', $theme-dark);
+//
+// 使用 CSS 变量:
+// .markdown-body { color: css-var('color-fg-default'); background: css-var('color-canvas-default'); }
+//
+// 使用 mixin 快速为按钮应用主题颜色:
+// .btn { @include theme-button('color-accent-emphasis'); }
+
+// -----------------------------
+// 结束
+// -----------------------------
diff --git a/packages/client/src/assets/styles/scss/common.scss b/packages/client/src/assets/styles/scss/common.scss
new file mode 100644
index 0000000..c09dff8
--- /dev/null
+++ b/packages/client/src/assets/styles/scss/common.scss
@@ -0,0 +1,60 @@
+html,
+body {
+ height: 100%;
+}
+
+/* 全局主题变量(使用 _theme-helpers.scss 中的 mixin/map)
+ - 在 :root 中生成默认亮色主题变量
+ - 支持手动切换(data-theme="dark" / .theme-dark)
+ - 保留 prefers-color-scheme 媒体查询用于自动切换
+*/
+
+// 亮色主题变量 map(键不带 -- 前缀)
+$theme-light: (
+ "color-fg-default": #24292f,
+ "color-fg-muted": #57606a,
+ "color-fg-subtle": #6e7781,
+ "color-canvas-default": #ffffff,
+ "color-canvas-subtle": #f6f8fa,
+ "color-border-default": #d0d7de,
+ "color-border-muted": hsla(210, 18%, 87%, 1),
+ "color-neutral-muted": rgba(175, 184, 193, 0.2),
+ "color-accent-fg": #0969da,
+ "color-accent-emphasis": #0969da,
+ "color-attention-subtle": #fff8c5,
+ "color-danger-fg": #cf222e,
+ "color-mark-default": rgb(255, 255, 0),
+ "color-mark-fg": rgb(255, 187, 0),
+);
+
+// 暗色主题变量 map(对应亮色变量的语义)
+$theme-dark: (
+ "color-fg-default": #c9d1d9,
+ "color-fg-muted": #8b949e,
+ "color-fg-subtle": #6e7681,
+ "color-canvas-default": #0d1117,
+ "color-canvas-subtle": #010409,
+ "color-border-default": #30363d,
+ "color-border-muted": hsla(210, 18%, 20%, 1),
+ "color-neutral-muted": rgba(175, 184, 193, 0.12),
+ "color-accent-fg": #58a6ff,
+ "color-accent-emphasis": #2389ff,
+ "color-attention-subtle": rgba(255, 214, 10, 0.07),
+ "color-danger-fg": #ff7b72,
+ "color-mark-default": rgb(255, 214, 10),
+ "color-mark-fg": rgb(255, 165, 0),
+);
+
+// 在 :root 中生成默认(亮色)变量,便于组件直接使用 css var
+@include generate-theme(":root", $theme-light);
+
+// 手动主题切换支持:data-theme 或 class
+@include generate-theme(':root[data-theme="dark"]', $theme-dark);
+@include generate-theme(".theme-dark", $theme-dark);
+
+#app {
+ height: 100%;
+ background-color: css-var(color-canvas-default);
+ color: css-var(color-fg-default);
+ line-height: 1.2;
+}
diff --git a/packages/client/src/entry-client.ts b/packages/client/src/entry-client.ts
index 10f7d3d..5984435 100644
--- a/packages/client/src/entry-client.ts
+++ b/packages/client/src/entry-client.ts
@@ -5,6 +5,8 @@ import { createHead } from '@unhead/vue/client'
import "@/assets/styles/css/reset.css"
import 'vue-final-modal/style.css'
+import "@/assets/styles/scss/common.scss"
+
import { MazUi } from 'maz-ui/plugins/maz-ui'
import { mazUi, ocean, pristine, obsidian } from '@maz-ui/themes'
import { zhCN } from '@maz-ui/translations'
diff --git a/packages/client/src/pages/index.vue b/packages/client/src/pages/index.vue
index 42643a0..f7ce484 100644
--- a/packages/client/src/pages/index.vue
+++ b/packages/client/src/pages/index.vue
@@ -1,7 +1,3 @@
-
- Open Modal
-
-
+
+
+
+
safda
+
safda
+
safda
+
safda
+
sada
+
asd
+
+
+
+
diff --git a/packages/client/vite.config.ts b/packages/client/vite.config.ts
index e285888..f6862c2 100644
--- a/packages/client/vite.config.ts
+++ b/packages/client/vite.config.ts
@@ -31,6 +31,13 @@ export default defineConfig({
ssr: {
noExternal: process.env.NODE_ENV === 'development' ? ['vue-router'] : []
},
+ css: {
+ preprocessorOptions: {
+ "scss": {
+ additionalData: `@use "@/assets/styles/scss/_global.scss" as *;\n`
+ }
+ }
+ },
plugins: [
devtoolsJson(),
VueRouter({