Merge pull request 'New desgin' (#27) from new-desgin into main

Reviewed-on: #27
This commit was merged in pull request #27.
This commit is contained in:
2026-08-23 21:15:39 +00:00
4 changed files with 929 additions and 66 deletions
+106 -2
View File
@@ -146,10 +146,12 @@
AiReviewResult,
AiCommitPlan,
AiSettings,
AppAppearance,
AppLanguage,
AppTheme,
AnalyticsSettings,
CommitAiPhase,
CustomThemeColors,
ConflictFile,
DetectedExternalTool,
ExplorerNode,
@@ -253,6 +255,8 @@
const AI_SETTINGS_KEY = "gitlite.aiSettings.v1";
const ANALYTICS_SETTINGS_KEY = "gitlite.analyticsSettings.v1";
const APP_THEME_KEY = "gitlite.theme.v1";
const APP_APPEARANCE_KEY = "gitlite.appearance.v1";
const CUSTOM_THEME_KEY = "gitlite.customTheme.v1";
const APP_LANGUAGE_KEY = "gitlite.language.v1";
const EXTERNAL_TOOLS_SETTINGS_KEY = "gitlite.externalTools.v1";
const AUTO_REFRESH_ENABLED_KEY = "gitlite.autoRefreshEnabled.v1";
@@ -364,6 +368,8 @@
let analyticsNoticeOpen = false;
let analyticsSettings: AnalyticsSettings = defaultAnalyticsSettings();
let appTheme: AppTheme = loadThemePreference();
let appAppearance: AppAppearance = loadAppearancePreference();
let customTheme: CustomThemeColors = loadCustomTheme();
let appLanguage: AppLanguage = loadLanguagePreference();
let externalToolsSettings: ExternalToolsSettings = loadExternalToolsSettings();
let externalToolsConfigured = hasStoredExternalToolsSettings();
@@ -555,6 +561,7 @@
$: fileManagerToolName = externalToolDisplayName("fileManager", externalToolsSettings.fileManager, detectedExternalTools);
$: applyThemePreference(appTheme);
$: applyAppearancePreference(appAppearance, customTheme);
$: applyLanguagePreference(appLanguage);
// ── Lifecycle ──────────────────────────────────────────────────────────────
@@ -1119,6 +1126,98 @@
}
}
function defaultCustomTheme(): CustomThemeColors {
return {
background: "#cfd5dc",
surface: "#e2e6ea",
accent: "#2eb5d1",
text: "#222328",
};
}
function isHexColor(value: unknown): value is string {
return typeof value === "string" && /^#[0-9a-f]{6}$/i.test(value);
}
function loadAppearancePreference(): AppAppearance {
try {
const stored = localStorage.getItem(APP_APPEARANCE_KEY);
if (stored === "modern" || stored === "classic" || stored === "custom") return stored;
} catch {
// Local storage is optional; the current design remains the default.
}
return "modern";
}
function loadCustomTheme(): CustomThemeColors {
const fallback = defaultCustomTheme();
try {
const stored = JSON.parse(localStorage.getItem(CUSTOM_THEME_KEY) ?? "null") as Partial<CustomThemeColors> | null;
if (!stored) return fallback;
return {
background: isHexColor(stored.background) ? stored.background : fallback.background,
surface: isHexColor(stored.surface) ? stored.surface : fallback.surface,
accent: isHexColor(stored.accent) ? stored.accent : fallback.accent,
text: isHexColor(stored.text) ? stored.text : fallback.text,
};
} catch {
return fallback;
}
}
function persistAppearancePreference(next: AppAppearance, colors: CustomThemeColors) {
try {
localStorage.setItem(APP_APPEARANCE_KEY, next);
localStorage.setItem(CUSTOM_THEME_KEY, JSON.stringify(colors));
} catch {
// Ignore storage quota/private-mode errors.
}
}
function applyAppearancePreference(next: AppAppearance, colors: CustomThemeColors) {
const root = document.documentElement;
root.dataset.appearance = next;
const customProperties = [
"--app-bg", "--app-button-bg", "--app-input-bg", "--app-dialog-bg", "--app-dialog-chrome",
"--app-settings-row-bg", "--color-surface", "--color-surface-alt", "--color-surface-dim",
"--color-surface-hover", "--color-surface-raised", "--color-surface-solid", "--color-border",
"--color-border-subtle", "--color-border-input", "--color-primary", "--color-primary-dark",
"--color-accent", "--color-ink", "--color-ink-muted", "--color-ink-faint", "--color-ink-dim",
"--color-bar-text", "--color-bar-muted",
];
customProperties.forEach((property) => root.style.removeProperty(property));
if (next !== "custom") return;
const { background, surface, accent, text } = colors;
const values: Record<string, string> = {
"--app-bg": background,
"--app-button-bg": surface,
"--app-input-bg": `color-mix(in srgb, ${surface} 88%, white)`,
"--app-dialog-bg": surface,
"--app-dialog-chrome": `color-mix(in srgb, ${surface} 90%, ${background})`,
"--app-settings-row-bg": `color-mix(in srgb, ${surface} 92%, ${background})`,
"--color-surface": surface,
"--color-surface-alt": `color-mix(in srgb, ${surface} 82%, ${background})`,
"--color-surface-dim": `color-mix(in srgb, ${surface} 88%, ${background})`,
"--color-surface-hover": `color-mix(in srgb, ${surface} 88%, ${text})`,
"--color-surface-raised": `color-mix(in srgb, ${surface} 92%, white)`,
"--color-surface-solid": surface,
"--color-border": `color-mix(in srgb, ${text} 32%, ${surface})`,
"--color-border-subtle": `color-mix(in srgb, ${text} 18%, ${surface})`,
"--color-border-input": `color-mix(in srgb, ${text} 38%, ${surface})`,
"--color-primary": accent,
"--color-primary-dark": `color-mix(in srgb, ${accent} 82%, black)`,
"--color-accent": accent,
"--color-ink": text,
"--color-ink-muted": `color-mix(in srgb, ${text} 76%, ${surface})`,
"--color-ink-faint": `color-mix(in srgb, ${text} 58%, ${surface})`,
"--color-ink-dim": `color-mix(in srgb, ${text} 68%, ${surface})`,
"--color-bar-text": text,
"--color-bar-muted": `color-mix(in srgb, ${text} 62%, ${surface})`,
};
Object.entries(values).forEach(([property, value]) => root.style.setProperty(property, value));
}
function loadLanguagePreference(): AppLanguage {
try {
const stored = localStorage.getItem(APP_LANGUAGE_KEY);
@@ -1157,15 +1256,18 @@
if (appTheme === "system") applyThemePreference(appTheme);
}
function saveAppSettings(next: AnalyticsSettings, nextTheme: AppTheme, nextLanguage: AppLanguage, nextAutoRefresh: boolean, nextExternalTools: ExternalToolsSettings) {
function saveAppSettings(next: AnalyticsSettings, nextTheme: AppTheme, nextAppearance: AppAppearance, nextCustomTheme: CustomThemeColors, nextLanguage: AppLanguage, nextAutoRefresh: boolean, nextExternalTools: ExternalToolsSettings) {
const autoRefreshWasEnabled = autoRefreshEnabled;
analyticsSettings = next;
appTheme = nextTheme;
appAppearance = nextAppearance;
customTheme = nextCustomTheme;
appLanguage = nextLanguage;
autoRefreshEnabled = nextAutoRefresh;
externalToolsSettings = nextExternalTools;
persistAnalyticsSettings(next);
persistThemePreference(nextTheme);
persistAppearancePreference(nextAppearance, nextCustomTheme);
persistLanguagePreference(nextLanguage);
persistStoredBoolean(AUTO_REFRESH_ENABLED_KEY, nextAutoRefresh);
persistExternalToolsSettings(nextExternalTools);
@@ -1173,7 +1275,7 @@
setTelemetryEnabled(next.enabled);
appSettingsOpen = false;
if (nextAutoRefresh && !autoRefreshWasEnabled) void autoRefreshTick();
if (next.enabled) trackEvent("settings_saved", { analytics_enabled: 1, theme: nextTheme, language: nextLanguage, auto_refresh: nextAutoRefresh ? 1 : 0 });
if (next.enabled) trackEvent("settings_saved", { analytics_enabled: 1, theme: nextTheme, appearance: nextAppearance, language: nextLanguage, auto_refresh: nextAutoRefresh ? 1 : 0 });
}
function updateCommitMessage(message: string) {
@@ -5599,6 +5701,8 @@
<AppSettingsDialog
analytics={analyticsSettings}
theme={appTheme}
appearance={appAppearance}
customTheme={customTheme}
language={appLanguage}
autoRefresh={autoRefreshEnabled}
externalTools={externalToolsSettings}
+713 -62
View File
@@ -1,57 +1,57 @@
@import "tailwindcss";
@theme {
--color-ink: #edf3ff;
--color-ink-muted: #b1bad0;
--color-ink-faint: #6f7c96;
--color-ink-dim: #8895ad;
--color-ink-quiet: #98a4bb;
--color-ink: #f0f1f2;
--color-ink-muted: #c1c3c6;
--color-ink-faint: #7f8389;
--color-ink-dim: #9da1a6;
--color-ink-quiet: #aeb1b5;
--color-surface: rgba(18, 23, 34, 0.88);
--color-surface-alt: #090d14;
--color-surface-dim: rgba(15, 20, 30, 0.94);
--color-surface-hover: rgba(36, 45, 64, 0.78);
--color-surface-raised: rgba(23, 29, 43, 0.92);
--color-surface-solid: #171d2b;
--color-surface: #2b2e34;
--color-surface-alt: #1b1c1e;
--color-surface-dim: #2e3137;
--color-surface-hover: #363a41;
--color-surface-raised: #32363d;
--color-surface-solid: #222328;
--color-border: rgba(90, 111, 154, 0.3);
--color-border-subtle: rgba(226, 232, 240, 0.08);
--color-border-input: rgba(77, 182, 214, 0.26);
--color-border: #3a3e45;
--color-border-subtle: #34383e;
--color-border-input: #465159;
--color-primary: #6f8cff;
--color-primary-dark: #5d74e8;
--color-accent: #4db6d6;
--color-primary: #25a7c7;
--color-primary-dark: #188ca9;
--color-accent: #2eb5d1;
--color-bar: rgba(7, 10, 16, 0.94);
--color-bar-text: #f1f5ff;
--color-bar-muted: #7f8ba3;
--color-bar: #292c30;
--color-bar-text: #f0f1f2;
--color-bar-muted: #8b8f94;
--font-mono: "Cascadia Code", "SFMono-Regular", Consolas, monospace;
}
:root {
--app-color-scheme: dark;
--app-bg: linear-gradient(135deg, #070a10 0%, #0c111a 48%, #090e16 100%);
--app-button-bg: linear-gradient(180deg, rgba(36, 45, 64, 0.92), rgba(22, 28, 42, 0.94));
--app-input-bg: rgba(10, 14, 22, 0.82);
--app-select-option-bg: #171d2b;
--app-bg: #222328;
--app-button-bg: #32363d;
--app-input-bg: #22252a;
--app-select-option-bg: #32363d;
--app-panel-highlight: linear-gradient(180deg, rgba(255,255,255,0.038), transparent 70%);
--app-panel-shadow: 0 18px 48px rgba(0,0,0,0.28), inset 0 1px 0 rgba(255,255,255,0.045);
--app-dialog-backdrop: rgba(4, 7, 12, 0.58);
--app-dialog-bg: #101622;
--app-dialog-chrome: #141b29;
--app-dialog-backdrop: rgba(12, 13, 15, 0.7);
--app-dialog-bg: #22252a;
--app-dialog-chrome: #2b2e34;
--app-dialog-shadow: 0 24px 68px rgba(0, 0, 0, 0.54), 0 2px 12px rgba(0,0,0,0.32);
--app-settings-row-bg: #141b29;
--app-scrollbar-thumb: #303a4f;
--app-scrollbar-thumb-hover: #44506a;
--app-settings-row-bg: #2b2e34;
--app-scrollbar-thumb: #4a4e55;
--app-scrollbar-thumb-hover: #60656d;
--code-surface: #111321;
--code-surface-raised: #171a2b;
--code-surface-subtle: #0d101a;
--code-surface-muted: #10131e;
--code-surface-meta: #0c0e18;
--code-input-bg: #0b0e18;
--code-hover-bg: #151a2b;
--code-surface: #222328;
--code-surface-raised: #2b2e34;
--code-surface-subtle: #1f2024;
--code-surface-muted: #26282d;
--code-surface-meta: #1d1e22;
--code-input-bg: #22252a;
--code-hover-bg: #30343a;
--code-add-text: #5dd88a;
--code-add-strong: #4eca76;
--code-add-bg: rgba(78, 202, 118, 0.09);
@@ -190,7 +190,7 @@
}
input:focus, textarea:focus, select:focus {
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(100, 108, 255, 0.22), 0 0 32px rgba(65, 209, 255, 0.08);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 20%, transparent), 0 0 30px color-mix(in srgb, var(--color-accent) 7%, transparent);
}
input { height: 34px; padding: 0 11px; }
textarea { resize: vertical; min-height: 132px; padding: 10px 11px; line-height: 1.45; }
@@ -334,15 +334,15 @@
}
.btn-primary {
border-color: rgba(111, 140, 255, 0.72);
border-color: color-mix(in srgb, var(--color-primary) 82%, white);
color: #ffffff;
background: linear-gradient(135deg, #5f7df2 0%, #238eb4 100%);
box-shadow: 0 10px 24px rgba(77, 182, 214, 0.16);
background: var(--color-primary);
box-shadow: none;
font-weight: 600;
}
.btn-primary:hover:not(:disabled) {
border-color: rgba(77, 182, 214, 0.78);
background: linear-gradient(135deg, #6f8cff 0%, #2da0c7 100%);
border-color: color-mix(in srgb, var(--color-accent) 78%, white);
background: var(--color-accent);
color: #ffffff;
}
@@ -6227,22 +6227,23 @@
--ui-radius-sm: 5px;
--ui-control-height: 32px;
--ui-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
--app-bg: #0d1118;
--app-button-bg: #171d27;
--app-input-bg: #101620;
--app-bg: #222328;
--app-button-bg: #32363d;
--app-input-bg: #22252a;
--app-panel-highlight: none;
--app-panel-shadow: none;
--color-surface: #111720;
--color-surface-alt: #0d121a;
--color-surface-dim: #141b25;
--color-surface-hover: #1b2431;
--color-surface-raised: #151c27;
--color-surface-solid: #111720;
--color-border: #2a3546;
--color-border-subtle: #222c3a;
--color-primary: #4d8dff;
--color-primary-dark: #3477ed;
--color-accent: #65a2ff;
--color-surface: #2b2e34;
--color-surface-alt: #1b1c1e;
--color-surface-dim: #2e3137;
--color-surface-hover: #363a41;
--color-surface-raised: #32363d;
--color-surface-solid: #222328;
--color-border: #3a3e45;
--color-border-subtle: #34383e;
--color-border-input: #465159;
--color-primary: #25a7c7;
--color-primary-dark: #188ca9;
--color-accent: #2eb5d1;
}
:root[data-theme="light"] {
@@ -6279,8 +6280,8 @@ button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
outline: 2px solid color-mix(in srgb, var(--color-primary) 65%, transparent);
outline-offset: 1px;
outline: 2px solid color-mix(in srgb, var(--color-accent) 88%, transparent);
outline-offset: 2px;
}
input, textarea, select { border-radius: var(--ui-radius-sm); }
input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 16%, transparent); }
@@ -6289,7 +6290,7 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
.shell-body { gap: 0; padding: 0; }
.titlebar {
border-bottom: 1px solid var(--color-border-subtle);
background: var(--color-surface-solid);
background: var(--color-bar);
}
.titlebar-brand { min-width: 140px; padding-left: 14px; border-right: 0; font-size: 14px; }
.titlebar-brand-icon,
@@ -6332,7 +6333,7 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
border: 0;
border-bottom: 1px solid var(--color-border);
border-radius: 0;
background: var(--color-surface-solid);
background: var(--color-surface-raised);
}
.repo-toolbar-sync { grid-template-rows: 10px 36px; }
.repo-toolbar-group-label { padding-left: 1px; font-size: 8.5px; letter-spacing: .13em; }
@@ -6348,7 +6349,7 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
background: var(--color-border-subtle);
row-gap: 0;
}
.left-sidebar { background: var(--color-surface-solid); }
.left-sidebar { background: var(--color-surface); }
.main-panel { border: 0; border-radius: 0; background: var(--color-surface-solid); }
.history-aside { background: var(--color-border-subtle); row-gap: 0; }
@@ -6360,6 +6361,7 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
backdrop-filter: none;
}
.left-sidebar .panel + .panel { border-top: 1px solid var(--color-border); }
.left-sidebar .panel { background: var(--color-surface); }
.section-head {
min-height: 50px;
padding: 8px 12px;
@@ -6720,6 +6722,184 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
.repo-section > header { background: var(--color-surface-dim); }
.repo-row-main:hover:not(:disabled) { background: var(--color-surface-hover); }
/* Dark control contrast --------------------------------------------------
Keep GitKraken's restrained graphite palette while making interactive
boundaries and text states unambiguous on every dark surface. */
:root:not([data-theme="light"]) .btn-primary {
border-color: #2eb5d1;
color: #ffffff;
background: #126f84;
}
:root:not([data-theme="light"]) .btn-primary:hover:not(:disabled) {
border-color: #55c5dc;
color: #ffffff;
background: #147c94;
}
:root:not([data-theme="light"]) .btn-secondary {
border-color: #596169;
color: #d7dadc;
background: #32363d;
}
:root:not([data-theme="light"]) .btn-secondary:hover:not(:disabled) {
border-color: #707982;
color: #ffffff;
background: #41464d;
}
:root:not([data-theme="light"]) input,
:root:not([data-theme="light"]) textarea,
:root:not([data-theme="light"]) select,
:root:not([data-theme="light"]) .select-menu-trigger {
border-color: #596169;
}
:root:not([data-theme="light"]) input:hover:not(:disabled),
:root:not([data-theme="light"]) textarea:hover:not(:disabled),
:root:not([data-theme="light"]) select:hover:not(:disabled),
:root:not([data-theme="light"]) .select-menu-trigger:hover:not(:disabled) {
border-color: #707982;
}
:root:not([data-theme="light"]) input:focus,
:root:not([data-theme="light"]) textarea:focus,
:root:not([data-theme="light"]) select:focus,
:root:not([data-theme="light"]) .select-menu.open .select-menu-trigger {
border-color: var(--color-accent);
}
:root:not([data-theme="light"]) .repo-action-group,
:root:not([data-theme="light"]) .dialog-icon-button {
border-color: #535a62;
}
:root:not([data-theme="light"]) .repo-action:hover:not(:disabled),
:root:not([data-theme="light"]) .repo-action.active,
:root:not([data-theme="light"]) .dialog-icon-button:hover:not(:disabled) {
border-color: #707982;
background: #3b4047;
}
/* Dark app chrome separation -------------------------------------------
Tabs, command toolbar and workspace should read as three adjacent
layers instead of one uninterrupted gray strip. */
:root:not([data-theme="light"]) .repo-tabbar {
border-bottom-color: #505760;
background: #26292f;
box-shadow:
inset 0 -1px 0 #191b1f,
0 1px 0 rgba(255, 255, 255, 0.035);
}
:root:not([data-theme="light"]) .repo-tabs-scroll {
border-left-color: #454b53;
}
:root:not([data-theme="light"]) .repo-tab-wrap {
border-right-color: #454b53;
background: #292c32;
}
:root:not([data-theme="light"]) .repo-tab-wrap:hover {
background: #30343a;
}
:root:not([data-theme="light"]) .repo-tab-wrap.active,
:root:not([data-theme="light"]) .repo-tab.management.active {
background: #343941;
box-shadow:
inset 0 -3px 0 var(--color-accent),
inset 1px 0 0 #4c535b,
inset -1px 0 0 #4c535b,
inset 0 1px 0 rgba(255, 255, 255, 0.045);
}
:root:not([data-theme="light"]) .repo-tab-add {
border-left-color: #454b53;
background: #292c32;
}
:root:not([data-theme="light"]) .repo-toolbar {
border-top: 1px solid #424850;
border-bottom-color: #505760;
background: #30343a;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.035),
0 2px 0 #191b1f;
}
:root:not([data-theme="light"]) .repo-action-group {
border-color: #596169;
background: #292d32;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.035);
}
:root:not([data-theme="light"]) .repo-action-group > .repo-action,
:root:not([data-theme="light"]) .repo-action-group > .repo-history-wrap > .repo-action {
border-right-color: #484e55;
}
:root:not([data-theme="light"]) .repo-toolbar-divider {
background: #555c64;
}
:root:not([data-theme="light"]) .workspace {
box-shadow: inset 0 1px 0 #17191c;
}
/* Light app chrome separation ------------------------------------------
Keep the same layered hierarchy as the dark theme with restrained,
cool-gray borders and a clean white active surface. */
:root[data-theme="light"] .repo-tabbar {
border-bottom-color: #aeb8c5;
background: #e9edf2;
box-shadow:
inset 0 -1px 0 #d2d9e2,
0 1px 0 rgba(255, 255, 255, 0.9);
}
:root[data-theme="light"] .repo-tabs-scroll {
border-left-color: #c3cbd5;
}
:root[data-theme="light"] .repo-tab-wrap {
border-right-color: #c3cbd5;
background: #eef1f5;
}
:root[data-theme="light"] .repo-tab-wrap:hover {
background: #e3e8ee;
}
:root[data-theme="light"] .repo-tab-wrap.active,
:root[data-theme="light"] .repo-tab.management.active {
background: #ffffff;
box-shadow:
inset 0 -3px 0 var(--color-primary),
inset 1px 0 0 #b7c1cd,
inset -1px 0 0 #b7c1cd,
inset 0 1px 0 rgba(255, 255, 255, 0.95);
}
:root[data-theme="light"] .repo-tab-add {
border-left-color: #c3cbd5;
background: #eef1f5;
}
:root[data-theme="light"] .repo-toolbar {
border-top: 1px solid #c4ccd6;
border-bottom-color: #aeb8c5;
background: #f4f6f8;
box-shadow:
inset 0 1px 0 #ffffff,
0 2px 0 #d6dce4;
}
:root[data-theme="light"] .repo-action-group {
border-color: #aeb8c5;
background: #ffffff;
box-shadow:
inset 0 1px 0 #ffffff,
0 1px 2px rgba(34, 49, 78, 0.06);
}
:root[data-theme="light"] .repo-action-group > .repo-action,
:root[data-theme="light"] .repo-action-group > .repo-history-wrap > .repo-action {
border-right-color: #c8d0da;
}
:root[data-theme="light"] .repo-toolbar-divider {
background: #b5bec9;
}
:root[data-theme="light"] .workspace {
box-shadow: inset 0 1px 0 #c9d1db;
}
@media (max-width: 1180px) {
.repo-action { padding-inline: 10px; }
.repo-toolbar-divider { margin-inline: 2px; }
@@ -7872,3 +8052,474 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
.status-lane-head { align-items: flex-start; flex-direction: column; }
.status-lane-actions { width: 100%; justify-content: flex-start; }
}
/* Muted light theme -----------------------------------------------------
A lower-luminance light palette for long sessions. The hierarchy stays
light and readable without using pure white for every working surface. */
:root[data-theme="light"] {
--ui-shadow: 0 10px 26px rgba(29, 39, 52, 0.12);
--app-bg: #cfd5dc;
--app-button-bg: #e2e7eb;
--app-input-bg: #e9edf0;
--app-select-option-bg: #e7ebef;
--app-dialog-backdrop: rgba(91, 103, 117, 0.38);
--app-dialog-bg: #e2e6ea;
--app-dialog-chrome: #d7dde3;
--app-settings-row-bg: #dce2e7;
--app-scrollbar-thumb: #aab4be;
--app-scrollbar-thumb-hover: #929eaa;
--color-ink: #202832;
--color-ink-muted: #4d5a68;
--color-ink-faint: #687583;
--color-ink-dim: #596674;
--color-ink-quiet: #62707e;
--color-surface: #e2e6ea;
--color-surface-alt: #d8dde3;
--color-surface-dim: #dce1e6;
--color-surface-hover: #cfd6de;
--color-surface-raised: #e7ebee;
--color-surface-solid: #e1e5e9;
--color-border: #9faab5;
--color-border-subtle: #bbc3cc;
--color-border-input: #98a5b2;
--color-bar: #d6dce2;
--color-bar-text: #202832;
--color-bar-muted: #596674;
--code-surface: #e1e5e9;
--code-surface-raised: #d9dfe5;
--code-surface-subtle: #dce2e7;
--code-surface-muted: #d4dae0;
--code-surface-meta: #ced5dc;
--code-input-bg: #e8ecef;
--code-hover-bg: #cfd7df;
}
:root[data-theme="light"] .titlebar {
background:
linear-gradient(90deg, rgba(49, 95, 214, 0.035), rgba(15, 143, 181, 0.025)),
var(--color-bar);
}
:root[data-theme="light"] .repo-tabbar {
border-bottom-color: #929da8;
background: #cbd2d9;
box-shadow: inset 0 -1px 0 #aeb7c0;
}
:root[data-theme="light"] .repo-tab-wrap,
:root[data-theme="light"] .repo-tab-add {
border-color: #aeb8c2;
background: #d3d9df;
}
:root[data-theme="light"] .repo-tab-wrap:hover,
:root[data-theme="light"] .repo-tab.management:hover:not(:disabled) {
background: #c8d0d8;
}
:root[data-theme="light"] .repo-tab-wrap.active,
:root[data-theme="light"] .repo-tab.management.active {
background: #e3e7eb;
box-shadow:
inset 0 -3px 0 var(--color-primary),
inset 1px 0 0 #9faab5,
inset -1px 0 0 #9faab5;
}
:root[data-theme="light"] .repo-toolbar {
border-top-color: #aeb7c0;
border-bottom-color: #929da8;
background: #d5dbe1;
box-shadow: 0 2px 0 #b9c1c9;
}
:root[data-theme="light"] .repo-action-group {
border-color: #98a4af;
background: #e0e5e9;
box-shadow: 0 1px 2px rgba(29, 39, 52, 0.1);
}
:root[data-theme="light"] .repo-action-group > .repo-action,
:root[data-theme="light"] .repo-action-group > .repo-history-wrap > .repo-action {
border-right-color: #aeb8c2;
}
:root[data-theme="light"] .workspace {
box-shadow: inset 0 1px 0 #aab4be;
}
:root[data-theme="light"] .repo-management,
:root[data-theme="light"] .main-panel {
background: var(--color-surface);
}
:root[data-theme="light"] .repo-section {
background: #dbe0e5;
}
:root[data-theme="light"] .repo-section > header,
:root[data-theme="light"] .repo-summary,
:root[data-theme="light"] .lane-header,
:root[data-theme="light"] .stash-toolbar,
:root[data-theme="light"] .dialog-footer,
:root[data-theme="light"] .cred-header {
background: #d2d8de;
}
:root[data-theme="light"] .repo-empty,
:root[data-theme="light"] .graph-list,
:root[data-theme="light"] .commit-body,
:root[data-theme="light"] .commit-files,
:root[data-theme="light"] .commit-file-button,
:root[data-theme="light"] .commit-ref-detail-item,
:root[data-theme="light"] .cred-card,
:root[data-theme="light"] .cred-body {
background: #e0e4e8;
}
:root[data-theme="light"] .graph-gutter {
background: #d2d8de;
}
:root[data-theme="light"] .graph-row:hover .commit-body {
background: #d3dae1;
}
:root[data-theme="light"] .branch-filter-dialog,
:root[data-theme="light"] .status-panel-overlay-card {
background: #e2e6ea;
}
:root[data-theme="light"] .cred-input input,
:root[data-theme="light"] .cred-expiry input[type="date"] {
background: var(--app-input-bg);
}
/* Shared dark-mode accent language in the muted light theme. */
:root[data-theme="light"] {
--color-primary: #25a7c7;
--color-primary-dark: #188ca9;
--color-accent: #2eb5d1;
--color-ink: #222328;
--color-ink-muted: #3f4852;
--color-ink-faint: #66707a;
--color-ink-dim: #515b65;
--color-ink-quiet: #5c6670;
--color-bar-text: #222328;
--color-bar-muted: #59636d;
}
:root[data-theme="light"] .btn-primary {
border-color: #2eb5d1;
color: #f0f1f2;
background: #126f84;
box-shadow: none;
}
:root[data-theme="light"] .btn-primary:hover:not(:disabled) {
border-color: #55c5dc;
color: #ffffff;
background: #147c94;
}
:root[data-theme="light"] .btn-secondary,
:root[data-theme="light"] .dialog-icon-button {
border-color: #909ca8;
color: #2f3943;
background: #d2d8de;
}
:root[data-theme="light"] .btn-secondary:hover:not(:disabled),
:root[data-theme="light"] .dialog-icon-button:hover:not(:disabled) {
border-color: #778591;
color: #222328;
background: #c3cbd3;
}
:root[data-theme="light"] .repo-action-group {
border-color: #909ca8;
background: #d2d8de;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.32);
}
:root[data-theme="light"] .repo-action {
color: #35404a;
}
:root[data-theme="light"] .repo-action-group > .repo-action,
:root[data-theme="light"] .repo-action-group > .repo-history-wrap > .repo-action {
border-right-color: #aab4be;
}
:root[data-theme="light"] .repo-action:hover:not(:disabled),
:root[data-theme="light"] .repo-action.active {
color: #222328;
background: #c3cbd3;
}
:root[data-theme="light"] .repo-action.sync-primary,
:root[data-theme="light"] .repo-action.sync-primary svg {
color: #2eb5d1;
}
/* Repository tabs stay light while sharing the cyan dark-theme accent. */
:root[data-theme="light"] .repo-tabbar {
border-bottom-color: #929da8;
background: #cbd2d9;
box-shadow: inset 0 -1px 0 #aeb7c0;
}
:root[data-theme="light"] .repo-tabs-scroll {
border-left-color: #aeb8c2;
}
:root[data-theme="light"] .repo-tab-wrap,
:root[data-theme="light"] .repo-tab.management,
:root[data-theme="light"] .repo-tab-add {
border-color: #aeb8c2;
color: #3f4852;
background: #d3d9df;
}
:root[data-theme="light"] .repo-tab-wrap:hover,
:root[data-theme="light"] .repo-tab.management:hover:not(:disabled),
:root[data-theme="light"] .repo-tab-add:hover:not(:disabled) {
color: #222328;
background: #c5ced6;
}
:root[data-theme="light"] .repo-tab-wrap.active,
:root[data-theme="light"] .repo-tab.management.active {
color: #222328;
background: #e3e7eb;
box-shadow:
inset 0 -3px 0 var(--color-accent),
inset 1px 0 0 #9faab5,
inset -1px 0 0 #9faab5;
}
:root[data-theme="light"] .repo-tab > svg,
:root[data-theme="light"] .repo-tab-close,
:root[data-theme="light"] .repo-tab-add {
color: #66707a;
}
:root[data-theme="light"] .repo-tab-wrap.active .repo-tab,
:root[data-theme="light"] .repo-tab-wrap.active .repo-tab > svg,
:root[data-theme="light"] .repo-tab.management.active > svg,
:root[data-theme="light"] .repo-tab-add:hover:not(:disabled) {
color: #2eb5d1;
}
:root[data-theme="light"] .repo-tab-wrap.active .repo-tab span,
:root[data-theme="light"] .repo-tab.management.active span {
color: #222328;
}
:root[data-theme="light"] .repo-tab-close:hover:not(:disabled),
:root[data-theme="light"] .repo-tab-close:focus-visible:not(:disabled) {
color: #222328;
background: #c3cbd3;
}
/* Appearance presets --------------------------------------------------- */
:root[data-theme="light"][data-appearance="classic"] {
--ui-shadow: 0 10px 28px rgba(23, 40, 72, 0.09);
--app-bg: #f4f6f9;
--app-button-bg: #ffffff;
--app-input-bg: #ffffff;
--app-dialog-bg: #ffffff;
--app-dialog-chrome: #f4f7fc;
--app-settings-row-bg: #f8fafd;
--color-ink: #172033;
--color-ink-muted: #475569;
--color-ink-faint: #728098;
--color-ink-dim: #5f6f89;
--color-surface: #ffffff;
--color-surface-alt: #f7f8fa;
--color-surface-dim: #f8f9fb;
--color-surface-hover: #f0f4fa;
--color-surface-raised: #ffffff;
--color-surface-solid: #ffffff;
--color-border: #cfd6e1;
--color-border-subtle: #e3e7ed;
--color-border-input: #c9d1dd;
--color-primary: #0b63e6;
--color-primary-dark: #0755c8;
--color-accent: #0b63e6;
}
:root[data-theme="light"][data-appearance="classic"] .titlebar {
background:
linear-gradient(90deg, rgba(49, 95, 214, 0.08), rgba(15, 143, 181, 0.05), rgba(214, 156, 49, 0.04)),
var(--color-bar);
}
:root[data-theme="light"][data-appearance="classic"] .repo-tabbar,
:root[data-theme="light"][data-appearance="classic"] .repo-management-tools {
border-color: var(--color-border);
background: rgba(247, 249, 252, 0.96);
box-shadow: none;
}
:root[data-theme="light"][data-appearance="classic"] .repo-tab-wrap,
:root[data-theme="light"][data-appearance="classic"] .repo-tab.management,
:root[data-theme="light"][data-appearance="classic"] .repo-tab-add {
border-color: var(--color-border-subtle);
color: var(--color-ink-muted);
background: rgba(255, 255, 255, 0.5);
}
:root[data-theme="light"][data-appearance="classic"] .repo-tab-wrap:hover,
:root[data-theme="light"][data-appearance="classic"] .repo-tab.management:hover:not(:disabled),
:root[data-theme="light"][data-appearance="classic"] .repo-tab-add:hover:not(:disabled) {
color: var(--color-ink);
background: rgba(255, 255, 255, 0.9);
}
:root[data-theme="light"][data-appearance="classic"] .repo-tab-wrap.active,
:root[data-theme="light"][data-appearance="classic"] .repo-tab.management.active {
color: var(--color-ink);
background: #ffffff;
box-shadow: inset 0 -3px 0 var(--color-primary);
}
:root[data-theme="light"][data-appearance="classic"] .repo-tab-wrap.active .repo-tab span,
:root[data-theme="light"][data-appearance="classic"] .repo-tab.management.active span {
color: var(--color-ink);
}
:root[data-theme="light"][data-appearance="classic"] .repo-toolbar {
border-color: var(--color-border);
background: rgba(255, 255, 255, 0.78);
box-shadow: none;
}
:root[data-theme="light"][data-appearance="classic"] .repo-action-group {
border-color: var(--color-border);
background: var(--color-surface-raised);
box-shadow: none;
}
:root[data-theme="light"][data-appearance="classic"] .repo-action {
color: var(--color-ink-muted);
}
:root[data-theme="light"][data-appearance="classic"] .repo-action:hover:not(:disabled),
:root[data-theme="light"][data-appearance="classic"] .repo-action.active {
color: var(--color-ink);
background: var(--color-surface-hover);
}
:root[data-theme="light"][data-appearance="classic"] .btn-primary {
border-color: rgba(49, 95, 214, 0.72);
color: #ffffff;
background: linear-gradient(135deg, #315fd6 0%, #0f8fb5 100%);
box-shadow: 0 10px 24px rgba(49, 95, 214, 0.18);
}
:root[data-theme="light"][data-appearance="classic"] .btn-secondary,
:root[data-theme="light"][data-appearance="classic"] .dialog-icon-button {
border-color: rgba(15, 143, 181, 0.28);
color: #0c6683;
background: linear-gradient(180deg, rgba(15, 143, 181, 0.08), rgba(49, 95, 214, 0.06));
}
:root[data-theme="light"][data-appearance="classic"] .repo-management,
:root[data-theme="light"][data-appearance="classic"] .main-panel,
:root[data-theme="light"][data-appearance="classic"] .cred-card,
:root[data-theme="light"][data-appearance="classic"] .cred-body {
background: var(--color-surface);
}
:root[data-theme="light"][data-appearance="classic"] .repo-section {
background: rgba(255, 255, 255, 0.62);
}
:root[data-theme="light"][data-appearance="classic"] .repo-section > header,
:root[data-theme="light"][data-appearance="classic"] .repo-summary,
:root[data-theme="light"][data-appearance="classic"] .lane-header,
:root[data-theme="light"][data-appearance="classic"] .stash-toolbar,
:root[data-theme="light"][data-appearance="classic"] .dialog-footer,
:root[data-theme="light"][data-appearance="classic"] .cred-header {
background: var(--color-surface-dim);
}
:root[data-theme="light"][data-appearance="classic"] .repo-empty {
background: rgba(255, 255, 255, 0.48);
}
:root[data-theme="light"][data-appearance="classic"] .graph-list {
background: rgba(248, 250, 253, 0.9);
}
:root[data-theme="light"][data-appearance="classic"] .commit-body,
:root[data-theme="light"][data-appearance="classic"] .commit-files,
:root[data-theme="light"][data-appearance="classic"] .commit-file-button {
background: rgba(255, 255, 255, 0.72);
}
:root[data-appearance="custom"] .titlebar,
:root[data-appearance="custom"] .repo-tabbar,
:root[data-appearance="custom"] .repo-toolbar {
border-color: var(--color-border);
background: var(--color-surface-alt);
box-shadow: none;
}
:root[data-appearance="custom"] .repo-tab-wrap,
:root[data-appearance="custom"] .repo-tab.management,
:root[data-appearance="custom"] .repo-tab-add,
:root[data-appearance="custom"] .repo-action-group,
:root[data-appearance="custom"] .btn-secondary,
:root[data-appearance="custom"] .dialog-icon-button {
border-color: var(--color-border);
color: var(--color-ink-muted);
background: var(--color-surface-raised);
}
:root[data-appearance="custom"] .repo-tab-wrap.active,
:root[data-appearance="custom"] .repo-tab.management.active {
color: var(--color-ink);
background: var(--color-surface-raised);
box-shadow: inset 0 -3px 0 var(--color-accent);
}
:root[data-appearance="custom"] .repo-tab-wrap.active .repo-tab span,
:root[data-appearance="custom"] .repo-tab.management.active span {
color: var(--color-ink);
}
:root[data-appearance="custom"] .btn-primary {
border-color: var(--color-accent);
color: var(--color-surface-raised);
background: var(--color-primary-dark);
box-shadow: none;
}
:root[data-appearance="custom"] .repo-management,
:root[data-appearance="custom"] .main-panel,
:root[data-appearance="custom"] .repo-section,
:root[data-appearance="custom"] .repo-empty,
:root[data-appearance="custom"] .graph-list,
:root[data-appearance="custom"] .commit-body,
:root[data-appearance="custom"] .commit-files,
:root[data-appearance="custom"] .commit-file-button,
:root[data-appearance="custom"] .cred-card,
:root[data-appearance="custom"] .cred-body,
:root[data-appearance="custom"] .branch-filter-dialog,
:root[data-appearance="custom"] .status-panel-overlay-card {
background: var(--color-surface);
}
:root[data-appearance="custom"] .repo-section > header,
:root[data-appearance="custom"] .repo-summary,
:root[data-appearance="custom"] .lane-header,
:root[data-appearance="custom"] .stash-toolbar,
:root[data-appearance="custom"] .dialog-footer,
:root[data-appearance="custom"] .cred-header,
:root[data-appearance="custom"] .graph-gutter {
background: var(--color-surface-dim);
}
+102 -2
View File
@@ -31,8 +31,10 @@
} from "../externalTools";
import type {
AnalyticsSettings,
AppAppearance,
AppLanguage,
AppTheme,
CustomThemeColors,
DetectedExternalTool,
ExternalToolsSettings,
ToolOpenMode,
@@ -44,6 +46,8 @@
interface Props {
analytics: AnalyticsSettings;
theme: AppTheme;
appearance: AppAppearance;
customTheme: CustomThemeColors;
language: AppLanguage;
autoRefresh: boolean;
externalTools: ExternalToolsSettings;
@@ -51,13 +55,15 @@
detectionPending: boolean;
detectionUnavailable: boolean;
onRefreshDetectedTools: () => void | Promise<void>;
onSave: (settings: AnalyticsSettings, theme: AppTheme, language: AppLanguage, autoRefresh: boolean, externalTools: ExternalToolsSettings) => void;
onSave: (settings: AnalyticsSettings, theme: AppTheme, appearance: AppAppearance, customTheme: CustomThemeColors, language: AppLanguage, autoRefresh: boolean, externalTools: ExternalToolsSettings) => void;
onClose: () => void;
}
let {
analytics,
theme = "system",
appearance = "modern",
customTheme = { background: "#cfd5dc", surface: "#e2e6ea", accent: "#2eb5d1", text: "#222328" },
language = "en",
autoRefresh = true,
externalTools,
@@ -76,6 +82,8 @@
let advancedOpen = $state(false);
let analyticsEnabled = $state(true);
let selectedTheme = $state<AppTheme>("system");
let selectedAppearance = $state<AppAppearance>("modern");
let customColors = $state<CustomThemeColors>({ background: "#cfd5dc", surface: "#e2e6ea", accent: "#2eb5d1", text: "#222328" });
let selectedLanguage = $state<AppLanguage>("en");
let autoRefreshEnabled = $state(true);
let tools = $state<ExternalToolsSettings>(defaultExternalToolsSettings());
@@ -84,6 +92,8 @@
$effect(() => {
analyticsEnabled = analytics.enabled;
selectedTheme = theme;
selectedAppearance = appearance;
customColors = structuredClone(customTheme);
selectedLanguage = language;
autoRefreshEnabled = autoRefresh;
tools = structuredClone(externalTools);
@@ -94,7 +104,46 @@
...analytics,
enabled: analyticsEnabled,
noticeSeen: true,
}, selectedTheme, selectedLanguage, autoRefreshEnabled, $state.snapshot(tools));
}, selectedTheme, selectedAppearance, $state.snapshot(customColors), selectedLanguage, autoRefreshEnabled, $state.snapshot(tools));
}
function resetCustomColors() {
customColors = selectedTheme === "dark"
? { background: "#222328", surface: "#2b2e34", accent: "#2eb5d1", text: "#f0f1f2" }
: { background: "#cfd5dc", surface: "#e2e6ea", accent: "#2eb5d1", text: "#222328" };
}
function cssColorToHex(value: string, fallback: string): string {
const color = value.trim();
if (/^#[0-9a-f]{6}$/i.test(color)) return color.toLowerCase();
if (!color || typeof document === "undefined") return fallback;
const probe = document.createElement("span");
probe.style.color = color;
if (!probe.style.color) return fallback;
probe.style.display = "none";
document.body.appendChild(probe);
const match = getComputedStyle(probe).color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)/i);
probe.remove();
if (!match) return fallback;
return `#${match.slice(1, 4).map((part) => Number(part).toString(16).padStart(2, "0")).join("")}`;
}
function currentThemeColors(): CustomThemeColors {
const styles = getComputedStyle(document.documentElement);
const fallback = selectedTheme === "dark"
? { background: "#222328", surface: "#2b2e34", accent: "#2eb5d1", text: "#f0f1f2" }
: { background: "#cfd5dc", surface: "#e2e6ea", accent: "#2eb5d1", text: "#222328" };
return {
background: cssColorToHex(styles.getPropertyValue("--app-bg"), fallback.background),
surface: cssColorToHex(styles.getPropertyValue("--color-surface"), fallback.surface),
accent: cssColorToHex(styles.getPropertyValue("--color-accent"), fallback.accent),
text: cssColorToHex(styles.getPropertyValue("--color-ink"), fallback.text),
};
}
function selectAppearance(next: AppAppearance) {
if (next === "custom" && selectedAppearance !== "custom") customColors = currentThemeColors();
selectedAppearance = next;
}
function toolLabel(kind: ExternalToolKind): string {
@@ -292,6 +341,40 @@
</div>
</section>
<section class="general-setting-panel">
<header><SlidersHorizontal size={16} /><div><h4>{isGerman ? "Darstellungsstil" : "Design style"}</h4><p>{isGerman ? "Aktuell, klassisch oder selbst gestaltet." : "Current, classic, or designed by you."}</p></div></header>
<div class="settings-segmented" role="radiogroup" aria-label={isGerman ? "Darstellungsstil" : "Design style"}>
<label class:active={selectedAppearance === "modern"}><input type="radio" name="appearance" value="modern" checked={selectedAppearance === "modern"} onchange={() => selectAppearance("modern")} /><span>{isGerman ? "Aktuell" : "Modern"}</span></label>
<label class:active={selectedAppearance === "classic"}><input type="radio" name="appearance" value="classic" checked={selectedAppearance === "classic"} onchange={() => selectAppearance("classic")} /><span>{isGerman ? "Klassisch" : "Classic"}</span></label>
<label class:active={selectedAppearance === "custom"}><input type="radio" name="appearance" value="custom" checked={selectedAppearance === "custom"} onchange={() => selectAppearance("custom")} /><span>{isGerman ? "Eigene" : "Custom"}</span></label>
</div>
</section>
{#if selectedAppearance === "custom"}
<section class="general-setting-panel general-setting-wide custom-theme-panel">
<header>
<Palette size={16} />
<div><h4>{isGerman ? "Theme-Generator" : "Theme generator"}</h4><p>{isGerman ? "Erstelle dein eigenes Farbprofil." : "Create your own color profile."}</p></div>
<button class="theme-reset-button" type="button" onclick={resetCustomColors}><RotateCw size={13} />{isGerman ? "Zurücksetzen" : "Reset"}</button>
</header>
<div
class="theme-preview"
style={`--preview-bg:${customColors.background};--preview-surface:${customColors.surface};--preview-accent:${customColors.accent};--preview-text:${customColors.text};`}
aria-label={isGerman ? "Vorschau des eigenen Themes" : "Custom theme preview"}
>
<span class="theme-preview-sidebar"></span>
<span class="theme-preview-content"><i></i><b></b><em></em></span>
</div>
<div class="theme-color-grid">
<label><span>{isGerman ? "Hintergrund" : "Background"}</span><input type="color" bind:value={customColors.background} aria-label={isGerman ? "Hintergrundfarbe" : "Background color"} /><code>{customColors.background}</code></label>
<label><span>{isGerman ? "Fläche" : "Surface"}</span><input type="color" bind:value={customColors.surface} aria-label={isGerman ? "Flächenfarbe" : "Surface color"} /><code>{customColors.surface}</code></label>
<label><span>{isGerman ? "Akzent" : "Accent"}</span><input type="color" bind:value={customColors.accent} aria-label={isGerman ? "Akzentfarbe" : "Accent color"} /><code>{customColors.accent}</code></label>
<label><span>{isGerman ? "Schrift" : "Text"}</span><input type="color" bind:value={customColors.text} aria-label={isGerman ? "Schriftfarbe" : "Text color"} /><code>{customColors.text}</code></label>
</div>
<p class="theme-generator-note">{isGerman ? "Die Farben werden beim Speichern auf die gesamte Oberfläche angewendet." : "The colors are applied across the interface when you save."}</p>
</section>
{/if}
<section class="general-setting-panel">
<header><Languages size={16} /><div><h4>{isGerman ? "Sprache" : "Language"}</h4><p>{isGerman ? "Sprache der Oberfläche." : "Language used by the interface."}</p></div></header>
<div class="settings-segmented settings-language" role="radiogroup" aria-label={isGerman ? "App-Sprache" : "App language"}>
@@ -534,6 +617,22 @@
.settings-segmented label { display: flex; align-items: center; justify-content: center; min-height: 31px; border: 1px solid transparent; border-radius: 6px; color: var(--color-ink-dim); font-size: 10.5px; font-weight: 750; }
.settings-segmented label.active { border-color: var(--color-border-input); color: var(--color-ink); background: var(--color-surface-hover); }
.settings-segmented input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.custom-theme-panel > header { align-items: center; }
.custom-theme-panel > header > div { min-width: 0; }
.theme-reset-button { display: inline-flex; align-items: center; gap: 5px; min-height: 27px; margin-left: auto; padding: 0 8px; border: 1px solid var(--color-border); color: var(--color-ink-muted); background: var(--color-surface-raised); font-size: 9.5px; font-weight: 750; }
.theme-reset-button:hover:not(:disabled) { border-color: var(--color-border-input); color: var(--color-ink); background: var(--color-surface-hover); }
.theme-preview { display: grid; grid-template-columns: 28% 1fr; min-height: 78px; overflow: hidden; border: 1px solid color-mix(in srgb, var(--preview-text) 30%, var(--preview-surface)); background: var(--preview-bg); }
.theme-preview-sidebar { border-right: 1px solid color-mix(in srgb, var(--preview-text) 24%, var(--preview-surface)); background: color-mix(in srgb, var(--preview-surface) 86%, var(--preview-bg)); }
.theme-preview-content { display: grid; grid-template-columns: 1fr auto; align-content: start; gap: 8px; margin: 10px; padding: 10px; border: 1px solid color-mix(in srgb, var(--preview-text) 22%, var(--preview-surface)); color: var(--preview-text); background: var(--preview-surface); }
.theme-preview-content i { display: block; width: 54%; height: 7px; background: var(--preview-text); opacity: .82; }
.theme-preview-content b { display: block; width: 34px; height: 18px; grid-row: 1 / 3; grid-column: 2; background: var(--preview-accent); }
.theme-preview-content em { display: block; width: 76%; height: 5px; background: var(--preview-text); opacity: .32; }
.theme-color-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
.theme-color-grid label { display: grid; grid-template-columns: minmax(0, 1fr) 32px auto; align-items: center; gap: 8px; min-width: 0; min-height: 38px; padding: 5px 7px; border: 1px solid var(--color-border-subtle); background: var(--color-surface-raised); }
.theme-color-grid label > span { color: var(--color-ink-muted); font-size: 10px; font-weight: 750; }
.theme-color-grid input[type="color"] { width: 32px; height: 25px; padding: 2px; border: 1px solid var(--color-border-input); background: transparent; cursor: pointer; }
.theme-color-grid code { color: var(--color-ink-faint); font: 9px var(--font-mono); text-transform: uppercase; }
.theme-generator-note { margin: -5px 0 0 !important; color: var(--color-ink-faint) !important; }
.settings-switch-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 14px; }
.settings-switch-row span { display: grid; gap: 3px; }
.settings-switch-row strong { color: var(--color-ink); font-size: 11px; }
@@ -569,6 +668,7 @@
.tool-rescan-button { align-self: flex-start; }
.general-settings-grid { grid-template-columns: 1fr; }
.general-setting-panel.general-setting-wide { grid-column: auto; }
.theme-color-grid { grid-template-columns: 1fr; }
.tool-config-panel { padding: 13px; }
.tool-usage-callout { grid-template-columns: 1fr; gap: 4px; }
}
+8
View File
@@ -13,8 +13,16 @@ export type CommitAiPhase = "idle" | "loading" | "ready" | "error";
export type CommitAiProvider = "local" | "openai" | "anthropic" | "custom";
export type CommitAiLocalProfile = "fast" | "balanced" | "detailed";
export type AppTheme = "system" | "light" | "dark";
export type AppAppearance = "modern" | "classic" | "custom";
export type AppLanguage = "en" | "de";
export interface CustomThemeColors {
background: string;
surface: string;
accent: string;
text: string;
}
export interface CommitAiStatus {
phase: CommitAiPhase;
model_id: string | null;