颜色变量计算&颜色主题迁移

This commit is contained in:
lutinglt
2025-06-27 22:55:59 +08:00
parent 16298f2b11
commit 5ae1f2f634
14 changed files with 514 additions and 412 deletions

324
src/core/color.ts Normal file
View File

@@ -0,0 +1,324 @@
import { rgba } from "polished";
import { scaleColorLight } from "src/functions";
import type { Ansi, Based, Console, Diff, Message, Named, Primary, Secondary } from "src/types";
import { themeVars } from "src/types/vars";
import type { Theme } from "./theme";
interface ColorTheme {
isDarkTheme: boolean;
primary: string;
primaryContrast: string;
secondary: string;
red: string;
orange: string;
yellow: string;
olive: string;
green: string;
teal: string;
blue: string;
violet: string;
purple: string;
pink: string;
brown: string;
black: string;
grey: string;
gold: string;
white: string;
console: Console;
diff: Diff;
based: Based;
}
/** 定义颜色, 用于生成颜色主题
* @example
* 文件名: `color-dark.css.ts`
* import type { Primary } from "src/types";
* import { defineTheme, themeVars } from "src";
*
* const primary: Primary = {
* self: "#ffffff",
* contrast: themeVars.color.white,
* ...
* }
*
* export default defineTheme({
* isDarkTheme: "true",
* color: {
* primary,
* ...
* }
* })
*/
export function defineTheme(theme: ColorTheme): Theme {
const lighten = theme.isDarkTheme ? -1 : 1;
const primary: Primary = {
self: theme.primary,
contrast: theme.primaryContrast,
dark: {
num1: scaleColorLight(theme.primary, -3 * lighten),
num2: scaleColorLight(theme.primary, -6 * lighten),
num3: scaleColorLight(theme.primary, -9 * lighten),
num4: scaleColorLight(theme.primary, -12 * lighten),
num5: scaleColorLight(theme.primary, -15 * lighten),
num6: scaleColorLight(theme.primary, -18 * lighten),
num7: scaleColorLight(theme.primary, -21 * lighten),
},
light: {
num1: scaleColorLight(theme.primary, 3 * lighten),
num2: scaleColorLight(theme.primary, 6 * lighten),
num3: scaleColorLight(theme.primary, 9 * lighten),
num4: scaleColorLight(theme.primary, 12 * lighten),
num5: scaleColorLight(theme.primary, 15 * lighten),
num6: scaleColorLight(theme.primary, 18 * lighten),
num7: scaleColorLight(theme.primary, 21 * lighten),
},
alpha: {
num10: rgba(theme.primary, 0.1),
num20: rgba(theme.primary, 0.2),
num30: rgba(theme.primary, 0.3),
num40: rgba(theme.primary, 0.4),
num50: rgba(theme.primary, 0.5),
num60: rgba(theme.primary, 0.6),
num70: rgba(theme.primary, 0.7),
num80: rgba(theme.primary, 0.8),
num90: rgba(theme.primary, 0.9),
},
hover: theme.isDarkTheme ? themeVars.color.primary.light.num1 : themeVars.color.primary.dark.num1,
active: theme.isDarkTheme ? themeVars.color.primary.light.num2 : themeVars.color.primary.dark.num2,
};
const secondary: Secondary = {
self: theme.secondary,
dark: {
num1: scaleColorLight(theme.secondary, -3 * lighten),
num2: scaleColorLight(theme.secondary, -6 * lighten),
num3: scaleColorLight(theme.secondary, -9 * lighten),
num4: scaleColorLight(theme.secondary, -12 * lighten),
num5: scaleColorLight(theme.secondary, -15 * lighten),
num6: scaleColorLight(theme.secondary, -18 * lighten),
num7: scaleColorLight(theme.secondary, -21 * lighten),
num8: scaleColorLight(theme.secondary, -24 * lighten),
num9: scaleColorLight(theme.secondary, -27 * lighten),
num10: scaleColorLight(theme.secondary, -30 * lighten),
num11: scaleColorLight(theme.secondary, -33 * lighten),
num12: scaleColorLight(theme.secondary, -36 * lighten),
num13: scaleColorLight(theme.secondary, -39 * lighten),
},
light: {
num1: scaleColorLight(theme.secondary, 3 * lighten),
num2: scaleColorLight(theme.secondary, 6 * lighten),
num3: scaleColorLight(theme.secondary, 9 * lighten),
num4: scaleColorLight(theme.secondary, 12 * lighten),
},
alpha: {
num10: rgba(theme.secondary, 0.1),
num20: rgba(theme.secondary, 0.2),
num30: rgba(theme.secondary, 0.3),
num40: rgba(theme.secondary, 0.4),
num50: rgba(theme.secondary, 0.5),
num60: rgba(theme.secondary, 0.6),
num70: rgba(theme.secondary, 0.7),
num80: rgba(theme.secondary, 0.8),
num90: rgba(theme.secondary, 0.9),
},
button: themeVars.color.secondary.dark.num4,
hover: theme.isDarkTheme ? themeVars.color.secondary.dark.num3 : themeVars.color.secondary.dark.num5,
active: theme.isDarkTheme ? themeVars.color.secondary.dark.num2 : themeVars.color.secondary.dark.num6,
};
const named: Named = {
red: {
self: theme.red,
light: theme.isDarkTheme ? scaleColorLight(theme.red, 10) : scaleColorLight(theme.red, 25),
dark: {
num1: scaleColorLight(theme.red, -10),
num2: scaleColorLight(theme.red, -20),
},
badge: {
self: theme.red,
bg: rgba(theme.red, 0.1),
hover: {
bg: rgba(theme.red, 0.3),
},
},
},
orange: {
self: theme.orange,
light: theme.isDarkTheme ? scaleColorLight(theme.orange, 10) : scaleColorLight(theme.orange, 25),
dark: {
num1: scaleColorLight(theme.orange, -10),
num2: scaleColorLight(theme.orange, -20),
},
badge: {
self: theme.orange,
bg: rgba(theme.orange, 0.1),
hover: {
bg: rgba(theme.orange, 0.3),
},
},
},
yellow: {
self: theme.yellow,
light: theme.isDarkTheme ? scaleColorLight(theme.yellow, 10) : scaleColorLight(theme.yellow, 25),
dark: {
num1: scaleColorLight(theme.yellow, -10),
num2: scaleColorLight(theme.yellow, -20),
},
badge: {
self: theme.yellow,
bg: rgba(theme.yellow, 0.1),
hover: {
bg: rgba(theme.yellow, 0.3),
},
},
},
olive: {
self: theme.olive,
light: theme.isDarkTheme ? scaleColorLight(theme.olive, 10) : scaleColorLight(theme.olive, 25),
dark: {
num1: scaleColorLight(theme.olive, -10),
num2: scaleColorLight(theme.olive, -20),
},
},
green: {
self: theme.green,
light: theme.isDarkTheme ? scaleColorLight(theme.green, 10) : scaleColorLight(theme.green, 25),
dark: {
num1: scaleColorLight(theme.green, -10),
num2: scaleColorLight(theme.green, -20),
},
badge: {
self: theme.green,
bg: rgba(theme.green, 0.1),
hover: {
bg: rgba(theme.green, 0.3),
},
},
},
teal: {
self: theme.teal,
light: theme.isDarkTheme ? scaleColorLight(theme.teal, 10) : scaleColorLight(theme.teal, 25),
dark: {
num1: scaleColorLight(theme.teal, -10),
num2: scaleColorLight(theme.teal, -20),
},
},
blue: {
self: theme.blue,
light: theme.isDarkTheme ? scaleColorLight(theme.blue, 10) : scaleColorLight(theme.blue, 25),
dark: {
num1: scaleColorLight(theme.blue, -10),
num2: scaleColorLight(theme.blue, -20),
},
},
violet: {
self: theme.violet,
light: theme.isDarkTheme ? scaleColorLight(theme.violet, 10) : scaleColorLight(theme.violet, 25),
dark: {
num1: scaleColorLight(theme.violet, -10),
num2: scaleColorLight(theme.violet, -20),
},
},
purple: {
self: theme.purple,
light: theme.isDarkTheme ? scaleColorLight(theme.purple, 10) : scaleColorLight(theme.purple, 25),
dark: {
num1: scaleColorLight(theme.purple, -10),
num2: scaleColorLight(theme.purple, -20),
},
},
pink: {
self: theme.pink,
light: theme.isDarkTheme ? scaleColorLight(theme.pink, 10) : scaleColorLight(theme.pink, 25),
dark: {
num1: scaleColorLight(theme.pink, -10),
num2: scaleColorLight(theme.pink, -20),
},
},
brown: {
self: theme.brown,
light: theme.isDarkTheme ? scaleColorLight(theme.brown, 10) : scaleColorLight(theme.brown, 25),
dark: {
num1: scaleColorLight(theme.brown, -10),
num2: scaleColorLight(theme.brown, -20),
},
},
black: {
self: theme.black,
light: theme.isDarkTheme ? scaleColorLight(theme.black, 10) : scaleColorLight(theme.black, 25),
dark: {
num1: scaleColorLight(theme.black, -10),
num2: scaleColorLight(theme.black, -20),
},
},
grey: {
self: theme.grey,
light: theme.isDarkTheme ? scaleColorLight(theme.grey, 10) : scaleColorLight(theme.grey, 25),
},
gold: theme.gold,
white: theme.white,
};
const message: Message = {
error: {
bg: {
self: rgba(theme.red, 0.1),
active: rgba(theme.red, 0.5),
hover: rgba(theme.red, 0.3),
},
border: scaleColorLight(theme.red, 30 * lighten),
text: theme.red,
},
success: {
bg: rgba(theme.green, 0.1),
border: scaleColorLight(theme.green, 30 * lighten),
text: theme.green,
},
warning: {
bg: rgba(theme.yellow, 0.1),
border: scaleColorLight(theme.yellow, 30 * lighten),
text: theme.yellow,
},
info: {
bg: rgba(theme.blue, 0.1),
border: scaleColorLight(theme.blue, 30 * lighten),
text: theme.blue,
},
};
const ansi: Ansi = {
black: themeVars.color.black.self,
red: themeVars.color.red.self,
green: themeVars.color.green.self,
yellow: themeVars.color.yellow.self,
blue: themeVars.color.blue.self,
magenta: themeVars.color.pink.self,
cyan: themeVars.color.teal.self,
white: themeVars.color.console.fg.subtle,
bright: {
black: themeVars.color.black.light,
red: themeVars.color.red.light,
green: themeVars.color.green.light,
yellow: themeVars.color.yellow.light,
blue: themeVars.color.blue.light,
magenta: themeVars.color.pink.light,
cyan: themeVars.color.teal.light,
white: themeVars.color.console.fg.self,
},
};
return {
isDarkTheme: theme.isDarkTheme.toString(),
color: {
primary,
secondary,
...named,
ansi,
console: theme.console,
diff: theme.diff,
...message,
...theme.based,
},
};
}

