mirror of
https://github.com/lutinglt/gitea-github-theme.git
synced 2026-10-28 09:44:55 +00:00
organize code
This commit is contained in:
6 files changed
+185
-111
No files matched your search
+130
-68
@@ -2,9 +2,13 @@
|
||||
|
||||
## Project Overview
|
||||
|
||||
Gitea GitHub Theme is a build-time CSS generation framework that produces static `.css` theme files for the [Gitea](https://github.com/go-gitea/gitea) self-hosted code platform. The project takes design tokens and color definitions as input, transforms them through a layered pipeline, and outputs 30+ minified CSS files covering 7 theme series (default, colorblind, tritanopia, pink, gitea, catppuccin, high-contrast).
|
||||
Gitea GitHub Theme is a build-time CSS generation framework that produces static `.css` theme files for the
|
||||
[Gitea](https://github.com/go-gitea/gitea) self-hosted code platform. The project takes design tokens and color
|
||||
definitions as input, transforms them through a layered pipeline, and outputs 30+ minified CSS files covering 7 theme
|
||||
series (default, colorblind, tritanopia, pink, gitea, catppuccin, high-contrast).
|
||||
|
||||
**Core principle:** Full type safety and CSS-in-JS developer experience at build time, pure static CSS delivered to the browser with zero runtime overhead.
|
||||
**Core principle:** Full type safety and CSS-in-JS developer experience at build time, pure static CSS delivered to the
|
||||
browser with zero runtime overhead.
|
||||
|
||||
---
|
||||
|
||||
@@ -108,8 +112,9 @@ Gitea GitHub Theme is a build-time CSS generation framework that produces static
|
||||
|
||||
### 1. Vanilla-Extract Adapter Hijacking
|
||||
|
||||
**Problem solved:**
|
||||
Vanilla-extract is a zero-runtime CSS-in-JS library that generates static CSS files at build time via its Vite/esbuild plugin. However, Gitea themes need single-file CSS output and programmatic control over the theme generation process (one output file per theme, auto theme generation, etc.).
|
||||
**Problem solved:** Vanilla-extract is a zero-runtime CSS-in-JS library that generates static CSS files at build time
|
||||
via its Vite/esbuild plugin. However, Gitea themes need single-file CSS output and programmatic control over the theme
|
||||
generation process (one output file per theme, auto theme generation, etc.).
|
||||
|
||||
**Solution:** Bypass vanilla-extract's default plugin and use its low-level adapter API directly.
|
||||
|
||||
@@ -146,19 +151,23 @@ export function compileCSS(compileFn: () => void): string {
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. `compileCSS` wraps a synchronous function that calls vanilla-extract APIs (`createGlobalTheme`, `globalStyle`, `globalKeyframes`, etc.)
|
||||
1. `compileCSS` wraps a synchronous function that calls vanilla-extract APIs (`createGlobalTheme`, `globalStyle`,
|
||||
`globalKeyframes`, etc.)
|
||||
2. The custom adapter intercepts all CSS generation calls, capturing them into in-memory arrays
|
||||
3. After the function executes, `transformCss()` serializes the captured objects into CSS strings
|
||||
4. The adapter is torn down, leaving no global side effects
|
||||
|
||||
**Safety guarantee:** Each `compileCSS` call is fully self-contained: install → capture → serialize → teardown. No state leaks between calls.
|
||||
**Safety guarantee:** Each `compileCSS` call is fully self-contained: install → capture → serialize → teardown. No state
|
||||
leaks between calls.
|
||||
|
||||
**Key insight:** Vanilla-extract's `createGlobalThemeContract` + `createGlobalTheme` fit this pattern perfectly—they only produce CSS during `createGlobalTheme` calls, which happen exactly within our capture scope.
|
||||
**Key insight:** Vanilla-extract's `createGlobalThemeContract` + `createGlobalTheme` fit this pattern perfectly—they
|
||||
only produce CSS during `createGlobalTheme` calls, which happen exactly within our capture scope.
|
||||
|
||||
### 2. Three Color Input Pipelines
|
||||
|
||||
**Problem solved:**
|
||||
Different color theme sources have different data structures. Primer design tokens (from GitHub) have hundreds of nested keys. Catppuccin has its own palette structure. Gitea's native format uses a flat structure. All three need to be supported.
|
||||
**Problem solved:** Different color theme sources have different data structures. Primer design tokens (from GitHub)
|
||||
have hundreds of nested keys. Catppuccin has its own palette structure. Gitea's native format uses a flat structure. All
|
||||
three need to be supported.
|
||||
|
||||
**Solution:** Three conversion paths, all converging on `ThemeVars`:
|
||||
|
||||
@@ -170,13 +179,15 @@ GiteaColor ───────────────────────
|
||||
|
||||
Each path has different complexity requirements:
|
||||
|
||||
| Path | Use case | Complexity | Examples |
|
||||
| -------- | ------------------------------ | ----------------------------------- | ----------------------------- |
|
||||
| `github` | Full Primer token compliance | High (hundreds of mapped keys) | Default, colorblind, high-contrast |
|
||||
| `theme` | 15 base colors, custom theme | Low (auto-derives 200+ CSS vars) | Catppuccin, community themes |
|
||||
| `gitea` | Gitea native color format | Medium (direct mapping) | Gitea-compatible themes |
|
||||
| Path | Use case | Complexity | Examples |
|
||||
| -------- | ---------------------------- | -------------------------------- | ---------------------------------- |
|
||||
| `github` | Full Primer token compliance | High (hundreds of mapped keys) | Default, colorblind, high-contrast |
|
||||
| `theme` | 15 base colors, custom theme | Low (auto-derives 200+ CSS vars) | Catppuccin, community themes |
|
||||
| `gitea` | Gitea native color format | Medium (direct mapping) | Gitea-compatible themes |
|
||||
|
||||
**Design rationale:** The `theme` path is the "onboarding path"—contributors only need to define 15 semantic colors
|
||||
(`red`, `orange`, `yellow`, …, `white`) plus primary and secondary. The framework automatically computes:
|
||||
|
||||
**Design rationale:** The `theme` path is the "onboarding path"—contributors only need to define 15 semantic colors (`red`, `orange`, `yellow`, …, `white`) plus primary and secondary. The framework automatically computes:
|
||||
- 7-level lightness variants (dark-1 through dark-7, light-1 through light-7)
|
||||
- 9-level alpha variants (alpha-10 through alpha-90)
|
||||
- Badge colors and their hover states
|
||||
@@ -188,7 +199,8 @@ Implemented in `theme2ThemeVars()` in [src/palette/theme.ts](src/palette/theme.t
|
||||
|
||||
### 3. CSS Variable Naming Convention
|
||||
|
||||
**Problem solved:** Gitea expects specific CSS variable naming patterns (`--color-primary-dark-1`, `--color-red-badge-bg`, etc.). We need type-safe access in TypeScript (`themeVars.color.primary.dark.num1`).
|
||||
**Problem solved:** Gitea expects specific CSS variable naming patterns (`--color-primary-dark-1`,
|
||||
`--color-red-badge-bg`, etc.). We need type-safe access in TypeScript (`themeVars.color.primary.dark.num1`).
|
||||
|
||||
**Solution:** Use vanilla-extract's `createGlobalThemeContract` with a custom `varMapper`.
|
||||
|
||||
@@ -211,13 +223,13 @@ function varMapper(prefix: string | null = null) {
|
||||
|
||||
This creates a bidirectional mapping:
|
||||
|
||||
| TypeScript access | CSS variable |
|
||||
| ------------------------------------------------ | -------------------------------------- |
|
||||
| `themeVars.color.primary.self` | `--color-primary` |
|
||||
| `themeVars.color.primary.dark.num1` | `--color-primary-dark-1` |
|
||||
| `themeVars.github.button.primary.bgColor.rest` | `--github-button-primary-bgColor-rest` |
|
||||
| `syntaxVars.keyword` | `--color-syntax-keyword` |
|
||||
| `customThemeVars.cloneMenuWidth` | `--custom-clone-menu-width` |
|
||||
| TypeScript access | CSS variable |
|
||||
| ---------------------------------------------- | -------------------------------------- |
|
||||
| `themeVars.color.primary.self` | `--color-primary` |
|
||||
| `themeVars.color.primary.dark.num1` | `--color-primary-dark-1` |
|
||||
| `themeVars.github.button.primary.bgColor.rest` | `--github-button-primary-bgColor-rest` |
|
||||
| `syntaxVars.keyword` | `--color-syntax-keyword` |
|
||||
| `customThemeVars.cloneMenuWidth` | `--custom-clone-menu-width` |
|
||||
|
||||
### 4. Build-Time CSS Syntax Validation
|
||||
|
||||
@@ -236,9 +248,11 @@ export function css(strings: TemplateStringsArray, ...values: CSSInterpolation[]
|
||||
}
|
||||
```
|
||||
|
||||
If a developer writes invalid CSS, the build fails immediately with `file:line` info pointing to the problematic template literal. This catches errors that would otherwise only be discovered through browser DevTools.
|
||||
If a developer writes invalid CSS, the build fails immediately with `file:line` info pointing to the problematic
|
||||
template literal. This catches errors that would otherwise only be discovered through browser DevTools.
|
||||
|
||||
**Trade-off:** Each `css` template call invokes `transform()` once. For ~60 style files, this adds ~200ms to the initial build (one-time cost, subsequent builds benefit from Bun's module cache).
|
||||
**Trade-off:** Each `css` template call invokes `transform()` once. For ~60 style files, this adds ~200ms to the initial
|
||||
build (one-time cost, subsequent builds benefit from Bun's module cache).
|
||||
|
||||
---
|
||||
|
||||
@@ -248,22 +262,29 @@ The build is orchestrated by a custom Vite plugin in [src/vite-plugin/index.ts](
|
||||
|
||||
### Phase 1: Configuration Resolution (`config` hook)
|
||||
|
||||
1. Dynamically import `theme.config.ts` via Bun native TypeScript + package exports self-reference (`@lutinglt/gitea-github-theme/theme.config.ts`)
|
||||
2. Iterate over each theme series, generating entries for each theme variant (dark, light, soft-dark, frappe, macchiato, etc.)
|
||||
1. Dynamically import `theme.config.ts` via Bun native TypeScript + package exports self-reference
|
||||
(`@lutinglt/gitea-github-theme/theme.config.ts`)
|
||||
2. Iterate over each theme series, generating entries for each theme variant (dark, light, soft-dark, frappe, macchiato,
|
||||
etc.)
|
||||
3. When a series has both dark and light variants, auto-generate an `auto` theme entry
|
||||
4. Provide a virtual module entry (Vite needs at least one input to trigger `generateBundle`)
|
||||
|
||||
### Phase 2: CSS Generation (`generateBundle` hook)
|
||||
|
||||
For each **non-auto theme**:
|
||||
|
||||
1. Call `compileCSS()` with a function that:
|
||||
- Creates Gitea theme meta info (`createThemeMetaInfo`) — sets `--theme-color-scheme`, `--theme-display-name`, `--theme-colorblind-type`
|
||||
- Creates theme CSS variables (`createTheme`) — generates all `--color-*` and `--github-*` variables, global styles, keyframe animations, code highlighting
|
||||
- Creates Gitea theme meta info (`createThemeMetaInfo`) — sets `--theme-color-scheme`, `--theme-display-name`,
|
||||
`--theme-colorblind-type`
|
||||
- Creates theme CSS variables (`createTheme`) — generates all `--color-*` and `--github-*` variables, global styles,
|
||||
keyframe animations, code highlighting
|
||||
2. Minify captured CSS via `lightningcss.transform()`
|
||||
3. Append public style overrides (`styles/`)
|
||||
|
||||
For each **auto theme**:
|
||||
1. Generate `@import` declarations with `prefers-color-scheme` media queries referencing the corresponding dark/light theme files
|
||||
|
||||
1. Generate `@import` declarations with `prefers-color-scheme` media queries referencing the corresponding dark/light
|
||||
theme files
|
||||
2. Include theme meta info so Gitea recognizes it as an auto color theme
|
||||
|
||||
### CSS Output Structure
|
||||
@@ -306,14 +327,17 @@ This is **proportional scaling**, not linear offset. Its significance:
|
||||
|
||||
### ThemeColor → ThemeVars Derivation
|
||||
|
||||
`theme2ThemeVars()` in [src/palette/theme.ts](src/palette/theme.ts) takes `ThemeColor` (15 base colors + metadata) and derives the full `ThemeVars` (200+ CSS variable values):
|
||||
`theme2ThemeVars()` in [src/palette/theme.ts](src/palette/theme.ts) takes `ThemeColor` (15 base colors + metadata) and
|
||||
derives the full `ThemeVars` (200+ CSS variable values):
|
||||
|
||||
1. **Primary scale**: 7 dark variants, 7 light variants, 9 alpha variants, hover/active states — all from a single hex color
|
||||
1. **Primary scale**: 7 dark variants, 7 light variants, 9 alpha variants, hover/active states — all from a single hex
|
||||
color
|
||||
2. **Secondary scale**: 13 dark variants, 4 light variants, 9 alpha variants, button hover/active states
|
||||
3. **Named colors** (13 of 15 base colors): each generates self/light/dark-1/dark-2/badge-self/badge-bg/badge-hover-bg
|
||||
4. **Semantic message colors**: bg/border/text with rgba transparency and saturation adjustments
|
||||
5. **ANSI colors**: 16-color palette mapped from named colors
|
||||
6. **Direction-aware**: `isDarkTheme` flag reverses scale direction — "dark" variants in dark themes go toward lighter values (to maintain contrast)
|
||||
6. **Direction-aware**: `isDarkTheme` flag reverses scale direction — "dark" variants in dark themes go toward lighter
|
||||
values (to maintain contrast)
|
||||
|
||||
---
|
||||
|
||||
@@ -326,7 +350,8 @@ Style overrides use Gitea's existing DOM selectors. The override strategy follow
|
||||
1. **Color variables** — All colors reference CSS variables from the theme (never hardcoded hex values)
|
||||
2. **Element-level overrides** — Base elements like `.ui.button`, `#navbar`, `input`
|
||||
3. **Component-level overrides** — Page-specific areas: heatmap, issues, actions, repo pages
|
||||
4. **`!important` escape hatch** — Only used when Gitea sets colors via inline `style` attributes (e.g., heatmap contribution squares)
|
||||
4. **`!important` escape hatch** — Only used when Gitea sets colors via inline `style` attributes (e.g., heatmap
|
||||
contribution squares)
|
||||
|
||||
### cssCombine() Explicit Composition
|
||||
|
||||
@@ -339,11 +364,13 @@ styles/index.ts
|
||||
└── templates/index.ts (template-specific styles)
|
||||
```
|
||||
|
||||
Each leaf module exports `default cssCombine(...)`, chaining CSS fragments together. This explicit composition makes the dependency graph visible and avoids the implicit ordering issues of CSS `@import` or `@use`.
|
||||
Each leaf module exports `default cssCombine(...)`, chaining CSS fragments together. This explicit composition makes the
|
||||
dependency graph visible and avoids the implicit ordering issues of CSS `@import` or `@use`.
|
||||
|
||||
### cssStyle() Reusable Fragments
|
||||
|
||||
`cssStyle()` in [src/core/css.ts](src/core/css.ts) enables extracting reusable CSS property sets while retaining vanilla-extract's type checking:
|
||||
`cssStyle()` in [src/core/css.ts](src/core/css.ts) enables extracting reusable CSS property sets while retaining
|
||||
vanilla-extract's type checking:
|
||||
|
||||
```typescript
|
||||
// In styles/common/button.ts:
|
||||
@@ -362,7 +389,8 @@ const baseButton = css`
|
||||
`;
|
||||
```
|
||||
|
||||
This preserves type safety (vanilla-extract validates property names and value types) in a system that ultimately outputs static CSS strings.
|
||||
This preserves type safety (vanilla-extract validates property names and value types) in a system that ultimately
|
||||
outputs static CSS strings.
|
||||
|
||||
---
|
||||
|
||||
@@ -427,27 +455,36 @@ This preserves type safety (vanilla-extract validates property names and value t
|
||||
|
||||
### Decision 1: Vanilla-Extract for CSS authoring only, not runtime
|
||||
|
||||
**Choice:** Use vanilla-extract's `createGlobalTheme`/`createGlobalThemeContract` for type-safe CSS variable generation, but serialize to static CSS strings at build time via adapter hijacking.
|
||||
**Choice:** Use vanilla-extract's `createGlobalTheme`/`createGlobalThemeContract` for type-safe CSS variable generation,
|
||||
but serialize to static CSS strings at build time via adapter hijacking.
|
||||
|
||||
**Rejected:** Using vanilla-extract's built-in Vite plugin (outputs per-module CSS files, unsuitable for single-file theme output).
|
||||
**Rejected:** Using vanilla-extract's built-in Vite plugin (outputs per-module CSS files, unsuitable for single-file
|
||||
theme output).
|
||||
|
||||
**Trade-off:** Adapter API is undocumented and may change between vanilla-extract versions. Mitigated by locking `@vanilla-extract/css` version and using snapshot tests to detect CSS output changes.
|
||||
**Trade-off:** Adapter API is undocumented and may change between vanilla-extract versions. Mitigated by locking
|
||||
`@vanilla-extract/css` version and using snapshot tests to detect CSS output changes.
|
||||
|
||||
### Decision 2: Single-file CSS output
|
||||
|
||||
**Choice:** Each theme is a single CSS file containing all variables and all style overrides.
|
||||
|
||||
**Rejected:** Splitting into multiple CSS files via `@import` chains (Gitea's theme system loads one CSS file per theme).
|
||||
**Rejected:** Splitting into multiple CSS files via `@import` chains (Gitea's theme system loads one CSS file per
|
||||
theme).
|
||||
|
||||
**Trade-off:** Style overrides are duplicated across all theme files (~60KB × 30 themes ≈ 1.8MB redundancy). This is a Gitea constraint, not a design choice. The alternative (separate common.css) would require Gitea to support multi-file theme loading.
|
||||
**Trade-off:** Style overrides are duplicated across all theme files (~60KB × 30 themes ≈ 1.8MB redundancy). This is a
|
||||
Gitea constraint, not a design choice. The alternative (separate common.css) would require Gitea to support multi-file
|
||||
theme loading.
|
||||
|
||||
### Decision 3: LightningCSS for both syntax validation and output minification
|
||||
|
||||
**Choice:** Use LightningCSS for build-time CSS syntax validation (in `css()` template tag) and output minification (in Vite plugin).
|
||||
**Choice:** Use LightningCSS for build-time CSS syntax validation (in `css()` template tag) and output minification (in
|
||||
Vite plugin).
|
||||
|
||||
**Rejected:** PostCSS (slower), esbuild CSS (less feature-complete), no validation at all.
|
||||
|
||||
**Trade-off:** LightningCSS is lenient—it recovers from many syntax errors rather than throwing. This means validation in `css()` catches severe errors but may silently accept certain edge cases. Build output snapshot tests partially compensate for this.
|
||||
**Trade-off:** LightningCSS is lenient—it recovers from many syntax errors rather than throwing. This means validation
|
||||
in `css()` catches severe errors but may silently accept certain edge cases. Build output snapshot tests partially
|
||||
compensate for this.
|
||||
|
||||
### Decision 4: Bun-only runtime
|
||||
|
||||
@@ -455,15 +492,19 @@ This preserves type safety (vanilla-extract validates property names and value t
|
||||
|
||||
**Rejected:** Cross-runtime support (Node + Bun).
|
||||
|
||||
**Trade-off:** Limits contributor environments. Benefits: native TypeScript execution (no ts-node/esbuild overhead), consistent stack trace format (for debugging utilities), faster builds (Bun native bundler).
|
||||
**Trade-off:** Limits contributor environments. Benefits: native TypeScript execution (no ts-node/esbuild overhead),
|
||||
consistent stack trace format (for debugging utilities), faster builds (Bun native bundler).
|
||||
|
||||
### Decision 5: Package self-referencing for internal imports
|
||||
|
||||
**Choice:** Use `@lutinglt/gitea-github-theme/core` style imports even within the same package, via `exports` mappings in `package.json`.
|
||||
**Choice:** Use `@lutinglt/gitea-github-theme/core` style imports even within the same package, via `exports` mappings
|
||||
in `package.json`.
|
||||
|
||||
**Rejected:** Relative path imports everywhere.
|
||||
|
||||
**Trade-off:** Requires `paths` mappings in `tsconfig.json` for IDE support. Benefits: import paths are consistent whether used as a dependency or developed locally; no path confusion between `src/`, `styles/`, and `themes/` directories.
|
||||
**Trade-off:** Requires `paths` mappings in `tsconfig.json` for IDE support. Benefits: import paths are consistent
|
||||
whether used as a dependency or developed locally; no path confusion between `src/`, `styles/`, and `themes/`
|
||||
directories.
|
||||
|
||||
---
|
||||
|
||||
@@ -479,24 +520,44 @@ import type { ThemeColor, Syntax } from "@lutinglt/gitea-github-theme/core";
|
||||
|
||||
const themeColor: ThemeColor = {
|
||||
isDarkTheme: true,
|
||||
primary: "#8b5cf6", // accent color (purple)
|
||||
primary: "#8b5cf6", // accent color (purple)
|
||||
primaryContrast: "#ffffff",
|
||||
secondary: "#27272a", // border color
|
||||
secondary: "#27272a", // border color
|
||||
base: {
|
||||
red: "#ef4444", orange: "#f97316", yellow: "#eab308",
|
||||
olive: "#84cc16", green: "#22c55e", teal: "#14b8a6",
|
||||
cyan: "#06b6d4", blue: "#3b82f6", violet: "#8b5cf6",
|
||||
purple: "#a855f7", pink: "#ec4899", brown: "#a16207",
|
||||
black: "#18181b", grey: "#71717a", gold: "#eab308",
|
||||
red: "#ef4444",
|
||||
orange: "#f97316",
|
||||
yellow: "#eab308",
|
||||
olive: "#84cc16",
|
||||
green: "#22c55e",
|
||||
teal: "#14b8a6",
|
||||
cyan: "#06b6d4",
|
||||
blue: "#3b82f6",
|
||||
violet: "#8b5cf6",
|
||||
purple: "#a855f7",
|
||||
pink: "#ec4899",
|
||||
brown: "#a16207",
|
||||
black: "#18181b",
|
||||
grey: "#71717a",
|
||||
gold: "#eab308",
|
||||
white: "#fafafa",
|
||||
},
|
||||
console: { /* Actions log colors */ },
|
||||
diff: { /* Code diff colors */ },
|
||||
other: { /* body, text, input, shadow, etc. */ },
|
||||
github: { /* GitHub-specific variables */ },
|
||||
console: {
|
||||
/* Actions log colors */
|
||||
},
|
||||
diff: {
|
||||
/* Code diff colors */
|
||||
},
|
||||
other: {
|
||||
/* body, text, input, shadow, etc. */
|
||||
},
|
||||
github: {
|
||||
/* GitHub-specific variables */
|
||||
},
|
||||
};
|
||||
|
||||
const syntaxColor: Syntax = { /* Code highlighting colors */ };
|
||||
const syntaxColor: Syntax = {
|
||||
/* Code highlighting colors */
|
||||
};
|
||||
|
||||
export default defineTheme({ colorType: "theme", themeColor, syntaxColor });
|
||||
```
|
||||
@@ -518,20 +579,21 @@ export default defineTheme({ colorType: "theme", themeColor, syntaxColor });
|
||||
|
||||
### Full Path (Primer tokens)
|
||||
|
||||
For pixel-perfect GitHub color matching, use the `github` path with direct Primer design token mapping. See `themes/github.ts` and `src/palette/github.ts` for the full mapping reference.
|
||||
For pixel-perfect GitHub color matching, use the `github` path with direct Primer design token mapping. See
|
||||
`themes/github.ts` and `src/palette/github.ts` for the full mapping reference.
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
| Layer | Test type | Location | What it verifies |
|
||||
| ------------ | --------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------- |
|
||||
| Utility | Unit tests | `src/utils.test.ts` | `deepOverride` behavior, `getCallerInfo` stack parsing |
|
||||
| Functions | Unit tests | `src/functions/*.test.ts` | `scaleColorLight` numeric computation, `extractVarName` parsing |
|
||||
| Core | Unit tests | `src/core/css.test.ts` | `css()` validation, `cssCombine()` composition, `cssStyle()` serialization |
|
||||
| Palette | Snapshot tests | `src/palette/*.test.ts` | Full color conversion chains (Primer → ThemeColor → ThemeVars, Catppuccin → ThemeColor → ThemeVars, etc.) |
|
||||
| Palette | Structure tests | `src/palette/github.test.ts` | Color value validity (all leaf nodes are valid CSS color strings), required keys exist |
|
||||
| Build output | Integration | `src/build-output.test.ts` | Expected files exist, CSS content validity (vars present, no debug residue, hex lowercase, color-scheme match), file size limits |
|
||||
| Layer | Test type | Location | What it verifies |
|
||||
| ------------ | --------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Utility | Unit tests | `src/utils.test.ts` | `deepOverride` behavior, `getCallerInfo` stack parsing |
|
||||
| Functions | Unit tests | `src/functions/*.test.ts` | `scaleColorLight` numeric computation, `extractVarName` parsing |
|
||||
| Core | Unit tests | `src/core/css.test.ts` | `css()` validation, `cssCombine()` composition, `cssStyle()` serialization |
|
||||
| Palette | Snapshot tests | `src/palette/*.test.ts` | Full color conversion chains (Primer → ThemeColor → ThemeVars, Catppuccin → ThemeColor → ThemeVars, etc.) |
|
||||
| Palette | Structure tests | `src/palette/github.test.ts` | Color value validity (all leaf nodes are valid CSS color strings), required keys exist |
|
||||
| Build output | Integration | `src/build-output.test.ts` | Expected files exist, CSS content validity (vars present, no debug residue, hex lowercase, color-scheme match), file size limits |
|
||||
|
||||
---
|
||||
|
||||
|
||||
+49
-34
@@ -2,33 +2,36 @@
|
||||
|
||||
## Directory Structure
|
||||
|
||||
| Directory | Description |
|
||||
| ----------------- | ---------------------------------------------- |
|
||||
| src | Theme generation framework and utilities |
|
||||
| Directory | Description |
|
||||
| ----------------- | ----------------------------------------------------------------- |
|
||||
| src | Theme generation framework and utilities |
|
||||
| src/core | Theme generation framework (CSS vars, syntax highlighting styles) |
|
||||
| src/functions | Theme utilities (color calculations, etc.) |
|
||||
| src/palette | Theme palettes (GitHub / Gitea / Catppuccin) |
|
||||
| src/types | Theme color variable type definitions |
|
||||
| src/vite-plugin | Theme Vite build plugin |
|
||||
| styles | Theme style overrides |
|
||||
| styles/common | Reusable CSS style fragments |
|
||||
| styles/public | Base element or cross-page element styles |
|
||||
| styles/components | Page-specific styles |
|
||||
| styles/templates | Template-specific styles |
|
||||
| themes | Color theme definitions |
|
||||
| primer | Auto-generated Primer design tokens |
|
||||
| scripts | Build and utility scripts |
|
||||
| templates | Gitea template overrides (optional) |
|
||||
| gitea | Upstream Gitea reference files |
|
||||
| screenshots | Theme screenshots |
|
||||
| src/functions | Theme utilities (color calculations, etc.) |
|
||||
| src/palette | Theme palettes (GitHub / Gitea / Catppuccin) |
|
||||
| src/types | Theme color variable type definitions |
|
||||
| src/vite-plugin | Theme Vite build plugin |
|
||||
| styles | Theme style overrides |
|
||||
| styles/common | Reusable CSS style fragments |
|
||||
| styles/public | Base element or cross-page element styles |
|
||||
| styles/components | Page-specific styles |
|
||||
| styles/templates | Template-specific styles |
|
||||
| themes | Color theme definitions |
|
||||
| primer | Auto-generated Primer design tokens |
|
||||
| scripts | Build and utility scripts |
|
||||
| templates | Gitea template overrides (optional) |
|
||||
| gitea | Upstream Gitea reference files |
|
||||
| screenshots | Theme screenshots |
|
||||
|
||||
## Contribution Notes
|
||||
|
||||
Style contributions are not recommended, as Gitea themes are ultimately delivered as a single CSS file, which introduces issues like ordering/override conflicts and broad-reaching style impacts.
|
||||
Style contributions are not recommended, as Gitea themes are ultimately delivered as a single CSS file, which introduces
|
||||
issues like ordering/override conflicts and broad-reaching style impacts.
|
||||
|
||||
Each developer has their own approach, making it difficult for review to catch these issues, greatly increasing maintenance difficulty.
|
||||
Each developer has their own approach, making it difficult for review to catch these issues, greatly increasing
|
||||
maintenance difficulty.
|
||||
|
||||
If you have confirmed understanding of Gitea's style layout and the project's approach, please first file an Issue to confirm scope and expected results, then develop and submit a PR.
|
||||
If you have confirmed understanding of Gitea's style layout and the project's approach, please first file an Issue to
|
||||
confirm scope and expected results, then develop and submit a PR.
|
||||
|
||||
If you believe you have a better approach, feel free to submit an Issue.
|
||||
|
||||
@@ -38,13 +41,16 @@ If you believe you have a better approach, feel free to submit an Issue.
|
||||
|
||||
## Development Environment
|
||||
|
||||
The theme depends on the Bun runtime. Please ensure Bun is installed in your environment. Bun 1.3.14 or later is recommended.
|
||||
The theme depends on the Bun runtime. Please ensure Bun is installed in your environment. Bun 1.3.14 or later is
|
||||
recommended.
|
||||
|
||||
Please use VSCode for development and install the recommended extensions in the repository.
|
||||
|
||||
If you prefer fewer extensions, you must install the `vscode-styled-components` extension, which is used for rendering and checking CSS template strings in TypeScript.
|
||||
If you prefer fewer extensions, you must install the `vscode-styled-components` extension, which is used for rendering
|
||||
and checking CSS template strings in TypeScript.
|
||||
|
||||
VSCode 1.102.0 or later is recommended for development, as this version and above support hex color rendering in TypeScript code.
|
||||
VSCode 1.102.0 or later is recommended for development, as this version and above support hex color rendering in
|
||||
TypeScript code.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
@@ -93,8 +99,7 @@ bun commit
|
||||
When referencing across modules, use package exports paths. For example:
|
||||
`import { defineTheme } from "@lutinglt/gitea-github-theme/core"`
|
||||
|
||||
When referencing files within the same module, use relative paths. For example:
|
||||
`import { defineTheme } from "./theme"`
|
||||
When referencing files within the same module, use relative paths. For example: `import { defineTheme } from "./theme"`
|
||||
|
||||
## Color Theme Contributions
|
||||
|
||||
@@ -102,13 +107,16 @@ Theme file naming format: `themeName.ts`, used together with `theme.config.ts` r
|
||||
|
||||
If a theme has both dark and light variants, the framework automatically generates an auto color theme.
|
||||
|
||||
The project accepts custom themes and will include them in published releases, but the project owner does not participate in their maintenance or review.
|
||||
The project accepts custom themes and will include them in published releases, but the project owner does not
|
||||
participate in their maintenance or review.
|
||||
|
||||
Please add your author info at the top of the color theme file so Issue reporters can `@` mention you.
|
||||
|
||||
It is recommended to use `defineTheme` with the `ThemeColor` type to define theme colors. The framework will automatically compute and generate all Gitea CSS variables.
|
||||
It is recommended to use `defineTheme` with the `ThemeColor` type to define theme colors. The framework will
|
||||
automatically compute and generate all Gitea CSS variables.
|
||||
|
||||
Color calculation functions can be imported from `@lutinglt/gitea-github-theme/core` (`scaleColorLight`), or use the `polished` library.
|
||||
Color calculation functions can be imported from `@lutinglt/gitea-github-theme/core` (`scaleColorLight`), or use the
|
||||
`polished` library.
|
||||
|
||||
Example: `themes/my-theme.ts`
|
||||
|
||||
@@ -162,7 +170,9 @@ const syntaxColor: Syntax = {
|
||||
export default defineTheme({ colorType: "gitea", themeColor: giteaColor, syntaxColor });
|
||||
```
|
||||
|
||||
After completing theme color development, register the theme series in `theme.config.ts`, compile it, and take screenshots in a Gitea instance. Place them in the `screenshots` directory with filenames matching the theme names. (Cloning the repository is recommended to avoid leaking personal information.)
|
||||
After completing theme color development, register the theme series in `theme.config.ts`, compile it, and take
|
||||
screenshots in a Gitea instance. Place them in the `screenshots` directory with filenames matching the theme names.
|
||||
(Cloning the repository is recommended to avoid leaking personal information.)
|
||||
|
||||
Then add screenshot information to `README.md`.
|
||||
|
||||
@@ -170,12 +180,17 @@ For color reuse patterns, see the colorblind theme implementation in `themes/git
|
||||
|
||||
## Theme Style Contributions
|
||||
|
||||
Theme styles use the `css()` template string for development. Strings are processed by LightningCSS and support CSS nesting syntax. Do not use SCSS functions; for complex processing, use TypeScript libraries such as the bundled `polished` library.
|
||||
Theme styles use the `css()` template string for development. Strings are processed by LightningCSS and support CSS
|
||||
nesting syntax. Do not use SCSS functions; for complex processing, use TypeScript libraries such as the bundled
|
||||
`polished` library.
|
||||
|
||||
For complex logic, it is recommended to extract it into functions under the `src/functions` directory.
|
||||
|
||||
All colors used in theme styles must use color variables. Import them via `import { themeVars } from "@lutinglt/gitea-github-theme/core"`.
|
||||
All colors used in theme styles must use color variables. Import them via
|
||||
`import { themeVars } from "@lutinglt/gitea-github-theme/core"`.
|
||||
|
||||
When using theme-specific color variables like `${themeVars.github.xxx}`, please add the file and variable to the corresponding variable's comment in `src/types/color/github`.
|
||||
When using theme-specific color variables like `${themeVars.github.xxx}`, please add the file and variable to the
|
||||
corresponding variable's comment in `src/types/color/github`.
|
||||
|
||||
For small border-radius values (6px), use the global border-radius variable. Import via `import { otherThemeVars } from "@lutinglt/gitea-github-theme/core"` and use `${otherThemeVars.border.radius}`.
|
||||
For small border-radius values (6px), use the global border-radius variable. Import via
|
||||
`import { otherThemeVars } from "@lutinglt/gitea-github-theme/core"` and use `${otherThemeVars.border.radius}`.
|
||||
@@ -21,7 +21,7 @@ import { execSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT_DIR = path.resolve(__dirname, "..");
|
||||
@@ -120,7 +120,7 @@ describe("非 auto 主题 CSS 内容验证", () => {
|
||||
describe(fileName, () => {
|
||||
let css: string;
|
||||
|
||||
it.beforeAll(() => {
|
||||
beforeAll(() => {
|
||||
css = fs.readFileSync(path.join(DIST_DIR, fileName), "utf-8");
|
||||
});
|
||||
|
||||
@@ -163,7 +163,7 @@ describe("auto 主题 CSS 内容验证", () => {
|
||||
describe(fileName, () => {
|
||||
let css: string;
|
||||
|
||||
it.beforeAll(() => {
|
||||
beforeAll(() => {
|
||||
css = fs.readFileSync(path.join(DIST_DIR, fileName), "utf-8");
|
||||
});
|
||||
|
||||
|
||||
+1
-2
@@ -21,6 +21,5 @@ export { createChroma } from "./chroma";
|
||||
export { createCodeMirror } from "./codemirror";
|
||||
export { css, cssCombine, cssStyle } from "./css";
|
||||
export { createThemeMetaInfo, type ColorblindType, type GiteaThemeMeta } from "./meta";
|
||||
export { createTheme, defineTheme } from "./theme";
|
||||
export type { Theme, ThemeVars } from "./theme";
|
||||
export { createTheme, defineTheme, type Theme, type ThemeVars } from "./theme";
|
||||
export type { CSSVarFunction, MapLeafNodes } from "./types";
|
||||
@@ -17,8 +17,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { StyleRule } from "@vanilla-extract/css";
|
||||
import { globalStyle } from "@vanilla-extract/css";
|
||||
import { globalStyle, type StyleRule } 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";
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
|
||||
import { transform } from "lightningcss";
|
||||
import type { PluginOption } from "vite";
|
||||
import type { GiteaThemeMeta, Theme } from "../core";
|
||||
import { createTheme, createThemeMetaInfo } from "../core";
|
||||
import { createTheme, createThemeMetaInfo, type GiteaThemeMeta, type Theme } from "../core";
|
||||
import { compileCSS } from "../vanilla-extract";
|
||||
import { buildFullDisplayName, buildFullThemeName } from "./utils";
|
||||
|
||||
|
||||
Reference in new issue
Block a user