diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3c64c96..e242438 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,16 +25,16 @@ jobs: - "vite.config.ts" - "package.json" - - uses: actions/setup-node@v6 + - uses: oven-sh/setup-bun@v2 with: - node-version: 24 + bun-version: "1.3.14" - name: Build theme id: build if: steps.changes.outputs.src == 'true' run: | - npm install - npm run build:ci + bun install + bun bundle:ci - name: Upload css assets if: steps.build.outcome == 'success' @@ -54,7 +54,7 @@ jobs: id: locales if: steps.build.outcome =='success' continue-on-error: true - run: npm run update:locale + run: bun update:locale - name: Upload locales assets if: steps.locales.outcome =='success' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a6fa80e..1318600 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,13 +11,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: actions/setup-node@v6 + - uses: oven-sh/setup-bun@v2 with: - node-version: 24 + bun-version: "1.3.14" - name: Build theme run: | - npm install - npm run release + bun install + bun release - name: Create release run: | tar -zcf dist/theme-github-base.tar.gz \ diff --git a/.gitignore b/.gitignore index 57794ac..88a4887 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ dist node_modules +bun.lock +bun.lockb package-lock.json .env .VSCodeCounter \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ec06bf0..8121b1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### ⚠️ Breaking Changes + +- Starting from this version, CSS nesting will no longer be expanded, which will reduce the volume by 40% and improve + loading speed,ensure styles are applied correctly by keeping Chrome/Edge >= 120, Firefox >= 121, Safari >= 16.5. + ### ✨ Feature - Add high contrast color themes. diff --git a/README.md b/README.md index 3be588d..9c1bcfd 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ accepted. > [!IMPORTANT] > -> Because the project uses new CSS features, ensure styles are applied correctly by keeping Chrome/Edge >= 105, -> Firefox >= 121, Safari >= 15.4 +> Because the project uses new CSS features, ensure styles are applied correctly by keeping Chrome/Edge >= 120, +> Firefox >= 121, Safari >= 16.5 1. Download the latest CSS theme file from the release page and place it in the `data/gitea/public/assets/css` directory (This directory may not be available by default and needs to be manually created) @@ -214,13 +214,13 @@ Add the following code at the beginning or end of the theme's CSS file You might want to use the development version of the theme instead of the released version -Please ensure you have Node.js environment installed, Node.js 24.12.0 or above is recommended +Please ensure you have Bun environment installed, Bun 1.3.14 or above is recommended ```bash git clone https://github.com/lutinglt/gitea-github-theme.git cd gitea-github-theme -npm install -npm run build +bun install +bun bundle ``` After compilation, theme files will be generated in the `dist` directory. You can place the theme files into the diff --git a/README_CN.md b/README_CN.md index bacc8b1..59607d2 100644 --- a/README_CN.md +++ b/README_CN.md @@ -35,7 +35,7 @@ Gitea 理论上小版本号变更不会修改前端布局, 所以主题的小版 > [!IMPORTANT] > -> 因为项目使用了 CSS 新特性, 确保样式正确应用需保持 Chrome/Edge >= 105, Firefox >= 121, Safari >= 15.4 +> 因为项目使用了 CSS 新特性, 确保样式正确应用需保持 Chrome/Edge >= 120, Firefox >= 121, Safari >= 16.5 1. 在发布页下载最新的 CSS 主题文件放入 `data/gitea/public/assets/css` 目录下 (默认可能没有此目录需手动创建) 2. 修改 `data/gitea/conf/app.ini`,并将 CSS 文件名去掉 `theme-` 的名称附加到 `[ui]` 下的 `THEMES` 末尾 @@ -208,13 +208,13 @@ THEMES = github-catppuccin-auto, github-catppuccin-latte, github-catppuccin-frap 也许你会想使用开发中的主题, 而不是发布的主题 -请确保你已经安装了 Node.js 环境, 推荐使用 Node.js 24.12.0 或以上版本 +请确保你已经安装了 Bun 环境, 推荐使用 Bun 1.3.14 或以上版本 ```bash git clone https://github.com/lutinglt/gitea-github-theme.git cd gitea-github-theme -npm install -npm run build +bun install +bun bundle ``` 编译完成后, 会在 `dist` 目录下生成主题文件, 你可以将主题文件放入 `gitea/public/assets/css` 目录下, 然后在 diff --git a/bunfig.toml b/bunfig.toml new file mode 100644 index 0000000..fd430c5 --- /dev/null +++ b/bunfig.toml @@ -0,0 +1,3 @@ +# bunfig.toml +[install] +registry = "https://registry.npmjs.org" \ No newline at end of file diff --git a/package.json b/package.json index 9b33bf7..a98e5a0 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,14 @@ { - "name": "gitea-github-theme", + "name": "@lutinglt/gitea-github-theme", + "exports": { + "./theme.config.ts": "./theme.config.ts", + "./core": "./src/index.ts", + "./vite-plugin": "./src/vite-plugin/index.ts", + "./styles": "./styles/index.ts", + "./styles/common": "./styles/common/index.ts", + "./themes": "./themes/index.ts", + "./primer": "./primer/index.ts" + }, "version": "1.26.2", "license": "Apache-2.0", "author": { @@ -8,20 +17,19 @@ }, "type": "module", "scripts": { - "test": "vitest", - "lint": "eslint .", - "format": "prettier --write .", - "build": "tsgo -b -v && vite build", - "commit": "npm run format && npm run lint && npm run test && npm run build", - "version": "node scripts/version.ts", - "release": "npm run build && npm run update:locale", - "sync:theme": "node scripts/syncTheme.ts", - "update:primer": "node scripts/buildPrimerTSToken.ts", - "update:locale": "node scripts/translate.ts", - "update:gitea": "node scripts/updateGitea.ts", - "install:clean": "npm cache clean --force && rm -rf node_modules package-lock.json && npm install", - "build:ci": "npm run lint && npm run test && npm run build", - "build:dev": "npm run build && npm run sync:theme" + "lint": "bun eslint .", + "format": "bun prettier --write .", + "bundle": "tsgo -b -v && bunx --bun vite build", + "commit": "bun format && bun lint && bun test && bun bundle", + "version": "bun scripts/version.ts", + "release": "bun bundle && bun update:locale", + "sync:theme": "bun scripts/syncTheme.ts", + "update:primer": "bun scripts/buildPrimerTSToken.ts", + "update:locale": "bun scripts/translate.ts", + "update:gitea": "bun scripts/updateGitea.ts", + "install:clean": "rm -rf node_modules bun.lock bun.lockb && bun install", + "bundle:ci": "bun lint && bun vitest && bun bundle", + "bundle:dev": "bun bundle && bun sync:theme" }, "devDependencies": { "@catppuccin/palette": "^1.8.0", @@ -41,7 +49,6 @@ "prettier-plugin-organize-imports": "^4.3.0", "style-dictionary": "^5.4.1", "typescript-eslint": "^8.59.1", - "typescript-plugin-css-modules": "^5.2.0", "undici": "^7.0.0", "vite": "^8.0.5", "vitest": "^4.1.7" diff --git a/primer/index.ts b/primer/index.ts index 8f042c4..182c42d 100644 --- a/primer/index.ts +++ b/primer/index.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { MapLeafNodes } from "@gitea-github-theme/core"; +import type { MapLeafNodes } from "@lutinglt/gitea-github-theme/core"; import dark from "./dark"; import darkColorblind from "./dark-colorblind"; diff --git a/scripts/translate.ts b/scripts/translate.ts index 0243a83..11c6117 100644 --- a/scripts/translate.ts +++ b/scripts/translate.ts @@ -21,7 +21,7 @@ import dotenv from "dotenv"; import child_process from "node:child_process"; import fs from "node:fs"; import path from "node:path"; -import { pkg, rootDir, setGlobalProxy } from "./utils.ts"; +import { pkg, rootDir, setGlobalProxy } from "./utils"; dotenv.config({ quiet: true }); setGlobalProxy(); diff --git a/scripts/updateGitea.ts b/scripts/updateGitea.ts index 4d0085f..ce2aab2 100644 --- a/scripts/updateGitea.ts +++ b/scripts/updateGitea.ts @@ -19,7 +19,7 @@ import fs from "node:fs"; import path from "node:path"; -import { pkg, rootDir, setGlobalProxy } from "./utils.ts"; +import { pkg, rootDir, setGlobalProxy } from "./utils"; setGlobalProxy(); diff --git a/scripts/utils.ts b/scripts/utils.ts index 1cb0e89..977b041 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -20,7 +20,7 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { ProxyAgent, setGlobalDispatcher } from "undici"; -import pkg from "../package.json" with { type: "json" }; +import pkg from "../package.json"; export function setGlobalProxy() { const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || process.env.ALL_PROXY; diff --git a/scripts/version.ts b/scripts/version.ts index 9aec140..7f76c44 100644 --- a/scripts/version.ts +++ b/scripts/version.ts @@ -17,6 +17,6 @@ * limitations under the License. */ -import { pkg } from "./utils.ts"; +import { pkg } from "./utils"; console.log(pkg.version); diff --git a/src/styles/chroma.ts b/src/core/chroma.ts similarity index 100% rename from src/styles/chroma.ts rename to src/core/chroma.ts diff --git a/src/styles/codemirror.ts b/src/core/codemirror.ts similarity index 100% rename from src/styles/codemirror.ts rename to src/core/codemirror.ts diff --git a/src/core/css.ts b/src/core/css.ts new file mode 100644 index 0000000..76be425 --- /dev/null +++ b/src/core/css.ts @@ -0,0 +1,90 @@ +/*! + * Copyright (c) https://github.com/lutinglt + * + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { StyleRule } from "@vanilla-extract/css"; +import { transform } from "lightningcss"; +import { getCallerInfo } from "../utils"; +import { captureStyle } from "../vanilla-extract"; + +declare const CSSBrand: unique symbol; +type CSSObject = { [CSSBrand]: true }; +type CSSPrimitive = string | number; +type CSSInterpolation = CSSPrimitive | CSSObject | undefined; +type SelectorStyleRule = + | StyleRule + | { + [key: string]: StyleRule | SelectorStyleRule; + }; + +const SHARED_CACHE_KEY = "__GITEA_GITHUB_THEME_CSS_CACHE__"; +const g = globalThis as Record; +const cssCache: string[] = (g[SHARED_CACHE_KEY] as string[]) || (g[SHARED_CACHE_KEY] = []); + +/** + * css 模板字符串 —— 类式 linaria 的 css tag,用于 vscode-styled-components 高亮。 + * 运行时校验 CSS 语法,收集输出到缓存,供 flushCSS() 获取。 + */ +export function css(strings: TemplateStringsArray, ...values: CSSInterpolation[]): string { + const result = strings.reduce((acc, s, i) => acc + s + String(values[i] ?? ""), ""); + // 构建时校验 CSS 语法 + transform({ filename: getCallerInfo(1), code: Buffer.from(result) }); + cssCache.push(result); + return result; +} + +/** 构建时一次性获取所有通过 css() 收集的 CSS */ +export function flushCSS(): string { + const all = cssCache.join("\n"); + cssCache.length = 0; + return all; +} + +/** cssStyle 用于 css 模板字符串的插值 + * 提取可复用的样式, 并保留 vanilla-extract 的类型检查 + * - 属性访问:保留原值(如 style.padding → "0px 6px") + * - 字符串插值:自动输出 CSS 片段(如 `${style}` → "padding:0px 6px;") + */ +export function cssStyle(input: T): T & CSSObject { + const flat: Record = {}; + const nested: Record = {}; + + // Object.entries 对无索引签名的 StyleRule 只能返回 any/unknown, + // 这里做最小断言:entry 的值是 CSS 叶子值(string|number)或嵌套对象 + for (const [key, val] of Object.entries(input) as [string, CSSPrimitive | SelectorStyleRule][]) { + if (val === null || val === undefined) continue; + if (typeof val === "object") { + nested[key] = cssStyle(val); + } else { + flat[key] = val; + } + } + + // 构建 CSS 字符串 + const cssParts: string[] = []; + if (Object.keys(flat).length > 0) { + cssParts.push(captureStyle(flat)); + } + for (const [key, val] of Object.entries(nested)) { + cssParts.push(`${key}{${String(val)}}`); + } + const cssText = cssParts.join(""); + input.toString = () => cssText; + + return input as T & CSSObject; +} diff --git a/src/core/index.ts b/src/core/index.ts index 69662a0..e1bf172 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -17,6 +17,10 @@ * limitations under the License. */ +export { createChroma } from "./chroma"; +export { createCodeMirror } from "./codemirror"; +export { css, cssStyle, flushCSS } from "./css"; +export { createThemeMetaInfo, type ColorblindType, type GiteaThemeMeta } from "./meta"; export { createTheme, defineTheme } from "./theme"; export type { Theme, ThemeVars } from "./theme"; export type { CSSVarFunction, MapLeafNodes } from "./types"; diff --git a/src/styles/meta.ts b/src/core/meta.ts similarity index 100% rename from src/styles/meta.ts rename to src/core/meta.ts diff --git a/src/core/theme.ts b/src/core/theme.ts index a50d033..aab564c 100644 --- a/src/core/theme.ts +++ b/src/core/theme.ts @@ -18,13 +18,24 @@ */ import { createGlobalTheme, globalKeyframes, globalStyle } from "@vanilla-extract/css"; +import pkg from "../../package.json"; import type { GiteaColor, GitHubColor, ThemeColor } from "../palette"; import { gitea2ThemeVars, github2ThemeColor, primer2Chroma, primer2CodeMirror, theme2ThemeVars } from "../palette"; import selectors from "../selectors"; -import { createChroma, createCodeMirror } from "../styles"; import { otherThemeVars, syntaxVars, themeVars, type Syntax } from "../types"; +import { createChroma } from "./chroma"; +import { createCodeMirror } from "./codemirror"; import type { MapLeafNodes } from "./types"; +function getThemeVersion(): string { + // 版本号: 版本号.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"); + return `${pkg.version}.${year}${month}${day}`; +} + export type ThemeVars = { isDarkTheme: boolean } & MapLeafNodes; export type ThemeColors = | { colorType: "github"; themeColor: GitHubColor } @@ -41,8 +52,8 @@ export type Theme = { * - "theme": GiteaGitHubTheme 用于简化 Gitea 颜色变量设置的配色, 使用 Gitea 的代码语法高亮色 * * @example - * import type { Console, Diff, Other, Github, ThemeColor, Syntax } from "@gitea-github-theme/core"; - * import { defineTheme, themeVars } from "@gitea-github-theme/core"; + * import type { Console, Diff, Other, Github, ThemeColor, Syntax } from "@lutinglt/gitea-github-theme/core"; + * import { defineTheme, themeVars } from "@lutinglt/gitea-github-theme/core"; * * const console: Console = { * fg: { @@ -77,9 +88,6 @@ export function defineTheme(themeColors: ThemeColors): Theme { }; } -// vite define 编译时注入的常量 -declare const __THEME_VERSION__: string; - export function createTheme(theme: Theme): void { const { isDarkTheme, ...themeVarsColor } = theme.colorType === "github" @@ -90,7 +98,7 @@ export function createTheme(theme: Theme): void { // 注入主题标识和版本号 createGlobalTheme(selectors.root, { - theme: { version: `"${__THEME_VERSION__}"` }, + theme: { version: `"${getThemeVersion()}"` }, is: { dark: { theme: isDarkTheme.toString() } }, }); // 全局主题变量 diff --git a/src/css.ts b/src/css.ts deleted file mode 100644 index 88c355a..0000000 --- a/src/css.ts +++ /dev/null @@ -1,57 +0,0 @@ -/*! - * Copyright (c) https://github.com/lutinglt - * - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as lightningcss from "lightningcss"; -import type { CSSObject } from "./toCSS"; - -const sharedCacheKey = "__GITEA_GITHUB_THEME_CSS_CACHE__"; -const g = globalThis as Record; -const cssCache: string[] = (g[sharedCacheKey] as string[]) || (g[sharedCacheKey] = []); - -type CSSInterpolation = string | number | boolean | CSSObject | undefined | null; - -function getCallerInfo(): string { - const stack = new Error().stack?.split("\n") || []; - // stack[0] = "Error" - // stack[1] = " at getCallerInfo (css.ts:...)" - // stack[2] = " at css (css.ts:...)" - // stack[3] = " at (styles/components/heatmap.ts:23:18)" ← 目标 - const frame = stack[3] || ""; - const match = frame.match(/\((.+?):(\d+):(\d+)\)/) ?? frame.match(/at\s+(.+?):(\d+):(\d+)/); - return match ? `${match[1]}:${match[2]}` : frame.trim() || "unknown"; -} - -/** - * css 模板字符串 —— 类式 linaria 的 css tag,用于 vscode-styled-components 高亮。 - * 运行时校验 CSS 语法,收集输出到缓存,供 flushCSS() 获取。 - */ -export function css(strings: TemplateStringsArray, ...values: CSSInterpolation[]): string { - const result = strings.reduce((acc, s, i) => acc + s + String(values[i] ?? ""), ""); - // 构建时校验 CSS 语法 - lightningcss.transform({ filename: getCallerInfo(), code: Buffer.from(result) }); - cssCache.push(result); - return result; -} - -/** 构建时一次性获取所有通过 css() 收集的 CSS */ -export function flushCSS(): string { - const all = cssCache.join("\n"); - cssCache.length = 0; - return all; -} diff --git a/src/index.ts b/src/index.ts index 061b231..f26513b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,8 +19,7 @@ import selectors from "./selectors"; -export { createTheme, defineTheme, type MapLeafNodes } from "./core"; -export { css, flushCSS } from "./css"; +export { css, cssStyle, defineTheme, type MapLeafNodes } from "./core"; export { extractVarName, scaleColorLight } from "./functions"; export { catppuccin2Syntax, @@ -30,10 +29,8 @@ export { primer2GitHubColor, } from "./palette"; export type { DisplayColor, GitHubColor, GiteaColor, ThemeColor } from "./palette"; -export { createThemeMetaInfo } from "./styles"; -export { toCSS } from "./toCSS"; export { chromaVars, customThemeVars, otherThemeVars, syntaxVars, themeVars } from "./types"; export type { Ansi, Chroma, Console, Diff, GitHub, Message, Named, Other, Primary, Secondary, Syntax } from "./types"; export { deepOverride } from "./utils"; -export { defineThemeConfig } from "./vite-plugin"; +export { defineThemeConfig } from "./vite-plugin/themeConfig"; export { selectors }; diff --git a/src/palette/display.ts b/src/palette/display.ts index a876c90..352d317 100644 --- a/src/palette/display.ts +++ b/src/palette/display.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { Primer } from "@gitea-github-theme/primer"; +import type { Primer } from "@lutinglt/gitea-github-theme/primer"; import { saturate } from "polished"; import { scaleColorLight } from "../functions"; import { deepOverride } from "../utils"; diff --git a/src/palette/github.ts b/src/palette/github.ts index ac67f2a..f21c108 100644 --- a/src/palette/github.ts +++ b/src/palette/github.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { Primer } from "@gitea-github-theme/primer"; +import type { Primer } from "@lutinglt/gitea-github-theme/primer"; import { mix, saturate } from "polished"; import { scaleColorLight } from "../functions"; import type { Ansi, Console, Diff, GitHub, Message, Other } from "../types"; diff --git a/src/palette/primer.ts b/src/palette/primer.ts index aa592f2..955a153 100644 --- a/src/palette/primer.ts +++ b/src/palette/primer.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { Primer } from "@gitea-github-theme/primer"; +import type { Primer } from "@lutinglt/gitea-github-theme/primer"; import type { Chroma, CodeMirror } from "../types"; import { deepOverride } from "../utils"; import type { GitHubColor } from "./github"; diff --git a/src/styles/index.ts b/src/styles/index.ts deleted file mode 100644 index 57d5737..0000000 --- a/src/styles/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/*! - * Copyright (c) https://github.com/lutinglt - * - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { createChroma } from "./chroma"; -export { createCodeMirror } from "./codemirror"; -export { createThemeMetaInfo, type ColorblindType, type GiteaThemeMeta } from "./meta"; diff --git a/src/toCSS.ts b/src/toCSS.ts deleted file mode 100644 index 2d31a8e..0000000 --- a/src/toCSS.ts +++ /dev/null @@ -1,102 +0,0 @@ -/*! - * Copyright (c) https://github.com/lutinglt - * - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { StyleRule } from "@vanilla-extract/css"; -import { globalStyle } from "@vanilla-extract/css"; -import { removeAdapter, setAdapter } from "@vanilla-extract/css/adapter"; -import { endFileScope, setFileScope } from "@vanilla-extract/css/fileScope"; -import { transformCss } from "@vanilla-extract/css/transformCss"; - -/** 使用 vanilla-extract 适配器序列化一个扁平 StyleRule 为 CSS 属性行 */ -function captureStyleRule(style: StyleRule): string { - const captured: unknown[] = []; - - setAdapter({ - appendCss: css => captured.push(css), - registerClassName: () => {}, - registerComposition: () => {}, - markCompositionUsed: () => {}, - onEndFileScope: () => {}, - getIdentOption: () => "short", - }); - - setFileScope(""); - globalStyle("_x", style); - endFileScope(); - removeAdapter(); - - const css = transformCss({ - localClassNames: [], - composedClassLists: [], - cssObjs: captured as Parameters[0]["cssObjs"], - }).join(""); - - // 去掉 "_x { ... }" 外壳,只留内部属性 - const inner = css - .replace(/^_x\s*\{/, "") - .replace(/\}\s*$/, "") - .trim(); - return inner ? inner + ";" : ""; -} - -// ─── toCSS ────────────────────────────────────────────── - -type SelectorStyleRule = { - [key: string]: StyleRule | SelectorStyleRule; -}; - -type SelectorsStyleRule = StyleRule | SelectorStyleRule; - -declare const CSSBrand: unique symbol; -export type CSSObject = { [CSSBrand]: true }; - -/** - * 将 SelectorsStyleRule 转为可复用的对象: - * - 属性访问:保留原值(如 style.padding → "0px 6px") - * - 字符串插值:自动输出 CSS 片段(如 `${style}` → "padding:0px 6px;") - */ -export function toCSS(input: T): T & CSSObject { - const flat: Record = {}; - const nested: Record = {}; - - // Object.entries 对无索引签名的 StyleRule 只能返回 any/unknown, - // 这里做最小断言:entry 的值是 CSS 叶子值(string|number)或嵌套对象 - for (const [key, val] of Object.entries(input) as [string, string | number | SelectorsStyleRule][]) { - if (val === null || val === undefined) continue; - if (typeof val === "object") { - nested[key] = toCSS(val); - } else { - flat[key] = val; - } - } - - // 构建 CSS 字符串 - const cssParts: string[] = []; - if (Object.keys(flat).length > 0) { - cssParts.push(captureStyleRule(flat)); - } - for (const [key, val] of Object.entries(nested)) { - cssParts.push(`${key}{${String(val)}}`); - } - const cssText = cssParts.join(""); - - input.toString = () => cssText; - - return input as T & CSSObject; -} diff --git a/src/utils.ts b/src/utils.ts index 1a9a6af..a17b65f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -32,3 +32,26 @@ export function deepOverride(target: T, patch: DeepPartial) } return result; } +/** + * 从调用堆栈中获取调用者信息(文件名:行号)。 + * + * 堆栈帧结构(0-based): + * stack[0] = "Error" + * stack[1] = getCallerInfo 自身 ← 始终跳过 + * stack[2] = 直接调用者 ← skipFrames=0 时返回此行 + * stack[3] = 上层调用者 ← skipFrames=1 时返回此行 + * ... + * + * 每层中间函数由调用方自行声明需要跳过的帧数, + * 而非将调用深度硬编码在此函数中。 + * + * @param skipFrames 额外跳过的帧数(默认 0:返回直接调用者) + * @returns 格式 "path/file:line",无法解析时返回 "unknown" + */ +export function getCallerInfo(skipFrames: number = 0): string { + const stack = new Error().stack?.split("\n") || []; + const index = 2 + skipFrames; + const frame = stack[index] || stack[stack.length - 1] || ""; + const match = frame.match(/\((.+?):(\d+):(\d+)\)/) ?? frame.match(/at\s+(.+?):(\d+):(\d+)/); + return match ? `${match[1]}:${match[2]}` : frame.trim() || "unknown"; +} diff --git a/src/vanilla-extract.ts b/src/vanilla-extract.ts new file mode 100644 index 0000000..694d491 --- /dev/null +++ b/src/vanilla-extract.ts @@ -0,0 +1,69 @@ +/*! + * Copyright (c) https://github.com/lutinglt + * + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { StyleRule } from "@vanilla-extract/css"; +import { globalStyle } from "@vanilla-extract/css"; +import { removeAdapter, setAdapter } from "@vanilla-extract/css/adapter"; +import { endFileScope, setFileScope } from "@vanilla-extract/css/fileScope"; +import { transformCss } from "@vanilla-extract/css/transformCss"; +import { getCallerInfo } from "./utils"; + +type CSS = Parameters[0]["cssObjs"][number]; +type Composition = Parameters[0]["composedClassLists"][number]; + +/** 执行 vanilla-extract API 并序列化为 CSS 字符串 */ +export function compileCSS(compileFn: () => void): string { + const capturedCssObjs: CSS[] = []; + const localClassNames = new Set(); + const composedClassLists: Composition[] = []; + + setAdapter({ + appendCss: css => capturedCssObjs.push(css), + registerClassName: className => localClassNames.add(className), + registerComposition: composition => composedClassLists.push(composition), + markCompositionUsed: () => {}, + onEndFileScope: () => {}, + getIdentOption: + () => + ({ debugId }) => + `${debugId}`, + }); + setFileScope(getCallerInfo(1)); + + compileFn(); + + endFileScope(); + removeAdapter(); + + return transformCss({ + localClassNames: Array.from(localClassNames), + composedClassLists, + cssObjs: capturedCssObjs, + }).join("\n"); +} + +/** 使用 vanilla-extract 适配器序列化一个扁平 StyleRule 为 CSS 属性行 */ +export function captureStyle(style: StyleRule): string { + const css = compileCSS(() => globalStyle("_CAPTURED_STYLE", style)); + const inner = css + .replace(/^_CAPTURED_STYLE\s*\{/, "") + .replace(/\}\s*$/, "") + .trim(); + return inner ? inner + ";" : ""; +} diff --git a/src/vite-plugin.ts b/src/vite-plugin.ts deleted file mode 100644 index 3529f2b..0000000 --- a/src/vite-plugin.ts +++ /dev/null @@ -1,325 +0,0 @@ -/*! - * Copyright (c) https://github.com/lutinglt - * - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { removeAdapter, setAdapter } from "@vanilla-extract/css/adapter"; -import { endFileScope, setFileScope } from "@vanilla-extract/css/fileScope"; -import { transformCss } from "@vanilla-extract/css/transformCss"; -import * as lightningcss from "lightningcss"; -import crypto from "node:crypto"; -import fs from "node:fs"; -import path from "node:path"; -import { pathToFileURL } from "node:url"; -import { rolldown } from "rolldown"; -import type { PluginOption } from "vite"; -import type { Theme } from "./core"; -import { createTheme } from "./core"; -import { flushCSS } from "./css"; -import type { ColorblindType, GiteaThemeMeta } from "./styles"; -import { createThemeMetaInfo } from "./styles"; - -interface Composition { - identifier: string; - classList: string; -} - -type ThemeEntry = { - /** 主题名称 */ - themeName: string; - /** Gitea 主题 元数据 */ - meta: GiteaThemeMeta; - /** 主题颜色 */ - theme: Theme; -}; - -type AutoThemeEntry = { darkThemeName: string; lightThemeName: string }; - -type ThemeConfig = { - /** 主题名称, 用于生成文件名, 未指定时取 themes 中的键名 */ - themeName?: string; - /** 显示名称, 用于 Gitea UI 显示的名称 - * - 未指定时根据 themeName 生成 - * - 指定时将覆盖生成的名称, 仅包含主题插件前缀, 不包含主题系列名称 - */ - displayName?: string; - /** 色盲类型, 仅用于声明主题为色盲主题 */ - colorblindType?: ColorblindType; - theme: Theme; -}; - -type Themes = - | { - /** 主题系列的深色模式主题 */ - dark: ThemeConfig; - [themeKeyName: string]: ThemeConfig; - } - | { - /** 主题系列的浅色模式主题 */ - light: ThemeConfig; - [themeKeyName: string]: ThemeConfig; - }; - -type ThemeSeries = { - /** 主题系列名称, 做为前缀用于生成文件名和显示名称 */ - themeSeriesName: string; - /** 主题系列自动颜色主题配置 */ - autoTheme?: { - /** 自动颜色主题用于 Gitea UI 显示的名称 */ - displayName?: string; - /** 色盲类型, 仅用于声明主题为色盲主题 */ - colorblindType?: ColorblindType; - }; - /** 必须至少声明 dark/light 其中一个, 如果 dark & light 都声明了, 会生成自动颜色主题 */ - themes: Themes; -}; - -/** 定义主题配置 */ -export function defineThemeConfig(config: ThemeSeries[]): ThemeSeries[] { - // 检查主题系列名称是否重复 - const names = config.map(c => c.themeSeriesName); - const duplicates = names.filter((name, index) => names.indexOf(name) !== index); - if (duplicates.length > 0) { - throw new Error(`Duplicate themeSeriesName found: ${[...new Set(duplicates)].join(", ")}`); - } - return config; -} - -/** 使用 Vanilla Extract 的 adapter + transformCss 在 Node.js 中编译主题 CSS */ -function compileThemeCSS(compileFn: () => void): string { - const capturedCssObjs: Parameters[0]["cssObjs"] = []; - const localClassNames = new Set(); - const composedClassLists: Composition[] = []; - - setAdapter({ - appendCss: css => capturedCssObjs.push(css), - registerClassName: className => localClassNames.add(className), - registerComposition: composition => composedClassLists.push(composition), - markCompositionUsed: () => {}, - onEndFileScope: () => {}, - getIdentOption: - () => - ({ debugId }) => - `${debugId}`, - }); - setFileScope("theme.css.ts"); - - compileFn(); - - endFileScope(); - removeAdapter(); - - return transformCss({ - localClassNames: Array.from(localClassNames), - composedClassLists, - cssObjs: capturedCssObjs, - }).join("\n"); -} - -/** Gitea GitHub Theme 主题插件: 解析入口文件, 生成主题 */ -export function giteaGitHubThemePlugin(): PluginOption { - const PLUGIN_NAME = "GiteaGitHubThemePlugin"; - const PREFIX = "theme-github-"; - let themeEntries: ThemeEntry[]; - const autoThemeEntries = new Map(); - let themeVersion = ""; - let styles = ""; - - return { - name: PLUGIN_NAME, - - async config(userConfig) { - const root = userConfig.root || process.cwd(); - const entry = path.join(root, "theme.config.ts"); - const entryPath = path.isAbsolute(entry) ? entry : path.resolve(root, entry); - - // 提取 __THEME_VERSION__ 定义, 用于后续在 Node.js 中编译主题时注入 - const themeVersionDefine = userConfig.define?.__THEME_VERSION__; - if (typeof themeVersionDefine === "string") { - themeVersion = JSON.parse(themeVersionDefine); - } - - // 1. 创建临时目录 - const hash = crypto.randomBytes(6).toString("hex"); - const tmpDir = path.join(userConfig.build?.outDir || "dist", `.gitea-theme-tmp-${hash}`); - fs.mkdirSync(tmpDir, { recursive: true }); - - // 2. 使用 rolldown 打包入口文件为 ESM, 以便在 Node.js 中 import - // 第三方包标记为外部依赖, 运行时从项目的 node_modules 解析 - const resolveAlias: Record = {}; - if (userConfig.resolve?.alias) { - const aliases = userConfig.resolve.alias; - if (Array.isArray(aliases)) { - for (const alias of aliases) { - if (typeof alias.find === "string") { - resolveAlias[alias.find] = alias.replacement; - } - } - } else { - Object.assign(resolveAlias, aliases); - } - } - - const tmpBundle = path.join(tmpDir, "_themes_entry.mjs"); - const bundle = await rolldown({ - input: entryPath, - platform: "node", - // 第三方包标记为外部依赖, 运行时从项目的 node_modules 解析, 避免无谓打包提速 - external: id => { - if (id.startsWith(".") || path.isAbsolute(id)) return false; - // alias 路径 (如 "src/core", "themes/dark", "styles") 是项目内部模块, 需要打包 - if (Object.keys(resolveAlias).some(alias => id === alias || id.startsWith(alias + "/"))) return false; - return true; - }, - resolve: { - alias: resolveAlias, - extensions: [".ts", ".js"], - }, - }); - const { output } = await bundle.generate({ format: "esm" }); - fs.writeFileSync(tmpBundle, output[0].code); - await bundle.close(); - - // 3. 动态导入打包后的入口文件, 获取主题配置 - const themeConfig: ThemeSeries[] = (await import(pathToFileURL(tmpBundle).href)).default; - - if (!themeConfig || typeof themeConfig !== "object") { - throw new Error(`[${PLUGIN_NAME}] Entry file must default-export a defineThemeConfig result`); - } - - /** 辅助函数: 按 "-" 分割字符串并首字母大写 */ - function kebabToTitle(str: string): string { - return str - .split("-") - .map(word => word.charAt(0).toUpperCase() + word.slice(1)) - .join(" "); - } - /** 辅助函数: 将主题名称转为正式主题名称 */ - function buildFullThemeName(themeSeries: ThemeSeries, themeName: string): string { - return `${PREFIX}${themeSeries.themeSeriesName !== "default" ? `${themeSeries.themeSeriesName}-` : ""}${themeName}`; - } - /** 辅助函数: 将显示名称转为正式名称 */ - function buildFullDisplayName(themeSeries: ThemeSeries, displayName: string): string { - return `GitHub ${kebabToTitle(themeSeries.themeSeriesName)} ${kebabToTitle(displayName)}`; - } - - // 4. 解析主题条目 - themeEntries = themeConfig.flatMap(themeSeries => - Object.entries(themeSeries.themes).map(([themeKeyName, entry]) => { - const name = entry.themeName ?? themeKeyName; - // 直接修改主题名用于自动主题生成使用, 避免重复计算 - entry.themeName = buildFullThemeName(themeSeries, name); - return { - themeName: entry.themeName, - meta: { - colorScheme: entry.theme.isDarkTheme ? "dark" : "light", - displayName: entry.displayName ? `GitHub ${entry.displayName}` : buildFullDisplayName(themeSeries, name), - colorblindType: entry.colorblindType, - }, - theme: entry.theme, - }; - }) - ); - - // 5. 解析自动主题条目 - for (const themeSeries of themeConfig) { - if (themeSeries.themes.dark && themeSeries.themes.light) { - const themeName = buildFullThemeName(themeSeries, "auto"); - const meta: GiteaThemeMeta = { - colorScheme: "auto", - displayName: themeSeries.autoTheme?.displayName - ? `GitHub ${themeSeries.autoTheme.displayName}` - : buildFullDisplayName(themeSeries, "auto"), - colorblindType: themeSeries.autoTheme?.colorblindType, - }; - autoThemeEntries.set(themeName, { - darkThemeName: themeSeries.themes.dark.themeName!, - lightThemeName: themeSeries.themes.light.themeName!, - }); - // 将自动主题也加入 themeEntries 以便编译 CSS - themeEntries.push({ themeName, meta, theme: null as unknown as Theme }); - } - } - - // 6. 编译公共样式 (替代 wyw-in-js) - // 使用 jiti 直接执行源文件,无需 rolldown 打包,避免 tree-shaking - const { createJiti } = await import("jiti"); - const jitiInstance = createJiti(import.meta.url, { - alias: resolveAlias, - }); - await jitiInstance.import(path.join(root, "styles/index.ts")); - const rawStyles = flushCSS(); - // LightningCSS 展开嵌套 + 压缩 - styles = lightningcss - .transform({ - filename: "styles.css", - code: Buffer.from(rawStyles), - targets: { chrome: 100 << 16 }, - minify: true, - }) - .code.toString(); - - // 7. 提供占位入口,Vite 需要至少一个输入才会触发 generateBundle - const placeholder = path.join(tmpDir, "_placeholder.js"); - fs.writeFileSync(placeholder, "// placeholder\n"); - return { build: { rollupOptions: { input: placeholder } } }; - }, - - generateBundle(this, _options, bundle) { - // 清除占位入口产物 - for (const key of Object.keys(bundle)) { - delete bundle[key]; - } - - // 注入 __THEME_VERSION__ 全局变量, createTheme 中使用 - (globalThis as Record).__THEME_VERSION__ = themeVersion; - - // 编译每个主题的 CSS 并输出 - for (const entry of themeEntries) { - const { themeName, meta } = entry; - const autoTheme = autoThemeEntries.get(themeName); - - let themeCSS = compileThemeCSS(() => { - createThemeMetaInfo(meta); - // 自动主题不需要颜色变量, 只有 metaInfo - if (!autoTheme) { - createTheme(entry.theme); - } - }); - themeCSS = lightningcss - .transform({ filename: themeName + ".css", code: Buffer.from(themeCSS), minify: true }) - .code.toString(); - const source = autoTheme - ? [ - `@import "./${autoTheme.darkThemeName}.css" (prefers-color-scheme: dark);`, - `@import "./${autoTheme.lightThemeName}.css" (prefers-color-scheme: light);`, - themeCSS, - ].join("\n") - : `${themeCSS}${styles}`; - - this.emitFile({ - type: "asset", - fileName: `${themeName}.css`, - source, - }); - } - - // 清理全局变量 - delete (globalThis as Record).__THEME_VERSION__; - }, - }; -} diff --git a/src/vite-plugin/index.ts b/src/vite-plugin/index.ts new file mode 100644 index 0000000..30ac179 --- /dev/null +++ b/src/vite-plugin/index.ts @@ -0,0 +1,131 @@ +/*! + * Copyright (c) https://github.com/lutinglt + * + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { transform } from "lightningcss"; +import fs from "node:fs"; +import path from "node:path"; +import type { PluginOption } from "vite"; +import type { GiteaThemeMeta, Theme } from "../core"; +import { createTheme, createThemeMetaInfo } from "../core"; +import { flushCSS } from "../core/css"; +import { compileCSS } from "../vanilla-extract"; +import { buildFullDisplayName, buildFullThemeName } from "./utils"; + +type ThemeEntry = { themeName: string; meta: GiteaThemeMeta; theme: Theme }; +type AutoThemeEntry = { darkThemeName: string; lightThemeName: string }; + +export function giteaGitHubTheme(): PluginOption { + const themeEntries = new Array(); + const autoThemeEntries = new Map(); + + return { + name: "lutinglt-gitea-github-theme", + + async config(userConfig) { + // 1. 动态导入 theme.config.ts(Bun 原生 TS + exports 自引用) + const themeConfig = (await import("@lutinglt/gitea-github-theme/theme.config.ts")).default; + + // 2. 解析主题条目 + for (const themeSeries of themeConfig) { + for (const [themeKeyName, entry] of Object.entries(themeSeries.themes)) { + const name = entry.themeName ?? themeKeyName; + // 直接修改主题名用于自动主题生成使用, 避免重复计算 + entry.themeName = buildFullThemeName(themeSeries, name); + themeEntries.push({ + themeName: entry.themeName, + meta: { + colorScheme: entry.theme.isDarkTheme ? "dark" : "light", + displayName: entry.displayName ? `GitHub ${entry.displayName}` : buildFullDisplayName(themeSeries, name), + colorblindType: entry.colorblindType, + }, + theme: entry.theme, + }); + } + } + + // 3. 解析自动主题条目 + for (const themeSeries of themeConfig) { + if (themeSeries.themes.dark && themeSeries.themes.light) { + const themeName = buildFullThemeName(themeSeries, "auto"); + const meta: GiteaThemeMeta = { + colorScheme: "auto", + displayName: themeSeries.autoTheme?.displayName + ? `GitHub ${themeSeries.autoTheme.displayName}` + : buildFullDisplayName(themeSeries, "auto"), + colorblindType: themeSeries.autoTheme?.colorblindType, + }; + autoThemeEntries.set(themeName, { + darkThemeName: themeSeries.themes.dark.themeName!, + lightThemeName: themeSeries.themes.light.themeName!, + }); + // 将自动主题也加入 themeEntries 以便编译 CSS + themeEntries.push({ themeName, meta, theme: null as unknown as Theme }); + } + } + + // 4. 提供占位入口,Vite 需要至少一个输入才会触发 generateBundle + const outDir = userConfig.build?.outDir || "dist"; + const placeholder = path.join(outDir, "_placeholder.js"); + fs.mkdirSync(outDir, { recursive: true }); + fs.writeFileSync(placeholder, "// placeholder\n"); + return { build: { outDir, rolldownOptions: { input: placeholder } } }; + }, + + async generateBundle(this, _options, bundle) { + // 清除占位入口产物 + for (const key of Object.keys(bundle)) { + delete bundle[key]; + } + + // 1. 编译公共样式 (替代 wyw-in-js) + // Bun 原生 TS + exports 自引用,导入即触发所有 css() 副作用 + await import("@lutinglt/gitea-github-theme/styles"); + const rawStyles = Buffer.from(flushCSS()); + const styles = transform({ filename: "styles.css", code: rawStyles, minify: true }).code.toString(); + + // 编译每个主题的 CSS 并输出 + for (const entry of themeEntries) { + const { themeName, meta } = entry; + const autoTheme = autoThemeEntries.get(themeName); + + const rawThemeCSS = Buffer.from( + compileCSS(() => { + createThemeMetaInfo(meta); + // 自动主题不需要颜色变量, 只有 metaInfo + if (!autoTheme) createTheme(entry.theme); + }) + ); + const themeCSS = transform({ filename: themeName + ".css", code: rawThemeCSS, minify: true }).code.toString(); + const source = autoTheme + ? [ + `@import "./${autoTheme.darkThemeName}.css" (prefers-color-scheme: dark);`, + `@import "./${autoTheme.lightThemeName}.css" (prefers-color-scheme: light);`, + themeCSS, + ].join("\n") + : `${themeCSS}${styles}`; + + this.emitFile({ + type: "asset", + fileName: `${themeName}.css`, + source, + }); + } + }, + }; +} diff --git a/src/vite-plugin/themeConfig.ts b/src/vite-plugin/themeConfig.ts new file mode 100644 index 0000000..f1ccc42 --- /dev/null +++ b/src/vite-plugin/themeConfig.ts @@ -0,0 +1,68 @@ +/*! + * Copyright (c) https://github.com/lutinglt + * + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ColorblindType, Theme } from "../core"; + +type ThemeConfig = { + /** 主题名称, 用于生成文件名, 未指定时取 themes 中的键名 */ + themeName?: string; + /** 显示名称, 用于 Gitea UI 显示的名称 + * - 未指定时根据 themeName 生成 + * - 指定时将覆盖生成的名称, 仅包含主题插件前缀, 不包含主题系列名称 + */ + displayName?: string; + /** 色盲类型, 仅用于声明主题为色盲主题 */ + colorblindType?: ColorblindType; + theme: Theme; +}; +type Themes = + | { + /** 主题系列的深色模式主题 */ + dark: ThemeConfig; + [themeKeyName: string]: ThemeConfig; + } + | { + /** 主题系列的浅色模式主题 */ + light: ThemeConfig; + [themeKeyName: string]: ThemeConfig; + }; +export type ThemeSeries = { + /** 主题系列名称, 做为前缀用于生成文件名和显示名称 */ + themeSeriesName: string; + /** 主题系列自动颜色主题配置 */ + autoTheme?: { + /** 自动颜色主题用于 Gitea UI 显示的名称 */ + displayName?: string; + /** 色盲类型, 仅用于声明主题为色盲主题 */ + colorblindType?: ColorblindType; + }; + /** 必须至少声明 dark/light 其中一个, 如果 dark & light 都声明了, 会生成自动颜色主题 */ + themes: Themes; +}; + +/** 定义主题配置 */ +export function defineThemeConfig(config: ThemeSeries[]): ThemeSeries[] { + // 检查主题系列名称是否重复 + const names = config.map(c => c.themeSeriesName); + const duplicates = names.filter((name, index) => names.indexOf(name) !== index); + if (duplicates.length > 0) { + throw new Error(`Duplicate themeSeriesName found: ${[...new Set(duplicates)].join(", ")}`); + } + return config; +} diff --git a/src/vite-plugin/utils.ts b/src/vite-plugin/utils.ts new file mode 100644 index 0000000..9a9b2c5 --- /dev/null +++ b/src/vite-plugin/utils.ts @@ -0,0 +1,36 @@ +/*! + * Copyright (c) https://github.com/lutinglt + * + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ThemeSeries } from "./themeConfig"; + +/** 按 "-" 分割字符串并首字母大写 */ +function kebabToTitle(str: string): string { + return str + .split("-") + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(" "); +} +/** 将主题名称转为正式主题名称 */ +export function buildFullThemeName(themeSeries: ThemeSeries, themeName: string): string { + return `theme-github-${themeSeries.themeSeriesName !== "default" ? `${themeSeries.themeSeriesName}-` : ""}${themeName}`; +} +/** 将显示名称转为正式名称 */ +export function buildFullDisplayName(themeSeries: ThemeSeries, displayName: string): string { + return `GitHub ${kebabToTitle(themeSeries.themeSeriesName)} ${kebabToTitle(displayName)}`; +} diff --git a/styles/common/after.ts b/styles/common/after.ts index 241b458..afaeec8 100644 --- a/styles/common/after.ts +++ b/styles/common/after.ts @@ -17,12 +17,12 @@ * limitations under the License. */ -import { otherThemeVars, themeVars, toCSS } from "@gitea-github-theme/core"; +import { cssStyle, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; /** 激活项后缀样式 * @example 菜单激活子项前面的竖线, 方便识别 */ -export const activeItemAfterStyle = toCSS({ +export const activeItemAfterStyle = cssStyle({ content: `""`, backgroundColor: themeVars.github.borderColor.accent.emphasis, borderRadius: otherThemeVars.border.radius, diff --git a/styles/common/animation.ts b/styles/common/animation.ts index cc909e1..c684b9f 100644 --- a/styles/common/animation.ts +++ b/styles/common/animation.ts @@ -17,10 +17,10 @@ * limitations under the License. */ -import { selectors, toCSS } from "@gitea-github-theme/core"; +import { cssStyle, selectors } from "@lutinglt/gitea-github-theme/core"; // 出现动画 -export const animation = toCSS({ +export const animation = cssStyle({ animation: selectors.overlayAppear, animationDuration: "80ms", animationFillMode: "forwards", @@ -28,14 +28,14 @@ export const animation = toCSS({ }); // 向下出现动画 -export const animationDown = toCSS({ +export const animationDown = cssStyle({ animation: selectors.overlayAppearDown, animationDuration: "200ms", animationTimingFunction: "cubic-bezier(0.33, 1, 0.68, 1)", }); // 向上出现动画 -export const animationUp = toCSS({ +export const animationUp = cssStyle({ animation: selectors.overlayAppearUp, animationDuration: "200ms", animationTimingFunction: "cubic-bezier(0.33, 1, 0.68, 1)", diff --git a/styles/common/button.ts b/styles/common/button.ts index 4649c11..d5afd7f 100644 --- a/styles/common/button.ts +++ b/styles/common/button.ts @@ -17,10 +17,10 @@ * limitations under the License. */ -import { themeVars, toCSS } from "@gitea-github-theme/core"; +import { cssStyle, themeVars } from "@lutinglt/gitea-github-theme/core"; /** 主色调按钮样式 */ -export const primaryButtonStyle = toCSS({ +export const primaryButtonStyle = cssStyle({ color: themeVars.github.button.primary.fgColor.rest, backgroundColor: themeVars.github.button.primary.bgColor.rest, borderColor: themeVars.github.button.primary.borderColor.rest, @@ -28,7 +28,7 @@ export const primaryButtonStyle = toCSS({ }); /** 主色调按钮悬停样式 */ -export const primaryButtonHoverStyle = toCSS({ +export const primaryButtonHoverStyle = cssStyle({ color: themeVars.github.button.primary.fgColor.rest, backgroundColor: themeVars.github.button.primary.bgColor.hover, borderColor: themeVars.github.button.primary.borderColor.hover, diff --git a/styles/common/delete.ts b/styles/common/delete.ts index 9dd7ea0..b4390b1 100644 --- a/styles/common/delete.ts +++ b/styles/common/delete.ts @@ -17,9 +17,9 @@ * limitations under the License. */ -import { themeVars, toCSS } from "@gitea-github-theme/core"; +import { cssStyle, themeVars } from "@lutinglt/gitea-github-theme/core"; -export const deleteHoverActiveStyle = toCSS({ +export const deleteHoverActiveStyle = cssStyle({ "&:hover": { backgroundColor: `${themeVars.github.control.danger.bgColor.hover} !important`, color: `${themeVars.github.control.danger.fgColor.hover} !important`, diff --git a/styles/common/label.ts b/styles/common/label.ts index c964f3e..92e3205 100644 --- a/styles/common/label.ts +++ b/styles/common/label.ts @@ -17,15 +17,15 @@ * limitations under the License. */ -import { toCSS } from "@gitea-github-theme/core"; +import { cssStyle } from "@lutinglt/gitea-github-theme/core"; /** 基本标签样式 */ -export const labelStyle = toCSS({ +export const labelStyle = cssStyle({ padding: "0px 6px", }); /** bot 标签样式 */ -export const botLabelStyle = toCSS({ +export const botLabelStyle = cssStyle({ height: "20px", padding: "0 6px !important", marginLeft: "4px", diff --git a/styles/components/actions/action_svg.ts b/styles/components/actions/action_svg.ts index cb67207..0d46be9 100644 --- a/styles/components/actions/action_svg.ts +++ b/styles/components/actions/action_svg.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; // 修改 action 页面 svg 颜色 (主要为了覆盖工作流状态中的白色图标) export const actionSVG = css` diff --git a/styles/components/actions/actions.ts b/styles/components/actions/actions.ts index 2e6a527..ba0c32c 100644 --- a/styles/components/actions/actions.ts +++ b/styles/components/actions/actions.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 仓库 Actions 页面 export const actions = css` diff --git a/styles/components/actions/workflow_runs.ts b/styles/components/actions/workflow_runs.ts index 54e263c..b47b822 100644 --- a/styles/components/actions/workflow_runs.ts +++ b/styles/components/actions/workflow_runs.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 工作流详情页标题 export const actionViewHeader = css` diff --git a/styles/components/actions/workflow_steps.ts b/styles/components/actions/workflow_steps.ts index 6064bee..74268ac 100644 --- a/styles/components/actions/workflow_steps.ts +++ b/styles/components/actions/workflow_steps.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; -import { animationDown } from "@gitea-github-theme/styles/common"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { animationDown } from "@lutinglt/gitea-github-theme/styles/common"; // 工作流右侧作业步骤日志详情 export const actionViewRight = css` diff --git a/styles/components/actions/workflow_summary.ts b/styles/components/actions/workflow_summary.ts index 61af8d7..58bbb92 100644 --- a/styles/components/actions/workflow_summary.ts +++ b/styles/components/actions/workflow_summary.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; export const summaryView = css` .action-view-right:has(.action-run-summary-view) { diff --git a/styles/components/dashboard.ts b/styles/components/dashboard.ts index fb63315..1b4bae1 100644 --- a/styles/components/dashboard.ts +++ b/styles/components/dashboard.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { labelStyle } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { labelStyle } from "@lutinglt/gitea-github-theme/styles/common"; export const dashboard = css` .page-content.dashboard { diff --git a/styles/components/explore.ts b/styles/components/explore.ts index 0ef3194..2cbc482 100644 --- a/styles/components/explore.ts +++ b/styles/components/explore.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, customThemeVars, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, customThemeVars, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; import { fallbackVar } from "@vanilla-extract/css"; const userRepoVar = fallbackVar(customThemeVars.userRepolistColumns, "2"); diff --git a/styles/components/footer.ts b/styles/components/footer.ts index ffc58fb..383715f 100644 --- a/styles/components/footer.ts +++ b/styles/components/footer.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; export const footer = css` .page-footer { diff --git a/styles/components/heatmap.ts b/styles/components/heatmap.ts index bd8eba2..8303a40 100644 --- a/styles/components/heatmap.ts +++ b/styles/components/heatmap.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; export const heatmap = css` #user-heatmap { diff --git a/styles/components/issues/issue.ts b/styles/components/issues/issue.ts index a73b7f9..b3152c1 100644 --- a/styles/components/issues/issue.ts +++ b/styles/components/issues/issue.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { activeItemAfterStyle } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { activeItemAfterStyle } from "@lutinglt/gitea-github-theme/styles/common"; export const button = css` /* 工单&PR标题右侧按钮 */ diff --git a/styles/components/issues/issue_comment.ts b/styles/components/issues/issue_comment.ts index e9a744c..5c82a71 100644 --- a/styles/components/issues/issue_comment.ts +++ b/styles/components/issues/issue_comment.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { botLabelStyle, deleteHoverActiveStyle } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { botLabelStyle, deleteHoverActiveStyle } from "@lutinglt/gitea-github-theme/styles/common"; // 评论 export const comment = css` diff --git a/styles/components/issues/issue_list.ts b/styles/components/issues/issue_list.ts index 40f22cd..5f1461b 100644 --- a/styles/components/issues/issue_list.ts +++ b/styles/components/issues/issue_list.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, extractVarName, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, extractVarName, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 工单&PR 列表 export const issueList = css` diff --git a/styles/components/issues/issue_sidebar.ts b/styles/components/issues/issue_sidebar.ts index bdd8e13..fb6b621 100644 --- a/styles/components/issues/issue_sidebar.ts +++ b/styles/components/issues/issue_sidebar.ts @@ -17,10 +17,10 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars, toCSS } from "@gitea-github-theme/core"; -import { deleteHoverActiveStyle } from "@gitea-github-theme/styles/common"; +import { css, cssStyle, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { deleteHoverActiveStyle } from "@lutinglt/gitea-github-theme/styles/common"; -const sidebarPadding = toCSS({ +const sidebarPadding = cssStyle({ padding: "4px 8px", }); diff --git a/styles/components/issues/issue_timeline.ts b/styles/components/issues/issue_timeline.ts index b8ec8c2..3fbaa61 100644 --- a/styles/components/issues/issue_timeline.ts +++ b/styles/components/issues/issue_timeline.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; -import { botLabelStyle } from "@gitea-github-theme/styles/common"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { botLabelStyle } from "@lutinglt/gitea-github-theme/styles/common"; // 时间线 export const timeline = css` diff --git a/styles/components/navbar.ts b/styles/components/navbar.ts index 0c58dbd..57c6acc 100644 --- a/styles/components/navbar.ts +++ b/styles/components/navbar.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, customThemeVars, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, customThemeVars, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; import { fallbackVar } from "@vanilla-extract/css"; export const navbarRight = css` diff --git a/styles/components/newrepo.ts b/styles/components/newrepo.ts index 2395d96..f9f5e6f 100644 --- a/styles/components/newrepo.ts +++ b/styles/components/newrepo.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css } from "@gitea-github-theme/core"; -import { activeItemAfterStyle } from "@gitea-github-theme/styles/common"; +import { css } from "@lutinglt/gitea-github-theme/core"; +import { activeItemAfterStyle } from "@lutinglt/gitea-github-theme/styles/common"; // 新建仓库页面下拉菜单 export const newRepo = css` diff --git a/styles/components/notification.ts b/styles/components/notification.ts index 6d69888..d789803 100644 --- a/styles/components/notification.ts +++ b/styles/components/notification.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 用户订阅/关注页面 export const notification = css` diff --git a/styles/components/org.ts b/styles/components/org.ts index 3fc4f23..40cb021 100644 --- a/styles/components/org.ts +++ b/styles/components/org.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; export const org = css` .page-content.organization { diff --git a/styles/components/repo/clone.ts b/styles/components/repo/clone.ts index 38e895c..cb6edaa 100644 --- a/styles/components/repo/clone.ts +++ b/styles/components/repo/clone.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, customThemeVars, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, customThemeVars, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 克隆按钮的弹窗 export const clone = css` diff --git a/styles/components/repo/commit.ts b/styles/components/repo/commit.ts index dca0fc6..5b9fcea 100644 --- a/styles/components/repo/commit.ts +++ b/styles/components/repo/commit.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 提交列表 export const commit = css` diff --git a/styles/components/repo/diff.ts b/styles/components/repo/diff.ts index 393da99..48e117a 100644 --- a/styles/components/repo/diff.ts +++ b/styles/components/repo/diff.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { activeItemAfterStyle } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { activeItemAfterStyle } from "@lutinglt/gitea-github-theme/styles/common"; export const diff = css` /* 这里的折叠行和代码行高度与 GitHub 的 release 和 review 的差异对比时的高度一致, 不需要像 commit 中的差异对比那样行高过高 */ diff --git a/styles/components/repo/milestones.ts b/styles/components/repo/milestones.ts index 1a96a70..681b283 100644 --- a/styles/components/repo/milestones.ts +++ b/styles/components/repo/milestones.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; export const milestone = css` /* 里程碑头部 */ diff --git a/styles/components/repo/packages.ts b/styles/components/repo/packages.ts index e88ec99..e9692d5 100644 --- a/styles/components/repo/packages.ts +++ b/styles/components/repo/packages.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 组织/仓库的软件包列表(包含用户但未测试) export const packagesList = css` diff --git a/styles/components/repo/release.ts b/styles/components/repo/release.ts index b6e02a8..310bc43 100644 --- a/styles/components/repo/release.ts +++ b/styles/components/repo/release.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; // release 顶部栏左侧按钮组 export const releaseTagMenu = css` diff --git a/styles/components/repo/repo.ts b/styles/components/repo/repo.ts index 41f9a90..c286d9c 100644 --- a/styles/components/repo/repo.ts +++ b/styles/components/repo/repo.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 仓库头信息 export const repoHeader = css` diff --git a/styles/components/repo/repo_file_view.ts b/styles/components/repo/repo_file_view.ts index 2ca333a..94718c3 100644 --- a/styles/components/repo/repo_file_view.ts +++ b/styles/components/repo/repo_file_view.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { activeItemAfterStyle, deleteHoverActiveStyle } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { activeItemAfterStyle, deleteHoverActiveStyle } from "@lutinglt/gitea-github-theme/styles/common"; // 仓库打开文件时的视图 export const repoFileView = css` diff --git a/styles/components/repo/repo_files.ts b/styles/components/repo/repo_files.ts index 8cd67d4..3843bed 100644 --- a/styles/components/repo/repo_files.ts +++ b/styles/components/repo/repo_files.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { animationDown } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { animationDown } from "@lutinglt/gitea-github-theme/styles/common"; // 文件列表页面下的分支按钮 export const branchButton = css` diff --git a/styles/components/repo/repo_sidebar.ts b/styles/components/repo/repo_sidebar.ts index cc3ee43..3fbc344 100644 --- a/styles/components/repo/repo_sidebar.ts +++ b/styles/components/repo/repo_sidebar.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; // 仓库代码布局调整, 侧边栏宽度调整 export const repoGrid = css` diff --git a/styles/components/setting.ts b/styles/components/setting.ts index e4a0327..9d30cce 100644 --- a/styles/components/setting.ts +++ b/styles/components/setting.ts @@ -17,16 +17,16 @@ * limitations under the License. */ -import { css, themeVars, toCSS } from "@gitea-github-theme/core"; -import { primaryButtonHoverStyle, primaryButtonStyle } from "@gitea-github-theme/styles/common"; +import { css, cssStyle, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { primaryButtonHoverStyle, primaryButtonStyle } from "@lutinglt/gitea-github-theme/styles/common"; -const tinyStyle = toCSS({ +const tinyStyle = cssStyle({ color: themeVars.github.themeExtra.button.primary.fgColor.accent, backgroundColor: themeVars.color.button, borderColor: themeVars.color.light.border, }); -const tinyHoverStyle = toCSS({ +const tinyHoverStyle = cssStyle({ color: themeVars.github.button.primary.fgColor.rest, backgroundColor: themeVars.github.button.primary.bgColor.hover, borderColor: themeVars.github.button.primary.borderColor.hover, diff --git a/styles/components/signin.ts b/styles/components/signin.ts index 04bb52f..7a9ac60 100644 --- a/styles/components/signin.ts +++ b/styles/components/signin.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css } from "@gitea-github-theme/core"; +import { css } from "@lutinglt/gitea-github-theme/core"; // 注册/登录界面 export const signIn = css` diff --git a/styles/components/user.ts b/styles/components/user.ts index 438dd3c..24ddbbc 100644 --- a/styles/components/user.ts +++ b/styles/components/user.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; // 用户点星仓库列表 export const stars = css` diff --git a/styles/public/attached.ts b/styles/public/attached.ts index 11b53a8..652de3f 100644 --- a/styles/public/attached.ts +++ b/styles/public/attached.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; export const attached = css` /* 设置右面板的内容 */ diff --git a/styles/public/base.ts b/styles/public/base.ts index 0785c0b..6d27faa 100644 --- a/styles/public/base.ts +++ b/styles/public/base.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css } from "@gitea-github-theme/core"; +import { css } from "@lutinglt/gitea-github-theme/core"; export const body = css` body { diff --git a/styles/public/button.ts b/styles/public/button.ts index 1e633fc..2e5636a 100644 --- a/styles/public/button.ts +++ b/styles/public/button.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; -import { primaryButtonHoverStyle, primaryButtonStyle } from "@gitea-github-theme/styles/common"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { primaryButtonHoverStyle, primaryButtonStyle } from "@lutinglt/gitea-github-theme/styles/common"; // 普通按钮和主色调按钮 export const baseButton = css` diff --git a/styles/public/dropdown/branch_dropdown.ts b/styles/public/dropdown/branch_dropdown.ts index 3bfe5c3..8042f0f 100644 --- a/styles/public/dropdown/branch_dropdown.ts +++ b/styles/public/dropdown/branch_dropdown.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, customThemeVars, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { animationDown } from "@gitea-github-theme/styles/common"; +import { css, customThemeVars, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { animationDown } from "@lutinglt/gitea-github-theme/styles/common"; import { fallbackVar } from "@vanilla-extract/css"; // 分支菜单 diff --git a/styles/public/dropdown/dropdown.ts b/styles/public/dropdown/dropdown.ts index 49824f7..73dbc21 100644 --- a/styles/public/dropdown/dropdown.ts +++ b/styles/public/dropdown/dropdown.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { activeItemAfterStyle, animationDown, animationUp } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { activeItemAfterStyle, animationDown, animationUp } from "@lutinglt/gitea-github-theme/styles/common"; export const dropdown = css` .ui.dropdown, diff --git a/styles/public/dropdown/emoji_dropdown.ts b/styles/public/dropdown/emoji_dropdown.ts index 61e9667..d1e5b15 100644 --- a/styles/public/dropdown/emoji_dropdown.ts +++ b/styles/public/dropdown/emoji_dropdown.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; // 包含表情的下拉菜单 export const emojiDropdown = css` diff --git a/styles/public/dropdown/selection_dropdown.ts b/styles/public/dropdown/selection_dropdown.ts index 300bf28..122f638 100644 --- a/styles/public/dropdown/selection_dropdown.ts +++ b/styles/public/dropdown/selection_dropdown.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { activeItemAfterStyle } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { activeItemAfterStyle } from "@lutinglt/gitea-github-theme/styles/common"; // 选择框的下拉菜单看起来像普通按钮 export const selectionDropdown = css` diff --git a/styles/public/input.ts b/styles/public/input.ts index 3b0f4db..9f93448 100644 --- a/styles/public/input.ts +++ b/styles/public/input.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; export const input = css` textarea, diff --git a/styles/public/label/label.ts b/styles/public/label/label.ts index 3d83943..7a0bcc8 100644 --- a/styles/public/label/label.ts +++ b/styles/public/label/label.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; -import { labelStyle } from "@gitea-github-theme/styles/common"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { labelStyle } from "@lutinglt/gitea-github-theme/styles/common"; export const label = css` .ui.label { diff --git a/styles/public/label/repo_label.ts b/styles/public/label/repo_label.ts index 04966dc..e65f4f8 100644 --- a/styles/public/label/repo_label.ts +++ b/styles/public/label/repo_label.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; // 仓库标签 (私有/公开/内部) export const repoLabel = css` diff --git a/styles/public/label/sha_label.ts b/styles/public/label/sha_label.ts index b25e9da..e470000 100644 --- a/styles/public/label/sha_label.ts +++ b/styles/public/label/sha_label.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; // 提交中的 SHA 标签 export const shaLabel = css` diff --git a/styles/public/label/task_status_label.ts b/styles/public/label/task_status_label.ts index 9703bea..3ebef6f 100644 --- a/styles/public/label/task_status_label.ts +++ b/styles/public/label/task_status_label.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; // 任务状态标签, 目前仅在管理员页面 Runner 状态中看到 export const taskStatusLabel = css` diff --git a/styles/public/menu/compact_menu.ts b/styles/public/menu/compact_menu.ts index cde4373..3299942 100644 --- a/styles/public/menu/compact_menu.ts +++ b/styles/public/menu/compact_menu.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 单行双选项菜单 export const smallCompactMenu = css` diff --git a/styles/public/menu/menu.ts b/styles/public/menu/menu.ts index f969843..40fa128 100644 --- a/styles/public/menu/menu.ts +++ b/styles/public/menu/menu.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; -import { labelStyle } from "@gitea-github-theme/styles/common"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { labelStyle } from "@lutinglt/gitea-github-theme/styles/common"; export const menu = css` .ui.menu { diff --git a/styles/public/menu/pagination_menu.ts b/styles/public/menu/pagination_menu.ts index e30becd..b36e796 100644 --- a/styles/public/menu/pagination_menu.ts +++ b/styles/public/menu/pagination_menu.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; // 分页菜单 export const paginationMenu = css` diff --git a/styles/public/menu/secondary_menu.ts b/styles/public/menu/secondary_menu.ts index 3cf38dc..6d42ed9 100644 --- a/styles/public/menu/secondary_menu.ts +++ b/styles/public/menu/secondary_menu.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; export const secondaryMenu = css` /* 二级菜单, 比如 Issue/PR/Actions 的筛选菜单 */ diff --git a/styles/public/menu/vertical_menu.ts b/styles/public/menu/vertical_menu.ts index ccba6ee..00969a5 100644 --- a/styles/public/menu/vertical_menu.ts +++ b/styles/public/menu/vertical_menu.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { activeItemAfterStyle } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { activeItemAfterStyle } from "@lutinglt/gitea-github-theme/styles/common"; export const verticalMenu = css` /* 垂直菜单, 用于左侧边栏 */ diff --git a/styles/public/modal.ts b/styles/public/modal.ts index 108dfc8..a297cdd 100644 --- a/styles/public/modal.ts +++ b/styles/public/modal.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; -import { animationDown } from "@gitea-github-theme/styles/common"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { animationDown } from "@lutinglt/gitea-github-theme/styles/common"; export const modal = css` .ui.modal { diff --git a/styles/public/other.ts b/styles/public/other.ts index 9359232..2900649 100644 --- a/styles/public/other.ts +++ b/styles/public/other.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; export const text = css` /* 默认颜色是 --color-text-light, 主题下此颜色是亮白色, 修改为灰色 */ diff --git a/styles/public/radius.ts b/styles/public/radius.ts index 5ca15af..090a48e 100644 --- a/styles/public/radius.ts +++ b/styles/public/radius.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars } from "@lutinglt/gitea-github-theme/core"; // 全部圆角替换 export const radius = css` diff --git a/styles/public/table.ts b/styles/public/table.ts index fa8b377..8ec5d0d 100644 --- a/styles/public/table.ts +++ b/styles/public/table.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, themeVars } from "@gitea-github-theme/core"; +import { css, themeVars } from "@lutinglt/gitea-github-theme/core"; export const table = css` .ui.table > tr > td, diff --git a/styles/public/tippy.ts b/styles/public/tippy.ts index 747511b..cfb22bb 100644 --- a/styles/public/tippy.ts +++ b/styles/public/tippy.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; -import { animation, animationDown } from "@gitea-github-theme/styles/common"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; +import { animation, animationDown } from "@lutinglt/gitea-github-theme/styles/common"; // 一些界面内的提示框, 比如克隆按钮, PR信息, Runner信息 等 export const tippyBox = css` diff --git a/styles/public/transition.ts b/styles/public/transition.ts index 0e2a7fc..a075084 100644 --- a/styles/public/transition.ts +++ b/styles/public/transition.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css } from "@gitea-github-theme/core"; +import { css } from "@lutinglt/gitea-github-theme/core"; // 简单的渐变过渡 export const transition = css` diff --git a/styles/templates/repo/commit_sign_badge.ts b/styles/templates/repo/commit_sign_badge.ts index b02fad6..e0eff40 100644 --- a/styles/templates/repo/commit_sign_badge.ts +++ b/styles/templates/repo/commit_sign_badge.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; export const commitSignBadge = css` a.ui.label.commit-id-short.gitea-github-theme-commit-sha { diff --git a/styles/templates/repo/commits_list.ts b/styles/templates/repo/commits_list.ts index d872e20..2abb1a9 100644 --- a/styles/templates/repo/commits_list.ts +++ b/styles/templates/repo/commits_list.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; const primary = "primary" as const; const secondary = "secondary" as const; diff --git a/styles/templates/repo/view_content.ts b/styles/templates/repo/view_content.ts index d0bf1cb..04125b5 100644 --- a/styles/templates/repo/view_content.ts +++ b/styles/templates/repo/view_content.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; export const repoButtonRow = css` .gitea-github-theme-templates { diff --git a/styles/templates/repo/view_list.ts b/styles/templates/repo/view_list.ts index 5003b10..3f9372f 100644 --- a/styles/templates/repo/view_list.ts +++ b/styles/templates/repo/view_list.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import { css, otherThemeVars, themeVars } from "@gitea-github-theme/core"; +import { css, otherThemeVars, themeVars } from "@lutinglt/gitea-github-theme/core"; export const repoFileLastCommit = css` /* 仓库页和文件列表文件夹页的最后一次提交 */ diff --git a/theme.config.ts b/theme.config.ts index 082e589..a9c0c72 100644 --- a/theme.config.ts +++ b/theme.config.ts @@ -17,8 +17,8 @@ * limitations under the License. */ -import { defineThemeConfig } from "@gitea-github-theme/core"; -import themes from "@gitea-github-theme/themes"; +import { defineThemeConfig } from "@lutinglt/gitea-github-theme/core"; +import themes from "@lutinglt/gitea-github-theme/themes"; export default defineThemeConfig([ { diff --git a/themes/catppuccin.ts b/themes/catppuccin.ts index 9fac428..d3df15b 100644 --- a/themes/catppuccin.ts +++ b/themes/catppuccin.ts @@ -22,7 +22,7 @@ */ import { flavors, type CatppuccinFlavor } from "@catppuccin/palette"; -import { catppuccin2Syntax, catppuccin2ThemeColor, defineTheme } from "@gitea-github-theme/core"; +import { catppuccin2Syntax, catppuccin2ThemeColor, defineTheme } from "@lutinglt/gitea-github-theme/core"; function defineCatppuccinTheme(flavor: CatppuccinFlavor) { return defineTheme({ diff --git a/themes/giteaDark.ts b/themes/giteaDark.ts index 14e1891..1cd4894 100644 --- a/themes/giteaDark.ts +++ b/themes/giteaDark.ts @@ -32,8 +32,8 @@ import type { Primary, Secondary, Syntax, -} from "@gitea-github-theme/core"; -import { defineTheme, themeVars } from "@gitea-github-theme/core"; +} from "@lutinglt/gitea-github-theme/core"; +import { defineTheme, themeVars } from "@lutinglt/gitea-github-theme/core"; const primary: Primary = { self: "#4183c4", diff --git a/themes/giteaLight.ts b/themes/giteaLight.ts index d5ad0b4..2d91f2e 100644 --- a/themes/giteaLight.ts +++ b/themes/giteaLight.ts @@ -32,8 +32,8 @@ import type { Primary, Secondary, Syntax, -} from "@gitea-github-theme/core"; -import { defineTheme, themeVars } from "@gitea-github-theme/core"; +} from "@lutinglt/gitea-github-theme/core"; +import { defineTheme, themeVars } from "@lutinglt/gitea-github-theme/core"; const primary: Primary = { self: "#4183c4", diff --git a/themes/github.ts b/themes/github.ts index a24e06f..3a8a8db 100644 --- a/themes/github.ts +++ b/themes/github.ts @@ -21,9 +21,9 @@ * @author lutinglt */ -import type { GitHubColor } from "@gitea-github-theme/core"; -import { deepOverride, defineTheme, display2GitHubColor, primer2GitHubColor } from "@gitea-github-theme/core"; -import { default as primer } from "@gitea-github-theme/primer"; +import type { GitHubColor } from "@lutinglt/gitea-github-theme/core"; +import { deepOverride, defineTheme, display2GitHubColor, primer2GitHubColor } from "@lutinglt/gitea-github-theme/core"; +import { default as primer } from "@lutinglt/gitea-github-theme/primer"; /** - 仅适用于 Dark 主题的颜色转换 */ function darkConvert(color: GitHubColor) { diff --git a/tsconfig.json b/tsconfig.json index f749ac2..d2b504f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,6 @@ { "compilerOptions": { "plugins": [ - { - "name": "typescript-plugin-css-modules" - }, { "name": "@styled/typescript-styled-plugin", "lint": { @@ -31,11 +28,13 @@ "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true, "paths": { - "@gitea-github-theme/core": ["./src"], - "@gitea-github-theme/styles": ["./styles"], - "@gitea-github-theme/styles/common": ["./styles/common"], - "@gitea-github-theme/themes": ["./themes"], - "@gitea-github-theme/primer": ["./primer"] + "@lutinglt/gitea-github-theme/theme.config.ts": ["./theme.config.ts"], + "@lutinglt/gitea-github-theme/core": ["./src"], + "@lutinglt/gitea-github-theme/vite-plugin": ["./src/vite-plugin"], + "@lutinglt/gitea-github-theme/styles": ["./styles"], + "@lutinglt/gitea-github-theme/styles/common": ["./styles/common"], + "@lutinglt/gitea-github-theme/themes": ["./themes"], + "@lutinglt/gitea-github-theme/primer": ["./primer"] } }, "include": ["src", "styles", "themes", "scripts", "primer", "vite.config.ts", "theme.config.ts", "eslint.config.ts"] diff --git a/vite.config.ts b/vite.config.ts index 911b95a..686bea0 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -17,40 +17,7 @@ * limitations under the License. */ -import * as dotenv from "dotenv"; -import * as lightningcss from "lightningcss"; -import fs from "node:fs"; -import path from "node:path"; +import { giteaGitHubTheme } from "@lutinglt/gitea-github-theme/vite-plugin"; import { defineConfig } from "vite"; -import { giteaGitHubThemePlugin } from "./src/vite-plugin"; -dotenv.config({ quiet: true }); - -// 版本号: 版本号.YYMMDD -const pkg = JSON.parse(fs.readFileSync("package.json", "utf-8")); -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"); - -export default defineConfig({ - define: { - __THEME_VERSION__: JSON.stringify(`${pkg.version}.${year}${month}${day}`), - }, - resolve: { - alias: { - "@gitea-github-theme/core": path.resolve(__dirname, "src"), - "@gitea-github-theme/styles": path.resolve(__dirname, "styles"), - "@gitea-github-theme/themes": path.resolve(__dirname, "themes"), - "@gitea-github-theme/primer": path.resolve(__dirname, "primer"), - }, - extensions: [".js", ".ts", ".css.ts"], - }, - css: { - transformer: "lightningcss", - lightningcss: { - exclude: lightningcss.Features.LightDark, // 不生成 LightningCSS 的主题变量 - }, - }, - plugins: [giteaGitHubThemePlugin()], -}); +export default defineConfig({ plugins: [giteaGitHubTheme()] });