View File

@@ -2,7 +2,7 @@ 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>>;
export type Theme = WithOptionalLayer<MapLeafNodes<typeof themeVars, string>>;
function stringToBoolean(str: string, name: string): boolean {
try {
@@ -13,27 +13,6 @@ function stringToBoolean(str: string, name: string): boolean {
}
}
/** 定义主题, 用于生成颜色主题
* @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, {
@@ -42,7 +21,7 @@ export function createTheme(theme: Theme): void {
},
});
globalStyle(":root", {
accentColor: themeVars.color.blue,
accentColor: themeVars.color.accent,
colorScheme: stringToBoolean(theme.isDarkTheme, "isDarkTheme") ? "dark" : "light",
});
}

View File

@@ -1,3 +1,4 @@
export { css } from "@linaria/core";
export { defineTheme } from "./core/theme";
export { defineTheme } from "./core/color";
export type { Based, Console, Diff } from "./types";
export { themeVars } from "./types/vars";

View File

@@ -28,13 +28,13 @@ export const based = {
},
/** 输入框 */
input: {
text: null,
background: null,
toggleBackgound: "color-input-toggle-background",
border: {
self: null,
hover: null,
},
text: null,
toggleBackgound: "color-input-toggle-background",
},
light: {
self: null,
@@ -86,12 +86,8 @@ export const based = {
label: {
text: null,
bg: null,
hover: {
bg: null,
},
active: {
bg: null,
},
hoverBg: "color-label-hover-bg",
activeBg: "color-label-active-bg",
},
accent: null,
smallAccent: "color-small-accent",

View File

@@ -2,5 +2,5 @@ export { based } from "./based";
export { ansi, console } from "./console";
export { diff } from "./diff";
export { primary, secondary } from "./main";
export { error, info, success, warning } from "./message";
export { message } from "./message";
export { named } from "./named";

View File

@@ -4,7 +4,7 @@ const msg = {
text: null,
};
export const error = {
const error = {
...msg,
bg: {
self: null,
@@ -13,13 +13,20 @@ export const error = {
},
};
export const success = {
const success = {
...msg,
};
export const warning = {
const warning = {
...msg,
};
export const info = {
const info = {
...msg,
};
export const message = {
error,
success,
warning,
info,
};

View File

@@ -4,3 +4,8 @@ import * as color from "./color";
export type Primary = MapLeafNodes<typeof color.primary, string>;
export type Secondary = MapLeafNodes<typeof color.secondary, string>;
export type Named = MapLeafNodes<typeof color.named, string>;
export type Message = MapLeafNodes<typeof color.message, string>;
export type Ansi = MapLeafNodes<typeof color.ansi, string>;
export type Console = MapLeafNodes<typeof color.console, string>;
export type Diff = MapLeafNodes<typeof color.diff, string>;
export type Based = MapLeafNodes<typeof color.based, string>;

View File

@@ -14,19 +14,14 @@ const vars = {
/** 用于标识当前是否为暗色主题: `"true"` 暗色 `"false"` 亮色 */
isDarkTheme: "is-dark-theme",
color: {
...color.message,
...color.based,
...color.named,
primary: color.primary,
secondary: color.secondary,
self: {
...color.based,
...color.named,
},
ansi: color.ansi,
console: color.console,
diff: color.diff,
error: color.error,
success: color.success,
warning: color.warning,
info: color.info,
},
};