You've already forked gitea-banana-theme
初始化提交
This commit is contained in:
64
src/core/chroma.ts
Normal file
64
src/core/chroma.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { prettylights2Chroma, type prettylightsColor } from "./prettylights";
|
||||
|
||||
export const lightPrettylights: prettylightsColor = {
|
||||
syntax: {
|
||||
brackethighlighter: { angle: "#59636e", unmatched: "#82071e" },
|
||||
carriage: { return: { bg: "#cf222e", text: "#f6f8fa" } },
|
||||
comment: "#59636e",
|
||||
constant: "#0550ae",
|
||||
constantOtherReferenceLink: "#0a3069",
|
||||
entity: "#6639ba",
|
||||
entityTag: "#0550ae",
|
||||
invalid: { illegal: { bg: "#82071e", text: "#f6f8fa" } },
|
||||
keyword: "#cf222e",
|
||||
markup: {
|
||||
bold: "#1f2328",
|
||||
changed: { bg: "#ffd8b5", text: "#953800" },
|
||||
deleted: { bg: "#ffebe9", text: "#82071e" },
|
||||
heading: "#0550ae",
|
||||
ignored: { bg: "#0550ae", text: "#d1d9e0" },
|
||||
inserted: { bg: "#dafbe1", text: "#116329" },
|
||||
italic: "#1f2328",
|
||||
list: "#3b2300",
|
||||
},
|
||||
metaDiffRange: "#8250df",
|
||||
storageModifierImport: "#1f2328",
|
||||
string: "#0a3069",
|
||||
stringRegexp: "#116329",
|
||||
sublimelinterGutterMark: "#818b98",
|
||||
variable: "#953800",
|
||||
},
|
||||
};
|
||||
|
||||
export const darkPrettylights: prettylightsColor = {
|
||||
syntax: {
|
||||
brackethighlighter: { angle: "#9198a1", unmatched: "#f85149" },
|
||||
carriage: { return: { bg: "#b62324", text: "#f0f6fc" } },
|
||||
comment: "#9198a1",
|
||||
constant: "#79c0ff",
|
||||
constantOtherReferenceLink: "#a5d6ff",
|
||||
entity: "#d2a8ff",
|
||||
entityTag: "#7ee787",
|
||||
invalid: { illegal: { bg: "#8e1519", text: "#f0f6fc" } },
|
||||
keyword: "#ff7b72",
|
||||
markup: {
|
||||
bold: "#f0f6fc",
|
||||
changed: { bg: "#5a1e02", text: "#ffdfb6" },
|
||||
deleted: { bg: "#67060c", text: "#ffdcd7" },
|
||||
heading: "#1f6feb",
|
||||
ignored: { bg: "#1158c7", text: "#f0f6fc" },
|
||||
inserted: { bg: "#033a16", text: "#aff5b4" },
|
||||
italic: "#f0f6fc",
|
||||
list: "#f2cc60",
|
||||
},
|
||||
metaDiffRange: "#d2a8ff",
|
||||
storageModifierImport: "#f0f6fc",
|
||||
string: "#a5d6ff",
|
||||
stringRegexp: "#7ee787",
|
||||
sublimelinterGutterMark: "#3d444d",
|
||||
variable: "#ffa657",
|
||||
},
|
||||
};
|
||||
|
||||
export const defaultLightChroma = prettylights2Chroma(lightPrettylights);
|
||||
export const defaultDarkChroma = prettylights2Chroma(darkPrettylights);
|
||||
389
src/core/color.ts
Normal file
389
src/core/color.ts
Normal file
@@ -0,0 +1,389 @@
|
||||
import { rgba, saturate } from "polished";
|
||||
import { scaleColorLight } from "src/functions";
|
||||
import type { Ansi, Chroma, Console, Diff, Github, Message, Named, Other, Primary, Secondary } from "src/types";
|
||||
import { themeVars } from "src/types/vars";
|
||||
import { defaultDarkChroma, defaultLightChroma } from "./chroma";
|
||||
import type { Theme } from "./theme";
|
||||
|
||||
export type ThemeColor = {
|
||||
/** 用于标识当前是否为暗色主题: `true` 暗色 `false` 亮色 */
|
||||
isDarkTheme: boolean;
|
||||
/** 主色调(强调色) */
|
||||
primary: string;
|
||||
/** 主色调的对比色, 一般用于 `color` 属性, primary 用于 `background-color` */
|
||||
primaryContrast: string;
|
||||
/** 副色调(边框色) */
|
||||
secondary: string;
|
||||
/** 基础颜色 */
|
||||
base: {
|
||||
/** 红色 */
|
||||
red: string;
|
||||
/** 橙色 */
|
||||
orange: string;
|
||||
/** 黄色 */
|
||||
yellow: string;
|
||||
/** 黄绿色/橄榄色 */
|
||||
olive: string;
|
||||
/** 绿色 */
|
||||
green: string;
|
||||
/** 蓝绿色/青色(偏绿) */
|
||||
teal: string;
|
||||
/** 蓝绿色/青色(偏蓝) */
|
||||
cyan: string;
|
||||
/** 蓝色 */
|
||||
blue: string;
|
||||
/** 蓝紫色/紫罗兰色 */
|
||||
violet: string;
|
||||
/** 紫色 */
|
||||
purple: string;
|
||||
/** 粉红色 */
|
||||
pink: string;
|
||||
/** 棕色 */
|
||||
brown: string;
|
||||
/** 黑色 */
|
||||
black: string;
|
||||
/** 灰色 */
|
||||
grey: string;
|
||||
/** 金色 */
|
||||
gold: string;
|
||||
/** 白色 */
|
||||
white: string;
|
||||
};
|
||||
/** Action 日志 */
|
||||
console: Console;
|
||||
/** 提交代码对比 */
|
||||
diff: Diff;
|
||||
/** 其他 */
|
||||
other: Other;
|
||||
/** 仅适用于本主题的全局变量, 取自 Github */
|
||||
github: Github;
|
||||
};
|
||||
|
||||
/** 定义颜色, 用于生成颜色主题
|
||||
* @example
|
||||
* 文件名: "dark.css.ts"
|
||||
* import type { Console, Diff, Other, Github } from "src/types";
|
||||
* import { defineTheme, themeVars } from "src";
|
||||
*
|
||||
* const console: Console = {
|
||||
* fg: {
|
||||
* self: "#f0f6fc", // self 表示本身等于 --color-console-fg: #f0f6fc, 所有键名为 self 的都将被忽略
|
||||
* subtle: themeVars.color.body, // 引用别的CSS变量等于 --color-console-fg-subtle: var(--color-body)
|
||||
* num1: "rgb(125, 133, 144)", // 由于纯数字无法在 TS 中使用点调用, 采用 num 前缀等于 --color-console-fg-1: rgb(125, 133, 144)
|
||||
* },
|
||||
* ...
|
||||
* }
|
||||
* ...
|
||||
* export default defineTheme({
|
||||
* isDarkTheme: true,
|
||||
* primary: "#0969da",
|
||||
* ...
|
||||
* console,
|
||||
* diff,
|
||||
* other,
|
||||
* github,
|
||||
* })
|
||||
*/
|
||||
export function defineTheme(themeColor: ThemeColor, chroma?: Chroma): Theme {
|
||||
const brightDir = themeColor.isDarkTheme ? -1 : 1;
|
||||
|
||||
const primary: Primary = {
|
||||
self: themeColor.primary,
|
||||
contrast: themeColor.primaryContrast,
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.primary, -12 * brightDir),
|
||||
num2: scaleColorLight(themeColor.primary, -24 * brightDir),
|
||||
num3: scaleColorLight(themeColor.primary, -36 * brightDir),
|
||||
num4: scaleColorLight(themeColor.primary, -48 * brightDir),
|
||||
num5: scaleColorLight(themeColor.primary, -60 * brightDir),
|
||||
num6: scaleColorLight(themeColor.primary, -72 * brightDir),
|
||||
num7: scaleColorLight(themeColor.primary, -84 * brightDir),
|
||||
},
|
||||
light: {
|
||||
num1: scaleColorLight(themeColor.primary, 12 * brightDir),
|
||||
num2: scaleColorLight(themeColor.primary, 24 * brightDir),
|
||||
num3: scaleColorLight(themeColor.primary, 36 * brightDir),
|
||||
num4: scaleColorLight(themeColor.primary, 48 * brightDir),
|
||||
num5: scaleColorLight(themeColor.primary, 60 * brightDir),
|
||||
num6: scaleColorLight(themeColor.primary, 72 * brightDir),
|
||||
num7: scaleColorLight(themeColor.primary, 84 * brightDir),
|
||||
},
|
||||
alpha: {
|
||||
num10: rgba(themeColor.primary, 0.1),
|
||||
num20: rgba(themeColor.primary, 0.2),
|
||||
num30: rgba(themeColor.primary, 0.3),
|
||||
num40: rgba(themeColor.primary, 0.4),
|
||||
num50: rgba(themeColor.primary, 0.5),
|
||||
num60: rgba(themeColor.primary, 0.6),
|
||||
num70: rgba(themeColor.primary, 0.7),
|
||||
num80: rgba(themeColor.primary, 0.8),
|
||||
num90: rgba(themeColor.primary, 0.9),
|
||||
},
|
||||
hover: themeColor.isDarkTheme ? themeVars.color.primary.light.num1 : themeVars.color.primary.dark.num1,
|
||||
active: themeColor.isDarkTheme ? themeVars.color.primary.light.num2 : themeVars.color.primary.dark.num2,
|
||||
};
|
||||
|
||||
const secondary: Secondary = {
|
||||
self: themeColor.secondary,
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.secondary, -6 * brightDir),
|
||||
num2: scaleColorLight(themeColor.secondary, -12 * brightDir),
|
||||
num3: scaleColorLight(themeColor.secondary, -18 * brightDir),
|
||||
num4: scaleColorLight(themeColor.secondary, -24 * brightDir),
|
||||
num5: scaleColorLight(themeColor.secondary, -30 * brightDir),
|
||||
num6: scaleColorLight(themeColor.secondary, -36 * brightDir),
|
||||
num7: scaleColorLight(themeColor.secondary, -42 * brightDir),
|
||||
num8: scaleColorLight(themeColor.secondary, -48 * brightDir),
|
||||
num9: scaleColorLight(themeColor.secondary, -54 * brightDir),
|
||||
num10: scaleColorLight(themeColor.secondary, -60 * brightDir),
|
||||
num11: scaleColorLight(themeColor.secondary, -66 * brightDir),
|
||||
num12: scaleColorLight(themeColor.secondary, -72 * brightDir),
|
||||
num13: scaleColorLight(themeColor.secondary, -80 * brightDir),
|
||||
},
|
||||
light: {
|
||||
num1: scaleColorLight(themeColor.secondary, 18 * brightDir),
|
||||
num2: scaleColorLight(themeColor.secondary, 36 * brightDir),
|
||||
num3: scaleColorLight(themeColor.secondary, 54 * brightDir),
|
||||
num4: scaleColorLight(themeColor.secondary, 72 * brightDir),
|
||||
},
|
||||
alpha: {
|
||||
num10: rgba(themeColor.secondary, 0.1),
|
||||
num20: rgba(themeColor.secondary, 0.2),
|
||||
num30: rgba(themeColor.secondary, 0.3),
|
||||
num40: rgba(themeColor.secondary, 0.4),
|
||||
num50: rgba(themeColor.secondary, 0.5),
|
||||
num60: rgba(themeColor.secondary, 0.6),
|
||||
num70: rgba(themeColor.secondary, 0.7),
|
||||
num80: rgba(themeColor.secondary, 0.8),
|
||||
num90: rgba(themeColor.secondary, 0.9),
|
||||
},
|
||||
button: themeVars.color.secondary.dark.num4,
|
||||
hover: themeColor.isDarkTheme ? themeVars.color.secondary.dark.num3 : themeVars.color.secondary.dark.num5,
|
||||
active: themeColor.isDarkTheme ? themeVars.color.secondary.dark.num2 : themeVars.color.secondary.dark.num6,
|
||||
};
|
||||
|
||||
const named: Named = {
|
||||
red: {
|
||||
self: themeColor.base.red,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.red, 15)
|
||||
: scaleColorLight(themeColor.base.red, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.red, -10),
|
||||
num2: scaleColorLight(themeColor.base.red, -20),
|
||||
},
|
||||
badge: {
|
||||
self: themeColor.base.red,
|
||||
bg: rgba(themeColor.base.red, 0.1),
|
||||
hover: {
|
||||
bg: rgba(themeColor.base.red, 0.3),
|
||||
},
|
||||
},
|
||||
},
|
||||
orange: {
|
||||
self: themeColor.base.orange,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.orange, 15)
|
||||
: scaleColorLight(themeColor.base.orange, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.orange, -10),
|
||||
num2: scaleColorLight(themeColor.base.orange, -20),
|
||||
},
|
||||
badge: {
|
||||
self: themeColor.base.orange,
|
||||
bg: rgba(themeColor.base.orange, 0.1),
|
||||
hover: {
|
||||
bg: rgba(themeColor.base.orange, 0.3),
|
||||
},
|
||||
},
|
||||
},
|
||||
yellow: {
|
||||
self: themeColor.base.yellow,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.yellow, 15)
|
||||
: scaleColorLight(themeColor.base.yellow, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.yellow, -10),
|
||||
num2: scaleColorLight(themeColor.base.yellow, -20),
|
||||
},
|
||||
badge: {
|
||||
self: themeColor.base.yellow,
|
||||
bg: rgba(themeColor.base.yellow, 0.1),
|
||||
hover: {
|
||||
bg: rgba(themeColor.base.yellow, 0.3),
|
||||
},
|
||||
},
|
||||
},
|
||||
olive: {
|
||||
self: themeColor.base.olive,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.olive, 15)
|
||||
: scaleColorLight(themeColor.base.olive, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.olive, -10),
|
||||
num2: scaleColorLight(themeColor.base.olive, -20),
|
||||
},
|
||||
},
|
||||
green: {
|
||||
self: themeColor.base.green,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.green, 15)
|
||||
: scaleColorLight(themeColor.base.green, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.green, -10),
|
||||
num2: scaleColorLight(themeColor.base.green, -20),
|
||||
},
|
||||
badge: {
|
||||
self: themeColor.base.green,
|
||||
bg: rgba(themeColor.base.green, 0.1),
|
||||
hover: {
|
||||
bg: rgba(themeColor.base.green, 0.3),
|
||||
},
|
||||
},
|
||||
},
|
||||
teal: {
|
||||
self: themeColor.base.teal,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.teal, 15)
|
||||
: scaleColorLight(themeColor.base.teal, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.teal, -10),
|
||||
num2: scaleColorLight(themeColor.base.teal, -20),
|
||||
},
|
||||
},
|
||||
blue: {
|
||||
self: themeColor.base.blue,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.blue, 15)
|
||||
: scaleColorLight(themeColor.base.blue, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.blue, -10),
|
||||
num2: scaleColorLight(themeColor.base.blue, -20),
|
||||
},
|
||||
},
|
||||
violet: {
|
||||
self: themeColor.base.violet,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.violet, 15)
|
||||
: scaleColorLight(themeColor.base.violet, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.violet, -10),
|
||||
num2: scaleColorLight(themeColor.base.violet, -20),
|
||||
},
|
||||
},
|
||||
purple: {
|
||||
self: themeColor.base.purple,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.purple, 15)
|
||||
: scaleColorLight(themeColor.base.purple, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.purple, -10),
|
||||
num2: scaleColorLight(themeColor.base.purple, -20),
|
||||
},
|
||||
},
|
||||
pink: {
|
||||
self: themeColor.base.pink,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.pink, 15)
|
||||
: scaleColorLight(themeColor.base.pink, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.pink, -10),
|
||||
num2: scaleColorLight(themeColor.base.pink, -20),
|
||||
},
|
||||
},
|
||||
brown: {
|
||||
self: themeColor.base.brown,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.brown, 15)
|
||||
: scaleColorLight(themeColor.base.brown, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.brown, -10),
|
||||
num2: scaleColorLight(themeColor.base.brown, -20),
|
||||
},
|
||||
},
|
||||
black: {
|
||||
self: themeColor.base.black,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.black, 15)
|
||||
: scaleColorLight(themeColor.base.black, 25),
|
||||
dark: {
|
||||
num1: scaleColorLight(themeColor.base.black, -10),
|
||||
num2: scaleColorLight(themeColor.base.black, -20),
|
||||
},
|
||||
},
|
||||
grey: {
|
||||
self: themeColor.base.grey,
|
||||
light: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.grey, 15)
|
||||
: scaleColorLight(themeColor.base.grey, 25),
|
||||
},
|
||||
gold: themeColor.base.gold,
|
||||
white: themeColor.base.white,
|
||||
};
|
||||
|
||||
const message: Message = {
|
||||
error: {
|
||||
bg: {
|
||||
self: rgba(themeColor.base.red, 0.1),
|
||||
active: rgba(themeColor.base.red, 0.5),
|
||||
hover: rgba(themeColor.base.red, 0.3),
|
||||
},
|
||||
border: rgba(themeColor.base.red, 0.4),
|
||||
text: saturate(0.2, themeColor.base.red), // 饱和度提高
|
||||
},
|
||||
success: {
|
||||
bg: rgba(themeColor.base.green, 0.1),
|
||||
border: rgba(themeColor.base.green, 0.4),
|
||||
text: saturate(0.2, themeColor.base.green),
|
||||
},
|
||||
warning: {
|
||||
bg: rgba(themeColor.base.yellow, 0.1),
|
||||
border: rgba(themeColor.base.yellow, 0.4),
|
||||
text: saturate(0.2, themeColor.base.yellow),
|
||||
},
|
||||
info: {
|
||||
bg: rgba(themeColor.base.blue, 0.1),
|
||||
border: rgba(themeColor.base.blue, 0.4),
|
||||
text: saturate(0.2, themeColor.base.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: themeColor.base.cyan,
|
||||
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: themeColor.isDarkTheme
|
||||
? scaleColorLight(themeColor.base.cyan, 10)
|
||||
: scaleColorLight(themeColor.base.cyan, 25),
|
||||
white: themeVars.color.console.fg.self,
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
isDarkTheme: themeColor.isDarkTheme.toString(),
|
||||
chroma: chroma || (themeColor.isDarkTheme ? defaultDarkChroma : defaultLightChroma),
|
||||
color: {
|
||||
primary,
|
||||
secondary,
|
||||
...named,
|
||||
ansi,
|
||||
console: themeColor.console,
|
||||
diff: themeColor.diff,
|
||||
...message,
|
||||
...themeColor.other,
|
||||
},
|
||||
github: themeColor.github,
|
||||
};
|
||||
}
|
||||
85
src/core/display.ts
Normal file
85
src/core/display.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { saturate } from "polished";
|
||||
import { scaleColorLight } from "src/functions";
|
||||
import { type GithubColor } from "./github";
|
||||
|
||||
export type DisplayColor = {
|
||||
num0: string;
|
||||
num1: string;
|
||||
num2: string;
|
||||
num3: string;
|
||||
num4: string;
|
||||
num5: string;
|
||||
num6: string;
|
||||
num7: string;
|
||||
num8: string;
|
||||
num9: string;
|
||||
};
|
||||
|
||||
export function display2GithubColor(
|
||||
displayColor: DisplayColor,
|
||||
baseGithubColor: GithubColor,
|
||||
soft?: boolean
|
||||
): GithubColor {
|
||||
return {
|
||||
...baseGithubColor,
|
||||
diffBlob: {
|
||||
...baseGithubColor.diffBlob,
|
||||
hunkNum: { bgColor: { rest: soft ? displayColor.num2 : displayColor.num1 } },
|
||||
},
|
||||
fgColor: {
|
||||
...baseGithubColor.fgColor,
|
||||
accent: soft ? displayColor.num7 : displayColor.num6,
|
||||
},
|
||||
bgColor: {
|
||||
...baseGithubColor.bgColor,
|
||||
accent: {
|
||||
emphasis: soft ? saturate(-0.1, scaleColorLight(displayColor.num5, -2)) : displayColor.num5,
|
||||
muted: soft ? displayColor.num1 : displayColor.num0,
|
||||
},
|
||||
},
|
||||
borderColor: {
|
||||
...baseGithubColor.borderColor,
|
||||
accent: {
|
||||
emphasis: soft ? displayColor.num6 : displayColor.num5,
|
||||
},
|
||||
},
|
||||
button: {
|
||||
...baseGithubColor.button,
|
||||
primary: {
|
||||
...baseGithubColor.button.primary,
|
||||
fgColor: {
|
||||
...baseGithubColor.button.primary.fgColor,
|
||||
accent: soft ? displayColor.num7 : displayColor.num6,
|
||||
},
|
||||
bgColor: {
|
||||
...baseGithubColor.button.primary.bgColor,
|
||||
rest: soft ? saturate(-0.1, scaleColorLight(displayColor.num5, -2)) : displayColor.num5,
|
||||
hover: soft ? saturate(-0.1, scaleColorLight(displayColor.num5, 3)) : scaleColorLight(displayColor.num5, 5),
|
||||
},
|
||||
},
|
||||
star: {
|
||||
iconColor: soft
|
||||
? scaleColorLight(displayColor.num6, -2)
|
||||
: saturate(0.1, scaleColorLight(displayColor.num6, -2)),
|
||||
},
|
||||
},
|
||||
underlineNav: {
|
||||
borderColor: {
|
||||
active: soft ? scaleColorLight(saturate(0.1, displayColor.num6), -5) : saturate(0.2, displayColor.num6),
|
||||
},
|
||||
},
|
||||
contribution: {
|
||||
...baseGithubColor.contribution,
|
||||
default: {
|
||||
...baseGithubColor.contribution.default,
|
||||
bgColor: {
|
||||
num0: baseGithubColor.contribution.default.bgColor.num0,
|
||||
num1: soft ? displayColor.num2 : displayColor.num1,
|
||||
num2: soft ? displayColor.num3 : displayColor.num2,
|
||||
num3: soft ? displayColor.num5 : displayColor.num4,
|
||||
num4: soft ? displayColor.num7 : displayColor.num6,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
370
src/core/github.ts
Normal file
370
src/core/github.ts
Normal file
@@ -0,0 +1,370 @@
|
||||
import { saturate } from "polished";
|
||||
import type { Console, Diff, Other } from "src";
|
||||
import { scaleColorLight } from "src/functions";
|
||||
import type { Github } from "src/types";
|
||||
import { themeVars } from "src/types/vars";
|
||||
import { type ThemeColor } from "./color";
|
||||
|
||||
export type GithubColor = {
|
||||
isDarkTheme: boolean;
|
||||
display: {
|
||||
blue: { fgColor: string };
|
||||
brown: { fgColor: string };
|
||||
cyan: { fgColor: string };
|
||||
indigo: { fgColor: string };
|
||||
lemon: { fgColor: string };
|
||||
olive: { fgColor: string };
|
||||
teal: { fgColor: string };
|
||||
};
|
||||
diffBlob: {
|
||||
addtionNum: { bgColor: string };
|
||||
addtionWord: { bgColor: string };
|
||||
deletionNum: { bgColor: string };
|
||||
deletionWord: { bgColor: string };
|
||||
hunkNum: { bgColor: { rest: string } };
|
||||
};
|
||||
fgColor: {
|
||||
accent: string;
|
||||
attention: string;
|
||||
danger: string;
|
||||
default: string;
|
||||
disabled: string;
|
||||
done: string;
|
||||
neutral: string;
|
||||
severe: string;
|
||||
sponsors: string;
|
||||
success: string;
|
||||
black: string;
|
||||
white: string;
|
||||
muted: string;
|
||||
onEmphasis: string;
|
||||
};
|
||||
bgColor: {
|
||||
accent: { emphasis: string; muted: string };
|
||||
attention: { muted: string };
|
||||
emphasis: string;
|
||||
success: { emphasis: string; muted: string };
|
||||
danger: { muted: string };
|
||||
done: { emphasis: string };
|
||||
default: string;
|
||||
inset: string;
|
||||
muted: string;
|
||||
neutral: { muted: string };
|
||||
};
|
||||
borderColor: {
|
||||
accent: { emphasis: string };
|
||||
attention: { emphasis: string };
|
||||
default: string;
|
||||
success: { emphasis: string };
|
||||
done: { emphasis: string };
|
||||
muted: string;
|
||||
translucent: string;
|
||||
};
|
||||
button: {
|
||||
primary: { fgColor: { accent: string; rest: string }; bgColor: { rest: string; hover: string } };
|
||||
danger: { fgColor: { rest: string; hover: string }; bgColor: { hover: string } };
|
||||
star: { iconColor: string };
|
||||
};
|
||||
control: {
|
||||
bgColor: { active: string; hover: string; rest: string };
|
||||
transparent: { bgColor: { active: string; hover: string; selected: string } };
|
||||
};
|
||||
shadow: { floating: { small: string }; resting: { small: string } };
|
||||
overlay: { backdrop: { bgColor: string } };
|
||||
underlineNav: { borderColor: { active: string } };
|
||||
contribution: {
|
||||
default: {
|
||||
bgColor: { num0: string; num1: string; num2: string; num3: string; num4: string };
|
||||
borderColor: { num0: string };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export function github2ThemeColor(githubColor: GithubColor): ThemeColor {
|
||||
const console: Console = {
|
||||
fg: {
|
||||
self: githubColor.fgColor.default,
|
||||
subtle: githubColor.fgColor.muted,
|
||||
},
|
||||
bg: githubColor.bgColor.inset,
|
||||
border: githubColor.borderColor.muted,
|
||||
activeBg: githubColor.control.bgColor.active,
|
||||
hoverBg: githubColor.control.transparent.bgColor.hover,
|
||||
menu: {
|
||||
bg: githubColor.bgColor.inset,
|
||||
border: githubColor.borderColor.muted,
|
||||
},
|
||||
};
|
||||
|
||||
const diff: Diff = {
|
||||
added: {
|
||||
linenum: {
|
||||
bg: githubColor.diffBlob.addtionNum.bgColor,
|
||||
},
|
||||
row: {
|
||||
bg: githubColor.bgColor.success.muted,
|
||||
border: githubColor.bgColor.success.muted,
|
||||
},
|
||||
word: {
|
||||
bg: githubColor.diffBlob.addtionWord.bgColor,
|
||||
},
|
||||
},
|
||||
removed: {
|
||||
linenum: {
|
||||
bg: githubColor.diffBlob.deletionNum.bgColor,
|
||||
},
|
||||
row: {
|
||||
bg: githubColor.bgColor.danger.muted,
|
||||
border: githubColor.bgColor.danger.muted,
|
||||
},
|
||||
word: {
|
||||
bg: githubColor.diffBlob.deletionWord.bgColor,
|
||||
},
|
||||
},
|
||||
moved: {
|
||||
row: {
|
||||
bg: githubColor.bgColor.attention.muted,
|
||||
border: githubColor.bgColor.attention.muted,
|
||||
},
|
||||
},
|
||||
inactive: githubColor.bgColor.muted,
|
||||
};
|
||||
|
||||
const other: Other = {
|
||||
body: githubColor.bgColor.default,
|
||||
box: {
|
||||
header: githubColor.bgColor.muted,
|
||||
body: {
|
||||
self: themeVars.color.body,
|
||||
highlight: githubColor.bgColor.accent.muted,
|
||||
},
|
||||
},
|
||||
text: {
|
||||
self: githubColor.fgColor.default,
|
||||
light: {
|
||||
self: githubColor.fgColor.default,
|
||||
num1: githubColor.fgColor.muted,
|
||||
num2: githubColor.fgColor.muted,
|
||||
num3: githubColor.fgColor.muted,
|
||||
},
|
||||
dark: githubColor.fgColor.default,
|
||||
},
|
||||
footer: githubColor.bgColor.inset,
|
||||
timeline: githubColor.borderColor.muted,
|
||||
input: {
|
||||
text: themeVars.color.text.self,
|
||||
background: githubColor.bgColor.muted,
|
||||
toggleBackgound: themeVars.color.body,
|
||||
border: {
|
||||
self: themeVars.color.light.border,
|
||||
hover: themeVars.color.light.border,
|
||||
},
|
||||
},
|
||||
light: {
|
||||
self: themeVars.color.body,
|
||||
border: githubColor.borderColor.default,
|
||||
},
|
||||
hover: {
|
||||
self: githubColor.control.bgColor.hover,
|
||||
opaque: themeVars.color.box.header,
|
||||
},
|
||||
active: githubColor.control.transparent.bgColor.selected,
|
||||
menu: githubColor.bgColor.inset,
|
||||
card: themeVars.color.body,
|
||||
markup: {
|
||||
tableRow: githubColor.bgColor.muted,
|
||||
code: {
|
||||
block: githubColor.bgColor.muted,
|
||||
inline: githubColor.bgColor.neutral.muted,
|
||||
},
|
||||
},
|
||||
button: githubColor.control.bgColor.rest,
|
||||
codeBg: "unset",
|
||||
shadow: {
|
||||
self: githubColor.shadow.floating.small,
|
||||
opaque: themeVars.color.shadow.self,
|
||||
},
|
||||
secondaryBg: "unset",
|
||||
expandButton: githubColor.diffBlob.hunkNum.bgColor.rest,
|
||||
placeholderText: themeVars.color.text.light.num3,
|
||||
editorLineHighlight: themeVars.color.primary.light.num5,
|
||||
projectColumnBg: githubColor.bgColor.inset,
|
||||
caret: themeVars.color.text.dark,
|
||||
reaction: {
|
||||
bg: "initial",
|
||||
hoverBg: githubColor.bgColor.accent.muted,
|
||||
activeBg: githubColor.bgColor.accent.muted,
|
||||
},
|
||||
tooltip: {
|
||||
text: githubColor.fgColor.onEmphasis,
|
||||
bg: githubColor.bgColor.emphasis,
|
||||
},
|
||||
nav: {
|
||||
bg: githubColor.bgColor.muted,
|
||||
hoverBg: githubColor.control.transparent.bgColor.hover,
|
||||
text: themeVars.color.text.self,
|
||||
},
|
||||
secondaryNavBg: themeVars.color.body,
|
||||
label: {
|
||||
text: themeVars.color.text.self,
|
||||
bg: githubColor.bgColor.neutral.muted,
|
||||
hoverBg: githubColor.control.transparent.bgColor.active,
|
||||
activeBg: themeVars.color.label.hoverBg,
|
||||
},
|
||||
accent: themeVars.color.primary.light.num1,
|
||||
smallAccent: themeVars.color.primary.light.num5,
|
||||
highlight: {
|
||||
fg: githubColor.fgColor.attention,
|
||||
bg: githubColor.bgColor.attention.muted,
|
||||
},
|
||||
overlayBackdrop: githubColor.overlay.backdrop.bgColor,
|
||||
};
|
||||
|
||||
const github: Github = {
|
||||
fgColor: {
|
||||
accent: githubColor.fgColor.accent,
|
||||
success: githubColor.fgColor.success,
|
||||
done: githubColor.fgColor.done,
|
||||
},
|
||||
bgColor: {
|
||||
accent: {
|
||||
emphasis: githubColor.bgColor.accent.emphasis,
|
||||
muted: githubColor.bgColor.accent.muted,
|
||||
},
|
||||
success: {
|
||||
emphasis: githubColor.bgColor.success.emphasis,
|
||||
},
|
||||
done: {
|
||||
emphasis: githubColor.bgColor.done.emphasis,
|
||||
},
|
||||
},
|
||||
borderColor: {
|
||||
accent: {
|
||||
emphasis: githubColor.borderColor.accent.emphasis,
|
||||
},
|
||||
attention: {
|
||||
emphasis: githubColor.borderColor.attention.emphasis,
|
||||
},
|
||||
success: {
|
||||
emphasis: githubColor.borderColor.success.emphasis,
|
||||
},
|
||||
done: {
|
||||
emphasis: githubColor.borderColor.done.emphasis,
|
||||
},
|
||||
},
|
||||
button: {
|
||||
default: {
|
||||
bgColor: {
|
||||
active: githubColor.control.bgColor.active,
|
||||
},
|
||||
},
|
||||
primary: {
|
||||
fgColor: {
|
||||
accent: saturate(
|
||||
0.1,
|
||||
scaleColorLight(githubColor.button.primary.fgColor.accent, githubColor.isDarkTheme ? 10 : -10)
|
||||
),
|
||||
rest: githubColor.button.primary.fgColor.rest,
|
||||
},
|
||||
bgColor: {
|
||||
rest: githubColor.button.primary.bgColor.rest,
|
||||
hover: githubColor.button.primary.bgColor.hover,
|
||||
},
|
||||
borderColor: {
|
||||
rest: githubColor.borderColor.translucent,
|
||||
hover: githubColor.borderColor.translucent,
|
||||
},
|
||||
},
|
||||
danger: {
|
||||
fgColor: {
|
||||
rest: githubColor.button.danger.fgColor.rest,
|
||||
hover: githubColor.button.danger.fgColor.hover,
|
||||
},
|
||||
bgColor: {
|
||||
rest: githubColor.control.bgColor.rest,
|
||||
hover: githubColor.button.danger.bgColor.hover,
|
||||
},
|
||||
borderColor: {
|
||||
hover: githubColor.borderColor.translucent,
|
||||
},
|
||||
},
|
||||
star: {
|
||||
iconColor: githubColor.button.star.iconColor,
|
||||
},
|
||||
},
|
||||
control: {
|
||||
bgColor: {
|
||||
rest: githubColor.control.bgColor.rest,
|
||||
},
|
||||
transparent: {
|
||||
bgColor: {
|
||||
hover: githubColor.control.transparent.bgColor.hover,
|
||||
},
|
||||
},
|
||||
},
|
||||
shadow: {
|
||||
floating: {
|
||||
small: `0px 0px 0px 1px ${themeVars.color.light.border}, 0px 6px 12px -3px ${themeVars.color.shadow.self}, 0px 6px 18px 0px ${themeVars.color.shadow.self};`,
|
||||
},
|
||||
resting: {
|
||||
small: `0px 1px 1px 0px ${githubColor.shadow.resting.small}, 0px 1px 3px 0px ${githubColor.shadow.resting.small};`,
|
||||
},
|
||||
},
|
||||
underlineNav: {
|
||||
borderColor: {
|
||||
active: githubColor.underlineNav.borderColor.active,
|
||||
},
|
||||
},
|
||||
contribution: {
|
||||
default: {
|
||||
bgColor: {
|
||||
num0: githubColor.contribution.default.bgColor.num0,
|
||||
num1: githubColor.contribution.default.bgColor.num1,
|
||||
num2: githubColor.contribution.default.bgColor.num2,
|
||||
num3: githubColor.contribution.default.bgColor.num3,
|
||||
num4: githubColor.contribution.default.bgColor.num4,
|
||||
num5: saturate(
|
||||
0.2,
|
||||
scaleColorLight(githubColor.contribution.default.bgColor.num4, githubColor.isDarkTheme ? 58 : -58)
|
||||
),
|
||||
},
|
||||
borderColor: {
|
||||
num0: githubColor.contribution.default.borderColor.num0,
|
||||
num1: themeVars.github.contribution.default.borderColor.num0,
|
||||
num2: themeVars.github.contribution.default.borderColor.num0,
|
||||
num3: themeVars.github.contribution.default.borderColor.num0,
|
||||
num4: themeVars.github.contribution.default.borderColor.num0,
|
||||
num5: themeVars.github.contribution.default.borderColor.num0,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
return {
|
||||
isDarkTheme: githubColor.isDarkTheme,
|
||||
primary: githubColor.fgColor.accent,
|
||||
primaryContrast: githubColor.fgColor.default,
|
||||
secondary: githubColor.borderColor.default,
|
||||
base: {
|
||||
red: githubColor.fgColor.danger,
|
||||
orange: githubColor.fgColor.severe,
|
||||
yellow: githubColor.fgColor.attention,
|
||||
olive: githubColor.display.olive.fgColor,
|
||||
green: githubColor.fgColor.success,
|
||||
cyan: githubColor.display.cyan.fgColor,
|
||||
teal: githubColor.display.teal.fgColor,
|
||||
blue: githubColor.display.blue.fgColor,
|
||||
violet: githubColor.display.indigo.fgColor,
|
||||
purple: githubColor.fgColor.done,
|
||||
pink: githubColor.fgColor.sponsors,
|
||||
brown: githubColor.display.brown.fgColor,
|
||||
black: githubColor.fgColor.black,
|
||||
grey: githubColor.fgColor.neutral,
|
||||
gold: githubColor.display.lemon.fgColor,
|
||||
white: githubColor.fgColor.white,
|
||||
},
|
||||
console,
|
||||
diff,
|
||||
other,
|
||||
github,
|
||||
};
|
||||
}
|
||||
1
src/core/index.ts
Normal file
1
src/core/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { createTheme } from "./theme";
|
||||
127
src/core/prettylights.ts
Normal file
127
src/core/prettylights.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import type { Chroma } from "src/types";
|
||||
|
||||
export type prettylightsColor = {
|
||||
syntax: {
|
||||
brackethighlighter: { angle: string; unmatched: string };
|
||||
carriage: { return: { bg: string; text: string } };
|
||||
comment: string;
|
||||
constant: string;
|
||||
constantOtherReferenceLink: string;
|
||||
entity: string;
|
||||
entityTag: string;
|
||||
invalid: { illegal: { bg: string; text: string } };
|
||||
keyword: string;
|
||||
markup: {
|
||||
bold: string;
|
||||
changed: { bg: string; text: string };
|
||||
deleted: { bg: string; text: string };
|
||||
heading: string;
|
||||
ignored: { bg: string; text: string };
|
||||
inserted: { bg: string; text: string };
|
||||
italic: string;
|
||||
list: string;
|
||||
};
|
||||
metaDiffRange: string;
|
||||
storageModifierImport: string;
|
||||
string: string;
|
||||
stringRegexp: string;
|
||||
sublimelinterGutterMark: string;
|
||||
variable: string;
|
||||
};
|
||||
};
|
||||
|
||||
export function prettylights2Chroma(prettylights: prettylightsColor): Chroma {
|
||||
return {
|
||||
textWhiteSpace: prettylights.syntax.brackethighlighter.unmatched,
|
||||
err: prettylights.syntax.brackethighlighter.unmatched,
|
||||
keyword: {
|
||||
self: prettylights.syntax.keyword,
|
||||
constant: prettylights.syntax.constant,
|
||||
declaration: prettylights.syntax.keyword,
|
||||
namespace: prettylights.syntax.keyword,
|
||||
pseudo: prettylights.syntax.constant,
|
||||
reserved: prettylights.syntax.keyword,
|
||||
type: prettylights.syntax.markup.bold,
|
||||
},
|
||||
name: {
|
||||
self: prettylights.syntax.markup.bold,
|
||||
attribute: prettylights.syntax.entityTag,
|
||||
builtin: prettylights.syntax.entity,
|
||||
builtinPseudo: prettylights.syntax.markup.bold,
|
||||
class: prettylights.syntax.variable,
|
||||
constant: prettylights.syntax.variable,
|
||||
decorator: prettylights.syntax.entity,
|
||||
entity: prettylights.syntax.variable,
|
||||
exception: prettylights.syntax.variable,
|
||||
function: prettylights.syntax.entity,
|
||||
functionMagic: prettylights.syntax.entity,
|
||||
label: prettylights.syntax.constant,
|
||||
other: prettylights.syntax.markup.bold,
|
||||
namespace: prettylights.syntax.markup.bold,
|
||||
property: prettylights.syntax.constant,
|
||||
tag: prettylights.syntax.entityTag,
|
||||
variable: prettylights.syntax.constant,
|
||||
variableClass: prettylights.syntax.constant,
|
||||
variableGlobal: prettylights.syntax.constant,
|
||||
variableInstance: prettylights.syntax.constant,
|
||||
variableMagic: prettylights.syntax.markup.bold,
|
||||
},
|
||||
literal: {
|
||||
self: prettylights.syntax.string,
|
||||
date: prettylights.syntax.constant,
|
||||
},
|
||||
string: {
|
||||
self: prettylights.syntax.string,
|
||||
affix: prettylights.syntax.string,
|
||||
backtick: prettylights.syntax.constant,
|
||||
char: prettylights.syntax.string,
|
||||
delimiter: prettylights.syntax.string,
|
||||
doc: prettylights.syntax.comment,
|
||||
double: prettylights.syntax.string,
|
||||
escape: prettylights.syntax.string,
|
||||
heredoc: prettylights.syntax.string,
|
||||
interpol: prettylights.syntax.string,
|
||||
other: prettylights.syntax.string,
|
||||
regex: prettylights.syntax.stringRegexp,
|
||||
single: prettylights.syntax.string,
|
||||
symbol: prettylights.syntax.string,
|
||||
},
|
||||
number: {
|
||||
self: prettylights.syntax.constant,
|
||||
bin: prettylights.syntax.constant,
|
||||
float: prettylights.syntax.constant,
|
||||
hex: prettylights.syntax.constant,
|
||||
integer: prettylights.syntax.constant,
|
||||
integerLong: prettylights.syntax.constant,
|
||||
oct: prettylights.syntax.constant,
|
||||
},
|
||||
operator: {
|
||||
self: prettylights.syntax.constant,
|
||||
word: prettylights.syntax.constant,
|
||||
},
|
||||
punctuation: prettylights.syntax.markup.bold,
|
||||
comment: {
|
||||
self: prettylights.syntax.comment,
|
||||
hashbang: prettylights.syntax.comment,
|
||||
multiline: prettylights.syntax.comment,
|
||||
preproc: prettylights.syntax.constant,
|
||||
preprocFile: prettylights.syntax.constant,
|
||||
single: prettylights.syntax.comment,
|
||||
special: prettylights.syntax.comment,
|
||||
},
|
||||
generic: {
|
||||
self: prettylights.syntax.markup.bold,
|
||||
deleted: prettylights.syntax.markup.deleted.text,
|
||||
emph: prettylights.syntax.markup.italic,
|
||||
error: prettylights.syntax.invalid.illegal.text,
|
||||
heading: prettylights.syntax.markup.heading,
|
||||
inserted: prettylights.syntax.markup.inserted.text,
|
||||
output: prettylights.syntax.markup.bold,
|
||||
prompt: prettylights.syntax.markup.bold,
|
||||
strong: prettylights.syntax.markup.bold,
|
||||
subheading: prettylights.syntax.markup.heading,
|
||||
traceback: prettylights.syntax.invalid.illegal.text,
|
||||
underline: prettylights.syntax.markup.italic,
|
||||
},
|
||||
};
|
||||
}
|
||||
67
src/core/theme.ts
Normal file
67
src/core/theme.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { createGlobalTheme, globalStyle } from "@vanilla-extract/css";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { otherThemeVars, themeInfoVars, themeVars } from "src/types/vars";
|
||||
import type { MapLeafNodes, WithOptionalLayer } from "./types";
|
||||
|
||||
export type Theme = WithOptionalLayer<MapLeafNodes<typeof themeVars, string>>;
|
||||
|
||||
export const overlayAppearDown = "overlay-appear-down";
|
||||
export const animationDown = `200ms cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running ${overlayAppearDown}`;
|
||||
export const overlayAppearUp = "overlay-appear-up";
|
||||
export const animationUp = `200ms cubic-bezier(0.33, 1, 0.68, 1) 0s 1 normal none running ${overlayAppearUp}`;
|
||||
|
||||
const emoji = `
|
||||
.emoji[aria-label="check mark"],
|
||||
.emoji[aria-label="currency exchange"],
|
||||
.emoji[aria-label="TOP arrow"],
|
||||
.emoji[aria-label="END arrow"],
|
||||
.emoji[aria-label="ON! arrow"],
|
||||
.emoji[aria-label="SOON arrow"],
|
||||
.emoji[aria-label="heavy dollar sign"],
|
||||
.emoji[aria-label="copyright"],
|
||||
.emoji[aria-label="registered"],
|
||||
.emoji[aria-label="trade mark"],
|
||||
.emoji[aria-label="multiply"],
|
||||
.emoji[aria-label="plus"],
|
||||
.emoji[aria-label="minus"],
|
||||
.emoji[aria-label="divide"],
|
||||
.emoji[aria-label="curly loop"],
|
||||
.emoji[aria-label="double curly loop"],
|
||||
.emoji[aria-label="wavy dash"],
|
||||
.emoji[aria-label="paw prints"],
|
||||
.emoji[aria-label="musical note"],
|
||||
.emoji[aria-label="musical notes"]
|
||||
`;
|
||||
|
||||
// 版本号: 版本号.YYMMDD
|
||||
const now = new Date();
|
||||
const year = now.getFullYear().toString().slice(-2);
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, "0");
|
||||
const day = now.getDate().toString().padStart(2, "0");
|
||||
|
||||
const pkgPath = path.join(__dirname, "../..", "package.json");
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
||||
const version = `"${pkg.version}.${year}${month}${day}"`;
|
||||
|
||||
export function createTheme(theme: Theme): void {
|
||||
const isDarkTheme: boolean = JSON.parse(theme.isDarkTheme);
|
||||
createGlobalTheme(":root", themeInfoVars, { version });
|
||||
createGlobalTheme(":root", themeVars, theme);
|
||||
createGlobalTheme(":root", otherThemeVars, {
|
||||
border: { radius: "6px" },
|
||||
color: {
|
||||
git: "#f05133",
|
||||
light: {
|
||||
mimicEnabled: isDarkTheme
|
||||
? "rgba(0, 0, 0, calc(40 / 255 * 222 / 255 / var(--opacity-disabled)))"
|
||||
: "rgba(0, 0, 0, calc(6 / 255 * 222 / 255 / var(--opacity-disabled)))",
|
||||
},
|
||||
},
|
||||
});
|
||||
globalStyle(":root", {
|
||||
accentColor: themeVars.color.accent,
|
||||
colorScheme: isDarkTheme ? "dark" : "light",
|
||||
});
|
||||
if (isDarkTheme) globalStyle(emoji, { filter: "invert(100%) hue-rotate(180deg)" });
|
||||
}
|
||||
12
src/core/types.ts
Normal file
12
src/core/types.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
type Primitive = string | boolean | number | null | undefined;
|
||||
type Tokens = { [key: string]: string | Tokens };
|
||||
|
||||
export type CSSVarFunction = `var(--${string})`;
|
||||
export type WithOptionalLayer<T extends Tokens> = T & { "@layer"?: string };
|
||||
export type MapLeafNodes<Obj, LeafType> = {
|
||||
[Prop in keyof Obj]: Obj[Prop] extends Primitive
|
||||
? LeafType
|
||||
: Obj[Prop] extends Record<string | number, unknown>
|
||||
? MapLeafNodes<Obj[Prop], LeafType>
|
||||
: never;
|
||||
};
|
||||
139
src/core/vite.ts
Normal file
139
src/core/vite.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { execSync } from "node:child_process";
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import type { Plugin } from "vite";
|
||||
|
||||
const suffix = ".css.ts";
|
||||
|
||||
/**
|
||||
* 生成主题输入
|
||||
* @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, mode: string): { [key: string]: string } {
|
||||
const hash = crypto.randomBytes(6).toString("hex");
|
||||
const tmpDir = `${outDir}/tmp-${hash}`; // 输出目录下的临时目录
|
||||
fs.mkdirSync(tmpDir, { recursive: true });
|
||||
|
||||
const input: { [key: string]: string } = {};
|
||||
const themeEntries = fs.readdirSync(themeDir, { withFileTypes: true });
|
||||
const devTheme = process.env.DEV_THEME || "dark"; // 开发模式仅打包单个颜色主题
|
||||
|
||||
for (const entry of themeEntries) {
|
||||
// 目录下所有的 css.ts 文件都作为主题入口
|
||||
if (entry.isFile() && entry.name.endsWith(suffix)) {
|
||||
const fileName = entry.name.replace(suffix, "");
|
||||
// 开发模式只打包 devTheme 主题
|
||||
if (mode === "dev" && fileName !== devTheme) continue;
|
||||
// 创建颜色主题的 css.ts 文件, vanilla-extract 需要这个文件后缀名并生成 css
|
||||
const tmpCssTs = path.join(tmpDir, `${fileName}${suffix}`);
|
||||
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}`);
|
||||
// 生成主题入口的 .ts 文件, 合并样式和颜色主题
|
||||
const tmpInputTs = path.join(tmpDir, `${fileName}.ts`);
|
||||
const stylesImport = `import "styles";`;
|
||||
const cssImport = `import "./${fileName}${suffix}";`;
|
||||
fs.writeFileSync(tmpInputTs, `${stylesImport}\n${cssImport}`);
|
||||
|
||||
input[fileName] = tmpInputTs;
|
||||
}
|
||||
}
|
||||
if (mode === "dev") {
|
||||
console.log("[themeInput] devTheme:", devTheme);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
function giteaThemeMetaInfo(nameGroup: string[]): string {
|
||||
const displayName = nameGroup.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
||||
return `gitea-theme-meta-info{--theme-display-name:"GitHub ${displayName}";}`; // 不要省略分号, 也不要追加任何变量, 否则 Gitea 不识别
|
||||
}
|
||||
|
||||
const prefix = "theme-github-";
|
||||
|
||||
/**
|
||||
* 生成主题文件
|
||||
* @important vite.rollupOptions.output 配置 `assetFileNames: "[name].[ext]"`
|
||||
*/
|
||||
export function themePlugin(): Plugin {
|
||||
return {
|
||||
name: "themePlugin",
|
||||
generateBundle(this, _, bundle) {
|
||||
let styles = "";
|
||||
for (const [key, value] of Object.entries(bundle)) {
|
||||
if (value.type === "chunk") {
|
||||
delete bundle[key]; // 删除 chunk
|
||||
} else {
|
||||
// 样式文件是通过入口导入的, 没有原始文件名
|
||||
if (value.originalFileNames.length === 0) {
|
||||
// 收集所有的样式文件(逻辑上只有一个)
|
||||
// vite 会在尾部添加注释, 后续会合并到颜色主题, 此处需要删除注释
|
||||
styles += value.source.toString().replace("/*$vite$:1*/", "");
|
||||
delete bundle[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
// 生成所有的主题文件
|
||||
for (const [key, value] of Object.entries(bundle)) {
|
||||
// 仅为了类型检查, 逻辑上输出中全是 asset 类型
|
||||
if (value.type === "asset") {
|
||||
const name = `${prefix}${key}`;
|
||||
const fileName = `${prefix}${value.fileName}`;
|
||||
const originalFileName = value.originalFileNames.pop();
|
||||
const type = value.type;
|
||||
// 合并样式文件和主题信息
|
||||
const meta = giteaThemeMetaInfo(key.split(".")[0].split("-"));
|
||||
const source = `${meta}${value.source.toString()}${styles}`;
|
||||
// 添加主题到输出
|
||||
this.emitFile({ name, fileName, source, type, originalFileName });
|
||||
// 自动颜色主题
|
||||
const isDark = key.endsWith("dark.css");
|
||||
const darkName = key.replace("light", "dark");
|
||||
const lightName = darkName.replace("dark", "light");
|
||||
const findTheme = isDark ? lightName : darkName;
|
||||
if (findTheme in bundle) {
|
||||
const autoName = `${prefix}${darkName.replace("dark", "auto")}`;
|
||||
const lightContent = `@import "./${prefix}${lightName}" (prefers-color-scheme: light);`;
|
||||
const darkContent = `@import "./${prefix}${darkName}" (prefers-color-scheme: dark);`;
|
||||
const nameGroup = key.split(".")[0].split("-").slice(0, -1);
|
||||
nameGroup.push("auto");
|
||||
const metaInfo = giteaThemeMetaInfo(nameGroup);
|
||||
this.emitFile({
|
||||
name: autoName,
|
||||
fileName: autoName,
|
||||
type: "asset",
|
||||
source: `${lightContent}\n${darkContent}\n${metaInfo}`,
|
||||
});
|
||||
}
|
||||
// 删除原始的样式文件, 自动颜色主题因为删除, 永远不会生成两次
|
||||
delete bundle[key];
|
||||
}
|
||||
}
|
||||
},
|
||||
writeBundle() {
|
||||
// 上传到服务器
|
||||
const server = process.env.SSH_SERVER;
|
||||
const user = process.env.SSH_USER || "root";
|
||||
const theme_path = process.env.GITEA_THEME_PATH;
|
||||
if (server && theme_path) {
|
||||
const cmd = `scp dist/${prefix}*.css ${user}@${server}:${theme_path}`;
|
||||
console.log("[themePlugin] exec:", cmd);
|
||||
try {
|
||||
execSync(cmd, { stdio: "inherit" });
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (_) {
|
||||
// continue regardless of error
|
||||
}
|
||||
} else {
|
||||
console.log("[themePlugin] no SSH_SERVER or GITEA_THEME_PATH, skip upload");
|
||||
}
|
||||
console.log("[themePlugin] exec end.");
|
||||
},
|
||||
};
|
||||
}
|
||||
2
src/functions/index.ts
Normal file
2
src/functions/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { scaleColorLight } from "./scss";
|
||||
export { fallbackVar } from "./var";
|
||||
27
src/functions/scss.ts
Normal file
27
src/functions/scss.ts
Normal 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);
|
||||
}
|
||||
13
src/functions/var.ts
Normal file
13
src/functions/var.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { CSSVarFunction } from "src/core/types";
|
||||
|
||||
type CSSFallbackVar = `var(--${string}, ${string})`;
|
||||
/**
|
||||
* 设置 CSS 变量的回退值
|
||||
* @param cssvar `var(--${string})`
|
||||
* @param fallback
|
||||
* @returns `var(--${string}, fallback)`
|
||||
*/
|
||||
export function fallbackVar(cssvar: CSSVarFunction, fallback: string): CSSFallbackVar {
|
||||
const var_name = cssvar.replace("var(--", "").replace(")", "");
|
||||
return `var(--${var_name}, ${fallback})`;
|
||||
}
|
||||
5
src/index.ts
Normal file
5
src/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export { defaultDarkChroma, defaultLightChroma } from "./core/chroma";
|
||||
export { defineTheme, type ThemeColor } from "./core/color";
|
||||
export type { Theme } from "./core/theme";
|
||||
export type { Ansi, Chroma, Console, Diff, Github, Message, Named, Other, Primary, Secondary } from "./types";
|
||||
export { otherThemeVars, themeVars } from "./types/vars";
|
||||
255
src/types/color/chroma.ts
Normal file
255
src/types/color/chroma.ts
Normal file
@@ -0,0 +1,255 @@
|
||||
// 注释来自 AI
|
||||
export const chroma = {
|
||||
textWhiteSpace: "text-white-space",
|
||||
err: null,
|
||||
keyword: {
|
||||
/** 所有关键字
|
||||
* @example class function var if else return
|
||||
*/
|
||||
self: null,
|
||||
/** 常量关键字
|
||||
* @example true false null
|
||||
*/
|
||||
constant: null,
|
||||
/** 声明关键字
|
||||
* @example var let const
|
||||
*/
|
||||
declaration: null,
|
||||
/** 命名空间关键字
|
||||
* @example package import export
|
||||
*/
|
||||
namespace: null,
|
||||
/** 伪关键字
|
||||
* @example this super __init__
|
||||
*/
|
||||
pseudo: null,
|
||||
/** 保留关键字
|
||||
* @example yield await goto
|
||||
*/
|
||||
reserved: null,
|
||||
/** 类型关键字
|
||||
* @example int float string bool
|
||||
*/
|
||||
type: null,
|
||||
},
|
||||
name: {
|
||||
/** 通用标识符 */
|
||||
self: null,
|
||||
/** 属性名
|
||||
* @example obj.foo HTML/XML 属性名 id="foo"
|
||||
*/
|
||||
attribute: null,
|
||||
/** 内置函数/对象
|
||||
* @example Math.PI Math.max
|
||||
*/
|
||||
builtin: null,
|
||||
/** 内置伪标识符
|
||||
* @example this super self
|
||||
*/
|
||||
builtinPseudo: null,
|
||||
/** 类名 */
|
||||
class: null,
|
||||
/** 常量名 */
|
||||
constant: null,
|
||||
/** 装饰器 */
|
||||
decorator: null,
|
||||
/** 实体名
|
||||
* @example HTML实体名 < > &
|
||||
*/
|
||||
entity: null,
|
||||
/** 异常类名 */
|
||||
exception: null,
|
||||
/** 函数名 */
|
||||
function: null,
|
||||
/** 魔术方法名
|
||||
* @example __init__ __str__
|
||||
*/
|
||||
functionMagic: null,
|
||||
/** 对象属性 */
|
||||
property: null,
|
||||
/** 标签名
|
||||
* @example 跳转标签
|
||||
*/
|
||||
label: null,
|
||||
/** 命名空间 */
|
||||
namespace: null,
|
||||
/** 其他未归类的标识符 */
|
||||
other: null,
|
||||
/** 标签名
|
||||
* @example 跳转标签
|
||||
*/
|
||||
tag: null,
|
||||
/** 变量名 */
|
||||
variable: null,
|
||||
/** 类变量 */
|
||||
variableClass: null,
|
||||
/** 全局变量 */
|
||||
variableGlobal: null,
|
||||
/** 实例变量 */
|
||||
variableInstance: null,
|
||||
/** 魔术变量
|
||||
* @example __name__ __doc__
|
||||
*/
|
||||
variableMagic: null,
|
||||
},
|
||||
literal: {
|
||||
/** 通用字面量 */
|
||||
self: null,
|
||||
/** 日期字面量
|
||||
* @example SQL 日期
|
||||
*/
|
||||
date: null,
|
||||
},
|
||||
string: {
|
||||
/** 通用字符串 */
|
||||
self: null,
|
||||
/** 字符串前缀/后缀
|
||||
* @example f"..." 的 f
|
||||
*/
|
||||
affix: null,
|
||||
/** 反引号字符串
|
||||
* @example `string`
|
||||
*/
|
||||
backtick: null,
|
||||
/** 字符字面量
|
||||
* @example 'a'
|
||||
*/
|
||||
char: null,
|
||||
/** 字符串分隔符
|
||||
* @example 引号自身
|
||||
*/
|
||||
delimiter: null,
|
||||
/** 文档字符串
|
||||
* @example """docstring"""
|
||||
*/
|
||||
doc: null,
|
||||
/** 双引号字符串
|
||||
* @example "string"
|
||||
*/
|
||||
double: null,
|
||||
/** 转义字符
|
||||
* @example \n \t
|
||||
*/
|
||||
escape: null,
|
||||
/** 定界字符串
|
||||
* @example <<EOF EOF>>
|
||||
*/
|
||||
heredoc: null,
|
||||
/** 插值字符串
|
||||
* @example ${name}
|
||||
*/
|
||||
interpol: null,
|
||||
/** 其他类型字符串 */
|
||||
other: null,
|
||||
/** 正则表达式字面量
|
||||
* @example /^abc/
|
||||
*/
|
||||
regex: null,
|
||||
/** 单引号字符串
|
||||
* @example 'string'
|
||||
*/
|
||||
single: null,
|
||||
/** 符号字符串
|
||||
* @example ruby 的 :symbol
|
||||
*/
|
||||
symbol: null,
|
||||
},
|
||||
number: {
|
||||
/** 通用数字 */
|
||||
self: null,
|
||||
/** 二进制数字
|
||||
* @example 0b1010
|
||||
*/
|
||||
bin: null,
|
||||
/** 浮点数
|
||||
* @example 1.23
|
||||
*/
|
||||
float: null,
|
||||
/** 十六进制数字
|
||||
* @example 0x123
|
||||
*/
|
||||
hex: null,
|
||||
/** 普通整数
|
||||
* @example 123
|
||||
*/
|
||||
integer: null,
|
||||
/** 长整数
|
||||
* @example 123L
|
||||
*/
|
||||
integerLong: null,
|
||||
/** 八进制数字
|
||||
* @example 0o123
|
||||
*/
|
||||
oct: null,
|
||||
},
|
||||
operator: {
|
||||
/** 运算符
|
||||
* @example + - * / =
|
||||
*/
|
||||
self: null,
|
||||
/** 单词运算符
|
||||
* @example and or not in is
|
||||
*/
|
||||
word: null,
|
||||
},
|
||||
/** 标点符号
|
||||
* @example , . : ; ( ) [ ] { }
|
||||
*/
|
||||
punctuation: null,
|
||||
comment: {
|
||||
/** 通用注释 */
|
||||
self: null,
|
||||
/** Hashbang 注释
|
||||
* @example #!/bin/bash
|
||||
*/
|
||||
hashbang: null,
|
||||
/** 多行注释 */
|
||||
multiline: null,
|
||||
/** 预处理器注释
|
||||
* @example #include <stdio.h>
|
||||
*/
|
||||
preproc: null,
|
||||
/** 预处理器文件注释
|
||||
* @example 如 python 的编码声明 # -*- coding: utf-8 -*-
|
||||
*/
|
||||
preprocFile: null,
|
||||
/** 单行注释 */
|
||||
single: null,
|
||||
/** 特殊注释
|
||||
* @example JavaDoc 的 `@param`
|
||||
*/
|
||||
special: null,
|
||||
},
|
||||
generic: {
|
||||
/** 通用文本容器 */
|
||||
self: null,
|
||||
/** 被删除的内容 */
|
||||
deleted: null,
|
||||
/** 强调文本 (斜体) */
|
||||
emph: null,
|
||||
/** 错误信息 */
|
||||
error: null,
|
||||
/** 标题
|
||||
* @example Markdown 标题 #
|
||||
*/
|
||||
heading: null,
|
||||
/** 新增内容 */
|
||||
inserted: null,
|
||||
/** 程序输出文本 */
|
||||
output: null,
|
||||
/** 交互式提示符
|
||||
* @example shell 的 $
|
||||
*/
|
||||
prompt: null,
|
||||
/** 强调文本 (粗体) */
|
||||
strong: null,
|
||||
/** 子标题
|
||||
* @example Markdown 子标题 ##
|
||||
*/
|
||||
subheading: null,
|
||||
/** 堆栈跟踪信息 */
|
||||
traceback: null,
|
||||
/** 下划线文本 */
|
||||
underline: null,
|
||||
},
|
||||
};
|
||||
49
src/types/color/console.ts
Normal file
49
src/types/color/console.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
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 = {
|
||||
/** Action 页面日志部分字体颜色 */
|
||||
fg: {
|
||||
/** 亮色用于标题或步骤标题激活时 */
|
||||
self: null,
|
||||
/** 暗色用于副标题或步骤标题 */
|
||||
subtle: null,
|
||||
},
|
||||
/** Action 页面日志部分背景色 */
|
||||
bg: null,
|
||||
/** Action 页面日志部分边框色 */
|
||||
border: null,
|
||||
/** Action 页面日志部分步骤标题激活颜色 */
|
||||
activeBg: "color-console-active-bg",
|
||||
/** Action 页面日志部分步骤标题悬停颜色 */
|
||||
hoverBg: "color-console-hover-bg",
|
||||
/** Action 页面日志部分设置菜单颜色 */
|
||||
menu: {
|
||||
/** 菜单背景色 */
|
||||
bg: null,
|
||||
/** 菜单边框色 */
|
||||
border: null,
|
||||
},
|
||||
};
|
||||
30
src/types/color/diff.ts
Normal file
30
src/types/color/diff.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
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,
|
||||
};
|
||||
253
src/types/color/github.ts
Normal file
253
src/types/color/github.ts
Normal file
@@ -0,0 +1,253 @@
|
||||
export const github = {
|
||||
/** 用于 color 属性的颜色 */
|
||||
fgColor: {
|
||||
/** 强调色
|
||||
* @actions `actionViewRight` 右侧日志标题颜色
|
||||
* @issue `prBranch` 分支名称文本颜色
|
||||
* @repo `repoTopic` 仓库主题标签文本颜色
|
||||
* @actions `actions` 分支标签按钮文本颜色
|
||||
* @actions `actionViewHeader` 分支标签按钮文本颜色
|
||||
*/
|
||||
accent: null,
|
||||
/** 成功的文本颜色
|
||||
* @issue `button` 重新开启按钮文本颜色
|
||||
* @label `label` 绿色标签的文本颜色
|
||||
*/
|
||||
success: null,
|
||||
/** 完成的文本颜色
|
||||
* @issue `button` 关闭工单按钮文本颜色
|
||||
* @svg `issueClosed` 工单已关闭图标颜色
|
||||
*/
|
||||
done: null,
|
||||
},
|
||||
/** 用于 background 属性的颜色 */
|
||||
bgColor: {
|
||||
accent: {
|
||||
/** 强调色
|
||||
* @diff 折叠/展开按钮的悬停颜色
|
||||
* @release `releaseTagMenu` 顶部栏左侧按钮激活背景色
|
||||
* @navbar `navbarRight` 头像管理员标识背景颜色
|
||||
* @dropdown `dropdown` emoji 的悬停背景色
|
||||
* @menu `paginationMenu` 分页菜单的激活背景色
|
||||
*/
|
||||
emphasis: null,
|
||||
/** 暗淡的背景颜色
|
||||
* @issue `prBranch` 分支名称背景颜色
|
||||
* @repo `repoTopic` 仓库主题标签背景颜色
|
||||
* @actions `actions` 分支标签按钮背景颜色
|
||||
* @actions `actionViewHeader` 分支标签按钮背景颜色
|
||||
* @notification `notification` 通知列表悬停时的背景颜色
|
||||
*/
|
||||
muted: null,
|
||||
},
|
||||
success: {
|
||||
/** 成功的背景颜色
|
||||
* @issue `babel` 重新开启图标背景颜色
|
||||
* @issue `prMerge` 合并提交的图标背景色
|
||||
*/
|
||||
emphasis: null,
|
||||
},
|
||||
done: {
|
||||
/** 完成的背景颜色
|
||||
* @issue `babel` 工单已关闭图标背景颜色
|
||||
*/
|
||||
emphasis: null,
|
||||
},
|
||||
},
|
||||
borderColor: {
|
||||
accent: {
|
||||
/** 强调色
|
||||
* @input `input` 输入框被选中时的边框颜色
|
||||
* @clone `clone` 克隆地址框被选中时的边框颜色
|
||||
* @issue `comment` 评论框被选中时的边框颜色
|
||||
* @actions `actionViewLeft` 左侧子作业激活伪元素颜色
|
||||
* @menu `verticalMenu` 垂直菜单项激活时左侧的伪元素颜色
|
||||
* @dropdown `selectionDropdown` 选择输入框的内部边框颜色
|
||||
* @notification `notification` 通知列表悬停时的左边框颜色
|
||||
*/
|
||||
emphasis: null,
|
||||
},
|
||||
attention: {
|
||||
/** 注意的边框颜色
|
||||
* @label `label` 黄色/橙色标签的边框色
|
||||
*/
|
||||
emphasis: null,
|
||||
},
|
||||
success: {
|
||||
/** 成功的边框颜色
|
||||
* @label `label` 绿色标签的边框色
|
||||
*/
|
||||
emphasis: null,
|
||||
},
|
||||
done: {
|
||||
/** 完成的边框颜色
|
||||
* @label `label` 红色/紫色标签的边框色
|
||||
*/
|
||||
emphasis: null,
|
||||
},
|
||||
},
|
||||
button: {
|
||||
/** 普通按钮 */
|
||||
default: {
|
||||
bgColor: {
|
||||
/** 静止色
|
||||
* @button `baseButton` 默认按钮激活颜色
|
||||
*/
|
||||
active: null,
|
||||
},
|
||||
},
|
||||
/** 主色调按钮 */
|
||||
primary: {
|
||||
fgColor: {
|
||||
/** 静止色
|
||||
* @button `primaryStyle` `primaryHoverStyle` 按钮文本颜色
|
||||
* @setting `tinyHoverStyle` 按钮的悬停文本颜色
|
||||
*/
|
||||
rest: null,
|
||||
/** 强调色 (Github 没有此颜色, 为本主题自定义, 需自行设置)
|
||||
* @setting `tinyStyle` 按钮的文本颜色
|
||||
*/
|
||||
accent: null,
|
||||
},
|
||||
bgColor: {
|
||||
/** 静止色
|
||||
* @button `primaryStyle` 按钮颜色
|
||||
*/
|
||||
rest: null,
|
||||
/** 悬停色
|
||||
* @button `primaryHoverStyle` 按钮悬停颜色
|
||||
* @setting `tinyHoverStyle` 按钮的悬停背景颜色
|
||||
*/
|
||||
hover: null,
|
||||
},
|
||||
borderColor: {
|
||||
/** 静止色
|
||||
* @button `primaryStyle` 按钮边框颜色
|
||||
*/
|
||||
rest: null,
|
||||
/** 悬停色
|
||||
* @button `primaryHoverStyle` 按钮悬停边框颜色
|
||||
* @setting `tinyHoverStyle` 按钮的悬停边框颜色
|
||||
*/
|
||||
hover: null,
|
||||
},
|
||||
},
|
||||
danger: {
|
||||
fgColor: {
|
||||
/** 静止色
|
||||
* @button `redButton` 红色按钮文本颜色
|
||||
*/
|
||||
rest: null,
|
||||
/** 悬停色
|
||||
* @button `redButton` 红色按钮悬停文本颜色
|
||||
*/
|
||||
hover: null,
|
||||
},
|
||||
bgColor: {
|
||||
/** 静止色
|
||||
* @button `redButton` 红色按钮颜色
|
||||
*/
|
||||
rest: null,
|
||||
/** 悬停色
|
||||
* @button `redButton` 红色按钮悬停颜色
|
||||
*/
|
||||
hover: null,
|
||||
},
|
||||
borderColor: {
|
||||
/** 悬停色
|
||||
* @button `redButton` 红色按钮悬停边框颜色
|
||||
*/
|
||||
hover: null,
|
||||
},
|
||||
},
|
||||
star: {
|
||||
/** 已标星的星星颜色 */
|
||||
iconColor: null,
|
||||
},
|
||||
},
|
||||
control: {
|
||||
bgColor: {
|
||||
/** 背景色
|
||||
* @issue `timeline` 时间线标签背景色
|
||||
*/
|
||||
rest: null,
|
||||
},
|
||||
transparent: {
|
||||
bgColor: {
|
||||
/** 悬停色
|
||||
* @clone `clone` 克隆按钮下按钮组和面板操作列表的悬停背景颜色
|
||||
* @input `inputAction` 输入框动作按钮的悬停背景颜色
|
||||
* @dropdown `dropdown` 下拉框子项的悬停背景颜色
|
||||
* @menu `verticalMenu` 垂直菜单项的悬停背景颜色
|
||||
* @menu `menu` 菜单项的悬停背景颜色
|
||||
* @menu `secondaryMenu` 二级菜单按钮的悬停背景颜色
|
||||
* @repo `repoHeader` 仓库标题的悬停背景颜色
|
||||
* @commit `commit` 提交信息的 Action 按钮的悬停背景颜色
|
||||
* @filelist `repoFiles` README 栏的按钮的悬停背景颜色
|
||||
* @issue `issueSidebar` 操作按钮的悬停背景颜色
|
||||
* @issue `issueList` 头部菜单左侧开启关闭菜单的悬停背景颜色
|
||||
* @dashboard `dashboard` 仓库列表项目的悬停背景颜色
|
||||
* @notification `notification` 通知列表的按钮悬停背景颜色
|
||||
*/
|
||||
hover: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
shadow: {
|
||||
floating: {
|
||||
/** 悬浮阴影
|
||||
* @tippy `tippyBox` 悬浮框阴影
|
||||
* @dropdown `dropdown` 下拉框阴影
|
||||
* @dashboard `dashboard` 仓库/组织切换按钮和列表边框和阴影
|
||||
* @heatmap `heatmap` 热力图阴影
|
||||
* @heatmap `activity` 动态活动阴影
|
||||
*/
|
||||
small: null,
|
||||
},
|
||||
resting: {
|
||||
/** 静止阴影
|
||||
* @button `primaryStyle` 主色调按钮阴影
|
||||
* @button `redButton` 红色按钮悬浮阴影
|
||||
* @setting `button` 红色按钮阴影
|
||||
*/
|
||||
small: null,
|
||||
},
|
||||
},
|
||||
underlineNav: {
|
||||
borderColor: {
|
||||
/** 下划线导航栏的边框颜色
|
||||
* @clone `clone` 按钮组的按钮下划线颜色
|
||||
* @menu `secondaryMenu` 二级菜单按钮的下划线颜色
|
||||
* @filelist `repoFiles` README 栏的左边按钮下划线颜色
|
||||
*/
|
||||
active: null,
|
||||
},
|
||||
},
|
||||
/** 热力图 */
|
||||
contribution: {
|
||||
default: {
|
||||
/** 热力图方块的颜色 */
|
||||
bgColor: {
|
||||
num0: null,
|
||||
num1: null,
|
||||
num2: null,
|
||||
num3: null,
|
||||
num4: null,
|
||||
/** github 无此颜色需自行计算 */
|
||||
num5: null,
|
||||
},
|
||||
/** 热力图方块的内边框颜色 */
|
||||
borderColor: {
|
||||
num0: null,
|
||||
num1: null,
|
||||
num2: null,
|
||||
num3: null,
|
||||
num4: null,
|
||||
/** github 无此颜色需自行计算
|
||||
* @example 目前均取 num0 的值
|
||||
*/
|
||||
num5: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
8
src/types/color/index.ts
Normal file
8
src/types/color/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export { chroma } from "./chroma";
|
||||
export { ansi, console } from "./console";
|
||||
export { diff } from "./diff";
|
||||
export { github } from "./github";
|
||||
export { primary, secondary } from "./main";
|
||||
export { message } from "./message";
|
||||
export { named } from "./named";
|
||||
export { other, otherAuto } from "./other";
|
||||
25
src/types/color/main.ts
Normal file
25
src/types/color/main.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
const num = { num1: null, num2: null, num3: null, num4: null, num5: null, num6: null, num7: null };
|
||||
|
||||
const alpha = {
|
||||
num10: null,
|
||||
num20: null,
|
||||
num30: null,
|
||||
num40: null,
|
||||
num50: null,
|
||||
num60: null,
|
||||
num70: null,
|
||||
num80: null,
|
||||
num90: null,
|
||||
};
|
||||
|
||||
export const primary = { self: null, contrast: null, dark: num, light: num, alpha: alpha, hover: null, active: null };
|
||||
|
||||
export const secondary = {
|
||||
self: null,
|
||||
dark: { num8: null, num9: null, num10: null, num11: null, num12: null, num13: null, ...num },
|
||||
light: { num1: null, num2: null, num3: null, num4: null },
|
||||
alpha: alpha,
|
||||
button: null,
|
||||
hover: null,
|
||||
active: null,
|
||||
};
|
||||
8
src/types/color/message.ts
Normal file
8
src/types/color/message.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
const msg = { bg: null, border: null, text: null };
|
||||
|
||||
const error = { ...msg, bg: { self: null, active: null, hover: null } };
|
||||
const success = { ...msg };
|
||||
const warning = { ...msg };
|
||||
const info = { ...msg };
|
||||
|
||||
export const message = { error, success, warning, info };
|
||||
37
src/types/color/named.ts
Normal file
37
src/types/color/named.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
const baseColor = { self: null, light: null, dark: { num1: null, num2: null } };
|
||||
|
||||
const commitColor = {
|
||||
/** 提交哈希值颜色 */
|
||||
badge: {
|
||||
/** 边框色 */
|
||||
self: null,
|
||||
/** 背景色 */
|
||||
bg: null,
|
||||
/** 悬停时背景色 */
|
||||
hover: {
|
||||
bg: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const named = {
|
||||
/** 红色/提交警告签名颜色 */
|
||||
red: { ...commitColor, ...baseColor },
|
||||
/** 橙色/提交未匹配签名颜色 */
|
||||
orange: { ...commitColor, ...baseColor },
|
||||
/** 黄色/提交未信任签名颜色 */
|
||||
yellow: { ...commitColor, ...baseColor },
|
||||
olive: baseColor,
|
||||
/** 绿色/提交信任签名颜色 */
|
||||
green: { ...commitColor, ...baseColor },
|
||||
teal: baseColor,
|
||||
blue: baseColor,
|
||||
violet: baseColor,
|
||||
purple: baseColor,
|
||||
pink: baseColor,
|
||||
brown: baseColor,
|
||||
black: baseColor,
|
||||
grey: { self: null, light: null },
|
||||
gold: null,
|
||||
white: null,
|
||||
};
|
||||
154
src/types/color/other.ts
Normal file
154
src/types/color/other.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
export const otherAuto = {
|
||||
/** 未知 */
|
||||
git: null,
|
||||
light: {
|
||||
/** 不知道什么用, gitea css 中没有使用这个属性的 */
|
||||
mimicEnabled: "color-light-mimic-enabled",
|
||||
},
|
||||
};
|
||||
|
||||
export const other = {
|
||||
/** 主要背景色 */
|
||||
body: null,
|
||||
/** 页面底部状态栏背景色 */
|
||||
footer: null,
|
||||
/** Issue 等页面时间线的线颜色 */
|
||||
timeline: null,
|
||||
/** 一些盒子颜色, 比如仓库文件列表 */
|
||||
box: {
|
||||
/** 仓库文件列表最后一次提交, 头行背景色 */
|
||||
header: null,
|
||||
body: {
|
||||
/** 仓库文件列表背景色 */
|
||||
self: null,
|
||||
/** diff 按钮行行色 */
|
||||
highlight: null,
|
||||
},
|
||||
},
|
||||
/** 文本 */
|
||||
text: {
|
||||
/** 主文本/主标题颜色 */
|
||||
self: null,
|
||||
light: {
|
||||
/** 普通basic按钮的文本颜色 */
|
||||
self: null,
|
||||
/** 仓库文件列表的commit信息和时间文本 */
|
||||
num1: null,
|
||||
/** 副标题颜色 */
|
||||
num2: null,
|
||||
/** git 提交图里的提交时间文本 */
|
||||
num3: null,
|
||||
},
|
||||
/** 弹窗标题色/一些激活的标题色 */
|
||||
dark: null,
|
||||
},
|
||||
/** 输入框 */
|
||||
input: {
|
||||
/** 选中时的文字颜色 */
|
||||
text: null,
|
||||
background: null,
|
||||
/** 找不到, 不知道啥玩意, 似乎是和复选框有关的东西 */
|
||||
toggleBackgound: "color-input-toggle-background",
|
||||
border: {
|
||||
self: null,
|
||||
hover: null,
|
||||
},
|
||||
},
|
||||
light: {
|
||||
/** 多行下交替行的强调色, 例提交历史 */
|
||||
self: null,
|
||||
/** 基础按钮/标签的边框色 */
|
||||
border: null,
|
||||
},
|
||||
hover: {
|
||||
/** 按钮悬停背景色 */
|
||||
self: null,
|
||||
/** 仓库文件列表悬停背景色 */
|
||||
opaque: null,
|
||||
},
|
||||
/** 设置页面菜单项当前项的背景色 */
|
||||
active: null,
|
||||
/** 菜单背景色 */
|
||||
menu: null,
|
||||
/** 卡片背景色, 但是找不到元素, 可能是个人 README */
|
||||
card: null,
|
||||
/** Markdown 颜色 */
|
||||
markup: {
|
||||
/** 隔行背景色 */
|
||||
tableRow: "color-markup-table-row",
|
||||
code: {
|
||||
/** 代码块背景色 */
|
||||
block: null,
|
||||
/** 代码行背景色 */
|
||||
inline: null,
|
||||
},
|
||||
},
|
||||
/** 普通按钮的背景色 (basic 非 primary) */
|
||||
button: null,
|
||||
/** 代码页面背景色 */
|
||||
codeBg: "color-code-bg",
|
||||
/** 弹窗阴影 */
|
||||
shadow: {
|
||||
self: null,
|
||||
/** css 没有使用 */
|
||||
opaque: null,
|
||||
},
|
||||
/** 弹窗按钮行的背景色 */
|
||||
secondaryBg: "color-secondary-bg",
|
||||
/** 代码差异对比折叠行按钮背景色 */
|
||||
expandButton: "color-expand-button",
|
||||
/** 不知道 */
|
||||
placeholderText: "color-placeholder-text",
|
||||
/** 不知道, css 没有 */
|
||||
editorLineHighlight: "color-editor-line-highlight",
|
||||
/** 仓库项目页面列的背景色 */
|
||||
projectColumnBg: "color-project-column-bg",
|
||||
/** caret-color 属性 */
|
||||
caret: null,
|
||||
/** Issue 表情按钮 */
|
||||
reaction: {
|
||||
/** css 里没用 */
|
||||
bg: null,
|
||||
/** 悬停时颜色 */
|
||||
hoverBg: "color-reaction-hover-bg",
|
||||
/** 点击后颜色 */
|
||||
activeBg: "color-reaction-active-bg",
|
||||
},
|
||||
/** 鼠标悬浮时的提示文本, 比如提交的具体时间, 任务状态等 */
|
||||
tooltip: {
|
||||
text: null,
|
||||
bg: null,
|
||||
},
|
||||
/** 顶部导航栏(用户导航栏) */
|
||||
nav: {
|
||||
/** 背景色 */
|
||||
bg: null,
|
||||
/** 悬停时背景色 */
|
||||
hoverBg: "color-nav-hover-bg",
|
||||
/** color 颜色 */
|
||||
text: null,
|
||||
},
|
||||
/** 顶部二级导航栏背景色(仓库导航栏等) */
|
||||
secondaryNavBg: "color-secondary-nav-bg",
|
||||
/** 普通标签 */
|
||||
label: {
|
||||
text: null,
|
||||
bg: null,
|
||||
hoverBg: "color-label-hover-bg",
|
||||
/** css 没用 */
|
||||
activeBg: "color-label-active-bg",
|
||||
},
|
||||
/** 不知道. 似乎和最后一次 review 相关的边框色 */
|
||||
accent: null,
|
||||
/** 不知道. 似乎和最后一次 review 相关的背景色 */
|
||||
smallAccent: "color-small-accent",
|
||||
/** 不知道啥玩意, 跟文件预览内容行颜色有关系 */
|
||||
highlight: {
|
||||
/** 在行号前追加的伪元素颜色 */
|
||||
fg: null,
|
||||
/** 背景色 */
|
||||
bg: null,
|
||||
},
|
||||
/** 叠加背景色, 比如弹窗时遮蔽页面其他部分的背景色 */
|
||||
overlayBackdrop: "color-overlay-backdrop",
|
||||
};
|
||||
23
src/types/index.ts
Normal file
23
src/types/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import type { MapLeafNodes } from "src/core/types";
|
||||
import * as color from "./color";
|
||||
|
||||
/** 代码高亮色 */
|
||||
export type Chroma = MapLeafNodes<typeof color.chroma, string>;
|
||||
/** 主色调(强调色) */
|
||||
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>;
|
||||
/** Actions 日志 ANSI 颜色 */
|
||||
export type Ansi = MapLeafNodes<typeof color.ansi, string>;
|
||||
/** Actions 颜色 */
|
||||
export type Console = MapLeafNodes<typeof color.console, string>;
|
||||
/** 代码差异对比颜色 */
|
||||
export type Diff = MapLeafNodes<typeof color.diff, string>;
|
||||
/** 其他颜色 */
|
||||
export type Other = MapLeafNodes<typeof color.other, string>;
|
||||
/** 仅限本主题的 Github 颜色 */
|
||||
export type Github = MapLeafNodes<typeof color.github, string>;
|
||||
53
src/types/vars.ts
Normal file
53
src/types/vars.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { createGlobalThemeContract } from "@vanilla-extract/css";
|
||||
import * as color from "./color";
|
||||
|
||||
function varMapper(prefix: string | null = null) {
|
||||
return (value: string | null, path: string[]) => {
|
||||
if (value === null) {
|
||||
path = path.filter(item => item !== "self");
|
||||
path = path.map(item => item.replace(/^num/, ""));
|
||||
value = path.join("-");
|
||||
}
|
||||
if (prefix) value = `${prefix}-${value}`;
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
const vars = {
|
||||
isDarkTheme: "is-dark-theme",
|
||||
chroma: color.chroma,
|
||||
color: {
|
||||
...color.other,
|
||||
...color.message,
|
||||
...color.named,
|
||||
primary: color.primary,
|
||||
secondary: color.secondary,
|
||||
/** Actions 日志 ANSI 颜色 */
|
||||
ansi: color.ansi,
|
||||
console: color.console,
|
||||
diff: color.diff,
|
||||
},
|
||||
github: color.github,
|
||||
};
|
||||
|
||||
const otherVars = { border: { radius: null }, color: { ...color.otherAuto } };
|
||||
|
||||
const customVars = {
|
||||
branchMenuWidth: "branch-menu-width",
|
||||
cloneMenuWidth: "clone-menu-width",
|
||||
userMenuWidth: "user-menu-width",
|
||||
explore: { repolistColumns: "explore-repolist-columns", userlistColumns: "explore-userlist-columns" },
|
||||
userRepolistColumns: "user-repolist-columns",
|
||||
org: { repolistColumns: "org-repolist-columns", userlistColumns: "org-userlist-columns" },
|
||||
};
|
||||
|
||||
const themeInfo = {
|
||||
version: null,
|
||||
};
|
||||
|
||||
export const themeVars = createGlobalThemeContract(vars, varMapper());
|
||||
export const otherThemeVars = createGlobalThemeContract(otherVars, varMapper());
|
||||
export const customThemeVars = createGlobalThemeContract(customVars, varMapper("custom"));
|
||||
export const themeInfoVars = createGlobalThemeContract(themeInfo, varMapper("theme"));
|
||||
|
||||
export { css } from "@linaria/core";
|
||||
Reference in New Issue
Block a user