feat(chroma): 代码高亮重构 (#9)

* feat(chroma): 代码高亮重构

* todo

* release 亮色适配

* 发布页分支按钮高度修正

* chroma变量和修复注册页导航栏

* chroma 重构适配亮色

---------

Co-authored-by: lutinglt <lutinglt@users.noreply.github.com>
This commit is contained in:
鲁汀
2025-08-10 14:06:08 +08:00
committed by GitHub
parent 065d7893d8
commit dca1c34518
18 changed files with 835 additions and 295 deletions

View File

@@ -1,7 +1,8 @@
import { rgba, saturate } from "polished";
import { scaleColorLight } from "src/functions";
import type { Ansi, Console, Diff, Github, Message, Named, Other, Primary, Secondary } from "src/types";
import type { Ansi, Chroma, Console, Diff, Github, Message, Named, Other, Primary, Secondary } from "src/types";
import { themeVars } from "src/types/vars";
import { prettylightsDark, prettylightsLight } from "./prettylights";
import type { Theme } from "./theme";
type ThemeColor = {
@@ -57,7 +58,7 @@ type ThemeColor = {
/** 定义颜色, 用于生成颜色主题
* @example
* 文件名: "dark.css.tsx"
* 文件名: "dark.css.ts"
* import type { Console, Diff, Other } from "src/types";
* import { defineTheme, themeVars } from "src";
*
@@ -70,7 +71,6 @@ type ThemeColor = {
* ...
* }
* ...
* // 会经过 lightningcss 打包处理生成最终的 CSS
* export default defineTheme({
* isDarkTheme: true,
* primary: "#0969da",
@@ -80,7 +80,7 @@ type ThemeColor = {
* other,
* })
*/
export function defineTheme(themeColor: ThemeColor): Theme {
export function defineTheme(themeColor: ThemeColor, chroma: Chroma | null = null): Theme {
const brightDir = themeColor.isDarkTheme ? -1 : 1;
const primary: Primary = {
@@ -341,6 +341,7 @@ export function defineTheme(themeColor: ThemeColor): Theme {
return {
isDarkTheme: themeColor.isDarkTheme.toString(),
chroma: chroma || (themeColor.isDarkTheme ? prettylightsDark : prettylightsLight),
color: {
primary,
secondary,

262
src/core/prettylights.ts Normal file
View File

@@ -0,0 +1,262 @@
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.string,
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,
},
};
}
export const prettylightsDark = prettylights2Chroma({
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 prettylightsLight = prettylights2Chroma({
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",
}
})

View File

@@ -4,15 +4,6 @@ import type { MapLeafNodes, WithOptionalLayer } from "./types";
export type Theme = WithOptionalLayer<MapLeafNodes<typeof themeVars, string>>;
function stringToBoolean(str: string, name: string): boolean {
try {
return JSON.parse(str);
} catch (error) {
console.error(error);
throw new Error(`Invalid boolean value(${name}): ${str}`);
}
}
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";
@@ -42,7 +33,7 @@ const emoji = `
`;
export function createTheme(theme: Theme): void {
const isDarkTheme = stringToBoolean(theme.isDarkTheme, "isDarkTheme");
const isDarkTheme: boolean = JSON.parse(theme.isDarkTheme);
if (isDarkTheme) {
globalStyle(emoji, { filter: "invert(100%) hue-rotate(180deg)" });
}