src 结构调整, 添加 functions

This commit is contained in:
lutinglt
2025-06-24 20:31:12 +08:00
parent 9a070c5726
commit 711e01b66c
15 changed files with 136 additions and 68 deletions

1
src/core/index.ts Normal file
View File

@@ -0,0 +1 @@
export { createTheme } from "./theme";

48
src/core/theme.ts Normal file
View File

@@ -0,0 +1,48 @@
import { createGlobalTheme, globalStyle } from "@vanilla-extract/css";
import { otherThemeVars, themeVars } from "src/types/vars";
import type { MapLeafNodes, WithOptionalLayer } from "./types";
type Theme = WithOptionalLayer<MapLeafNodes<typeof themeVars, string>>;
function stringToBoolean(str: string, name: string): boolean {
try {
return JSON.parse(str);
} catch (error) {
console.error(error);
throw new Error(`Invalid boolean value(${name}): ${str}`);
}
}
/** 定义主题, 用于生成颜色主题
* @example
* 文件名: `color-dark.css.ts`
* import type { Primary } from "src/types";
* import { defineTheme, themeVars } from "src";
*
* const primary: Primary = {
* self: "#000000",
* contrast: themeVars.color.white,
* ...
* }
*
* export default defineTheme({
* isDarkTheme: "true",
* color: {
* primary,
* ...
* }
* })
*/
export const defineTheme = (theme: Theme) => theme;
export function createTheme(theme: Theme): void {
createGlobalTheme(":root", themeVars, theme);
createGlobalTheme(":root", otherThemeVars, {
border: {
radius: "6px",
},
});
globalStyle(":root", {
accentColor: themeVars.color.blue,
colorScheme: stringToBoolean(theme.isDarkTheme, "isDarkTheme") ? "dark" : "light",
});
}

View File

@@ -3,6 +3,14 @@ import fs from "node:fs";
import path from "node:path";
import type { Plugin } from "vite";
/**
*
* @param outDir vite outDir ,
* @param themeDir
* @param devTheme ,
* @param mode , dev `vite build --mode dev`
* @returns vite.rollupOptions.input
*/
export function themeInput(
outDir: string,
themeDir: string,
@@ -25,7 +33,7 @@ export function themeInput(
if (mode === "dev" && fileName !== devTheme) continue;
// 创建颜色主题的 css.ts 文件, vanilla-extract 需要这个文件后缀名并生成 css
const tmpCssTs = path.join(tmpDir, `${fileName}.css.ts`);
const createImport = `import { createTheme } from "src/theme";`;
const createImport = `import { createTheme } from "src/core";`;
const themeImport = `import theme from "themes/${fileName}";`;
const createFn = `createTheme(theme);`;
fs.writeFileSync(tmpCssTs, `${createImport}\n${themeImport}\n${createFn}`);
@@ -43,6 +51,10 @@ export function themeInput(
const prefix = "theme-github-";
/**
*
* @important vite.rollupOptions.output `assetFileNames: "[name].[ext]"`
*/
export function themePlugin(): Plugin {
return {
name: "themePlugin",

1
src/functions/index.ts Normal file
View File

@@ -0,0 +1 @@
export { scaleColorLight } from "./scss";

27
src/functions/scss.ts Normal file
View File

@@ -0,0 +1,27 @@
import { hsl, parseToHsl } from "polished";
/**
* 改变颜色的亮度, 等同于 sass 中的 `color.scale` 函数
* @param color 颜色值
* @param lightnessScale 亮度变化比例,负数表示变暗,正数表示变亮
* @returns 新的颜色值
* @example
* const newColor = scaleColorLight("#ff0000", 20); // 变亮
* const newColor = scaleColorLight("#ff0000", -20); // 变暗
* 等同于 sass `@use "sass:color"`;
* color: color.scale(#ff0000, $lightness: 20%)
* color: color.scale(#ff0000, $lightness: -20%)
*/
export function scaleColorLight(color: string, lightness: number) {
const hslColor = parseToHsl(color);
let newLightness;
if (lightness < 0) {
newLightness = hslColor.lightness * (1 + lightness / 100); // 变暗
} else {
newLightness = hslColor.lightness + (1 - hslColor.lightness) * (lightness / 100); // 变亮
}
newLightness = Math.min(1, Math.max(0, newLightness)); // 确保亮度值在 0 到 1 之间
return hsl(hslColor.hue, hslColor.saturation, newLightness);
}

View File

@@ -1,4 +1,3 @@
export * as color from "src/color";
export { defineTheme, themeVars } from "src/theme";
export { css } from "@linaria/core";
export { defineTheme } from "./core/theme";
export { themeVars } from "./types/vars";

View File

@@ -1,35 +0,0 @@
import { createGlobalTheme, createGlobalThemeContract, globalStyle } from "@vanilla-extract/css";
import type { MapLeafNodes, WithOptionalLayer } from "src/types";
import { varMapper, vars } from "src/vars";
function stringToBoolean(str: string, name: string): boolean {
try {
return JSON.parse(str);
} catch (error) {
console.error(error);
throw new Error(`Invalid boolean value(${name}): ${str}`);
}
}
const otherVars = {
border: {
radius: null,
},
};
const otherThemeVars = createGlobalThemeContract(otherVars, varMapper);
export const themeVars = createGlobalThemeContract(vars, varMapper);
export type Theme = WithOptionalLayer<MapLeafNodes<typeof themeVars, string>>;
export const defineTheme = (theme: Theme) => theme;
export function createTheme(theme: Theme): void {
createGlobalTheme(":root", themeVars, theme);
createGlobalTheme(":root", otherThemeVars, {
border: {
radius: "6px",
},
});
globalStyle(":root", {
accentColor: themeVars.color.blue,
colorScheme: stringToBoolean(theme.isDarkTheme, "isDarkTheme") ? "dark" : "light",
});
}

View File

@@ -1,5 +1,5 @@
import type { MapLeafNodes } from "src/types";
import { color } from "src/vars";
import type { MapLeafNodes } from "src/core/types";
import * as color from "./color";
export type Primary = MapLeafNodes<typeof color.primary, string>;
export type Secondary = MapLeafNodes<typeof color.secondary, string>;

29
src/types/vars.ts Normal file
View File

@@ -0,0 +1,29 @@
import { createGlobalThemeContract } from "@vanilla-extract/css";
import * as color from "./color";
export function varMapper(value: string | null, path: string[]) {
if (value === null) {
path = path.filter(item => item !== "self");
path = path.map(item => item.replace(/^num/, ""));
return path.join("-");
}
return value;
}
const vars = {
/** 用于标识当前是否为暗色主题: `"true"` 暗色 `"false"` 亮色 */
isDarkTheme: "is-dark-theme",
color: {
blue: null,
primary: color.primary,
},
};
const otherVars = {
border: {
radius: null,
},
};
export const themeVars = createGlobalThemeContract(vars, varMapper);
export const otherThemeVars = createGlobalThemeContract(otherVars, varMapper);

View File

@@ -1,21 +0,0 @@
import * as color from "src/vars/color";
export function varMapper(value: string | null, path: string[]) {
if (value === null) {
path = path.filter((item) => item !== "self");
path = path.map((item) => item.replace(/^num/, ""))
return path.join("-");
}
return value;
}
export const vars = {
/** 用于标识当前是否为暗色主题: `"true"` 暗色 `"false"` 亮色 */
isDarkTheme: "is-dark-theme",
color: {
blue: null,
primary: color.primary,
},
};
export { color };