feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled

Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
2026-08-13 18:34:25 +08:00
parent 61c3fa1df9
commit 9dfa06ffee
3785 changed files with 1085458 additions and 2 deletions
+115
View File
@@ -0,0 +1,115 @@
import 'theme_catalog.dart';
/// Light → dark theme counterparts, ported from the desktop app's `THEME_PAIRS`
/// (`desktop/src/shared/theme/theme-loader.ts`) so both clients offer the same
/// System-mode pairings.
///
/// Buzz leads the map the way it leads desktop's, so the first-party pair sorts
/// ahead of the borrowed syntax themes wherever insertion order is preserved.
const themePairs = <String, String>{
'buzz': 'buzz-dark',
'catppuccin-latte': 'catppuccin-mocha',
'everforest-light': 'everforest-dark',
'github-light': 'github-dark',
'github-light-default': 'github-dark-default',
'github-light-high-contrast': 'github-dark-high-contrast',
'gruvbox-light-hard': 'gruvbox-dark-hard',
'gruvbox-light-medium': 'gruvbox-dark-medium',
'gruvbox-light-soft': 'gruvbox-dark-soft',
'kanagawa-lotus': 'kanagawa-wave',
'light-plus': 'dark-plus',
'material-theme-lighter': 'material-theme',
'min-light': 'min-dark',
'one-light': 'one-dark-pro',
'rose-pine-dawn': 'rose-pine',
'slack-ochin': 'slack-dark',
'solarized-light': 'solarized-dark',
'vitesse-light': 'vitesse-dark',
};
final Map<String, String> _darkToLight = {
for (final entry in themePairs.entries) entry.value: entry.key,
};
/// The counterpart of [name] in the opposite brightness, or null when the theme
/// has no pair. Resolves in both directions.
String? themePairFor(String name) => themePairs[name] ?? _darkToLight[name];
/// Whether [name] participates in a light/dark pair, and so can follow the OS.
bool isPairedTheme(String name) => themePairFor(name) != null;
/// [themeCatalog] partitioned the way the appearance picker offers it.
class ThemeGroups {
/// Light members of light/dark pairs — the System-mode options. Each stands
/// in for both halves of its pair.
final List<ThemeColors> paired;
/// Every light theme, paired or not — the Light-mode options.
final List<ThemeColors> light;
/// Every dark theme, paired or not — the Dark-mode options.
final List<ThemeColors> dark;
const ThemeGroups({
required this.paired,
required this.light,
required this.dark,
});
}
ThemeGroups? _groups;
/// [themeCatalog] grouped for the appearance picker, each list sorted by
/// display name. Computed once — the catalog is a compile-time constant.
ThemeGroups themeGroups() {
final cached = _groups;
if (cached != null) return cached;
final paired = <ThemeColors>[];
final light = <ThemeColors>[];
final dark = <ThemeColors>[];
for (final theme in themeCatalog) {
if (theme.isDark) {
dark.add(theme);
continue;
}
light.add(theme);
if (themePairs.containsKey(theme.name)) paired.add(theme);
}
int byDisplayName(ThemeColors a, ThemeColors b) =>
a.displayName.compareTo(b.displayName);
paired.sort(byDisplayName);
light.sort(byDisplayName);
dark.sort(byDisplayName);
return _groups = ThemeGroups(paired: paired, light: light, dark: dark);
}
/// Tokens that only describe a theme's brightness, stripped from paired labels.
const _modeTokens = <String>{
'light',
'latte',
'dawn',
'lotus',
'ochin',
'lighter',
'plus',
};
/// Display label for a pair, derived from its light member: strips the
/// mode-specific tokens so `github-light` reads as "Github" and stands for both
/// halves. Mirrors desktop's `pairedThemeLabel`.
String pairedThemeLabel(String lightName) {
final stripped = lightName
.split('-')
.where((token) => !_modeTokens.contains(token))
.toList();
// Stripping can remove everything (e.g. "light-plus") — fall back to the raw
// name so the row is never blank.
final parts = stripped.isEmpty ? lightName.split('-') : stripped;
return parts
.map((w) => w.isEmpty ? w : '${w[0].toUpperCase()}${w.substring(1)}')
.join(' ');
}