添加 sass 预处理

This commit is contained in:
lutinglt
2025-06-24 13:52:03 +08:00
parent 77fe50a4cc
commit 9a070c5726
13 changed files with 201 additions and 90 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,3 @@
dist dist
node_modules node_modules
package-lock.json package-lock.json

View File

@@ -30,6 +30,7 @@
"eslint-plugin-react-refresh": "^0.4.20", "eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.2.0", "globals": "^16.2.0",
"lightningcss": "^1.30.1", "lightningcss": "^1.30.1",
"polished": "^4.3.1",
"prettier": "3.5.3", "prettier": "3.5.3",
"prettier-plugin-organize-imports": "^4.1.0", "prettier-plugin-organize-imports": "^4.1.0",
"react": "^19.1.0", "react": "^19.1.0",

View File

@@ -3,3 +3,4 @@ import { color } from "src/vars";
export type Primary = MapLeafNodes<typeof color.primary, string>; export type Primary = MapLeafNodes<typeof color.primary, string>;
export type Secondary = MapLeafNodes<typeof color.secondary, string>; export type Secondary = MapLeafNodes<typeof color.secondary, string>;
export type Self = MapLeafNodes<typeof color.self, string>;

View File

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

View File

@@ -11,12 +11,23 @@ function stringToBoolean(str: string, name: string): boolean {
} }
} }
const otherVars = {
border: {
radius: null,
},
};
const otherThemeVars = createGlobalThemeContract(otherVars, varMapper);
export const themeVars = createGlobalThemeContract(vars, varMapper); export const themeVars = createGlobalThemeContract(vars, varMapper);
export type Theme = WithOptionalLayer<MapLeafNodes<typeof themeVars, string>>; export type Theme = WithOptionalLayer<MapLeafNodes<typeof themeVars, string>>;
export const defineTheme = (theme: Theme) => theme; export const defineTheme = (theme: Theme) => theme;
export function createTheme(theme: Theme): void { export function createTheme(theme: Theme): void {
createGlobalTheme(":root", themeVars, theme); createGlobalTheme(":root", themeVars, theme);
createGlobalTheme(":root", otherThemeVars, {
border: {
radius: "6px",
},
});
globalStyle(":root", { globalStyle(":root", {
accentColor: themeVars.color.blue, accentColor: themeVars.color.blue,
colorScheme: stringToBoolean(theme.isDarkTheme, "isDarkTheme") ? "dark" : "light", colorScheme: stringToBoolean(theme.isDarkTheme, "isDarkTheme") ? "dark" : "light",

View File

@@ -1,23 +1,23 @@
const num = { const num = {
1: null, num1: null,
2: null, num2: null,
3: null, num3: null,
4: null, num4: null,
5: null, num5: null,
6: null, num6: null,
7: null, num7: null,
}; };
const alpha = { const alpha = {
10: null, num10: null,
20: null, num20: null,
30: null, num30: null,
40: null, num40: null,
50: null, num50: null,
60: null, num60: null,
70: null, num70: null,
80: null, num80: null,
90: null, num90: null,
}; };
export const primary = { export const primary = {
@@ -33,37 +33,108 @@ export const primary = {
export const secondary = { export const secondary = {
self: null, self: null,
dark: { dark: {
8: null, num8: null,
9: null, num9: null,
10: null, num10: null,
11: null, num11: null,
12: null, num12: null,
13: null, num13: null,
...num, ...num,
}, },
light: { light: {
1: null, num1: null,
2: null, num2: null,
3: null, num3: null,
4: null, num4: null,
}, },
alpha: alpha, alpha: alpha,
}; };
export const color = { const baseColor = {
red: null, self: null,
orange: null, light: null,
yellow: null, dark: {
olive: null, num1: null,
green: null, num2: null,
teal: null, },
blue: null, };
violet: null,
purple: null, export const self = {
pink: null, red: baseColor,
brown: null, orange: baseColor,
black: null, yellow: baseColor,
grey: null, olive: baseColor,
green: baseColor,
teal: baseColor,
blue: baseColor,
violet: baseColor,
purple: baseColor,
pink: baseColor,
brown: baseColor,
black: baseColor,
grey: {
self: null,
light: null,
},
gold: null, gold: null,
white: null, white: null,
}; };
const ansiColor = {
black: null,
red: null,
green: null,
yellow: null,
blue: null,
magenta: null,
cyan: null,
white: null,
};
export const ansi = {
bright: ansiColor,
...ansiColor,
};
export const console = {
fg: {
self: null,
subtle: null,
},
bg: null,
border: null,
active: {
bg: null,
},
hover: {
bg: null,
},
menu: {
bg: null,
border: null,
},
};
const row = {
bg: null,
border: null,
};
const line = {
linenum: {
bg: null,
},
row: row,
word: {
bg: null,
},
};
export const diff = {
added: line,
moved: {
row: row,
},
removed: line,
inactive: null,
};

View File

@@ -2,7 +2,8 @@ import * as color from "src/vars/color";
export function varMapper(value: string | null, path: string[]) { export function varMapper(value: string | null, path: string[]) {
if (value === null) { if (value === null) {
if (path.at(-1) === "self") return path.slice(0, -1).join("-"); path = path.filter((item) => item !== "self");
path = path.map((item) => item.replace(/^num/, ""))
return path.join("-"); return path.join("-");
} }
return value; return value;

View File

@@ -1,5 +1,6 @@
import fs from "fs"; import crypto from "node:crypto";
import path from "path"; import fs from "node:fs";
import path from "node:path";
import type { Plugin } from "vite"; import type { Plugin } from "vite";
export function themeInput( export function themeInput(
@@ -8,7 +9,9 @@ export function themeInput(
devTheme: string, devTheme: string,
mode: string mode: string
): { [key: string]: string } { ): { [key: string]: string } {
const tmpDir = `${outDir}/tmp`; // 输出目录下的临时目录 const hash = crypto.randomBytes(6).toString("hex");
const tmpDir = `${outDir}/tmp-${hash}`; // 输出目录下的临时目录
fs.mkdirSync(tmpDir, { recursive: true }); fs.mkdirSync(tmpDir, { recursive: true });
const input: { [key: string]: string } = {}; const input: { [key: string]: string } = {};

View File

@@ -1 +1,2 @@
import "styles/test"; import "styles/test";
import "styles/t1";

20
styles/t1.tsx Normal file
View File

@@ -0,0 +1,20 @@
import { css, themeVars } from "src";
export const setting_global = css`
.user-main-content,
.repo-setting-content,
.user-setting-content,
.org-setting-content,
.admin-setting-content {
.ui.right {
.ui.primary.button.tiny {
color: #fff;
background-color: #238636;
&:hover {
background-color: #29903b;
border-color: ${themeVars.color.primary.light.num1};
}
}
}
}
`;

View File

@@ -1,23 +1,15 @@
import { css } from "@linaria/core"; import { mix } from "polished";
import { themeVars } from "src/theme"; import { css, themeVars } from "src";
export const setting_global = css` export const setting_global = css`
:global() { .lines-num span:after {
.user-main-content, color: ${themeVars.color.primary.hover};
.repo-setting-content, }
.user-setting-content, .ui.cards > .card,
.org-setting-content, .ui.card {
.admin-setting-content { > .extra a:not(.ui):hover {
.ui.right { color: ${mix(0.1, "#fff", "#cc4848")};
.ui.primary.button.tiny { background-color: scale-color(#cc4848, $lightness: 10%);
color: #fff;
background-color: #238636;
&:hover {
background-color: #29903b;
border-color: ${themeVars.color.primary.light[1]};
}
}
}
} }
} }
`; `;

View File

@@ -1,36 +1,36 @@
import type { color } from "src"; import { color } from "src";
import { defineTheme, themeVars } from "src"; import { defineTheme, themeVars } from "src";
const dark = { const dark = {
1: "#739cb3", num1: "#739cb3",
2: "#40aaff", num2: "#40aaff",
3: "#92b4c4", num3: "#92b4c4",
4: "#a1bbcd", num4: "#a1bbcd",
5: "#cfddc1", num5: "#cfddc1",
6: "#e7eee0", num6: "#e7eee0",
7: "#f8faf6", num7: "#f8faf6",
}; };
const light = { const light = {
1: themeVars.color.blue, num1: themeVars.color.primary.self,
2: "#437aad", num2: "#437aad",
3: "#415b8b", num3: "#415b8b",
4: "#25425a", num4: "#25425a",
5: "#223546", num5: "#223546",
6: "#131923", num6: "#131923",
7: "#06090b", num7: "#06090b",
}; };
const alpha = { const alpha = {
10: "#3683c019", num10: "#3683c019",
20: "#3683c033", num20: "#3683c033",
30: "#3683c04b", num30: "#3683c04b",
40: "#3683c066", num40: "#3683c066",
50: "#3683c080", num50: "#3683c080",
60: "#3683c099", num60: "#3683c099",
70: "#3683c0b3", num70: "#3683c0b3",
80: "#3683c0cc", num80: "#3683c0cc",
90: "#3683c0e1", num90: "#3683c0e1",
}; };
const primary: color.Primary = { const primary: color.Primary = {
@@ -39,8 +39,8 @@ const primary: color.Primary = {
dark, dark,
light, light,
alpha, alpha,
hover: light[1], hover: light.num1,
active: light[2], active: light.num2,
}; };
export default defineTheme({ export default defineTheme({

View File

@@ -2,10 +2,14 @@ import { vanillaExtractPlugin } from "@vanilla-extract/vite-plugin";
import react from "@vitejs/plugin-react"; import react from "@vitejs/plugin-react";
import linaria from "@wyw-in-js/vite"; import linaria from "@wyw-in-js/vite";
import { Features } from "lightningcss"; import { Features } from "lightningcss";
import path from "path"; import { createRequire } from "node:module";
import path from "node:path";
import * as sass from "sass-embedded";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import { themeInput, themePlugin } from "./src/vite"; import { themeInput, themePlugin } from "./src/vite";
const require = createRequire(import.meta.url);
const devTheme = "dark"; // 开发模式仅打包单个颜色主题 const devTheme = "dark"; // 开发模式仅打包单个颜色主题
const outDir = "dist"; // 输出目录 const outDir = "dist"; // 输出目录
const themesDir = "themes"; // 颜色主题目录 const themesDir = "themes"; // 颜色主题目录
@@ -33,6 +37,10 @@ export default defineConfig(({ mode }) => {
babelOptions: { babelOptions: {
presets: ["@babel/preset-typescript", "@babel/preset-react"], presets: ["@babel/preset-typescript", "@babel/preset-react"],
}, },
preprocessor: (_selector, cssText) => sass.compileString(cssText).css, // 默认为全局样式并使用 sass-embedded 预处理 css
tagResolver: (source, tag) =>
// 识别从 src 导出的 css 标签,使用 @linaria/core/processors/css 处理
source === "src" && tag === "css" ? require.resolve("@linaria/core/processors/css") : null,
}), }),
react(), react(),
vanillaExtractPlugin(), vanillaExtractPlugin(),