Compare commits

..
2 Commits
Author SHA1 Message Date
Christoph Brandau de8832a919 style(ui): update global theme colors and palette
This commit implements a comprehensive visual refresh by updating the core color scheme across the application. A new, cohesive dark mode aesthetic has been applied, shifting primary accents from purple/orange tones to cooler blue/cyan gradients. This ensures better consistency and modernizes the look of various components, including buttons and loading indicators.

- Updated global CSS variables for consistent theming
- Refreshed component styles with the new color palette
- Adjusted repository loading overlay visuals
2026-07-10 13:47:50 +02:00
Christoph Brandau 25b98d7c4d feat(ui): Implement theme persistence and system preference support
Adds comprehensive theme management across the application, allowing users to save their preferred color scheme (light/dark) or automatically follow the operating system's settings. This required updating state management in App.svelte to handle theme loading and applying changes dynamically via CSS variables.

The styling layer was significantly updated with new CSS variables and rules for both dark and light modes, ensuring visual consistency across all components like dialogs, buttons, and sidebars.

- Added logic to detect system color scheme preference
- Implemented full support for persistent light/dark mode switching
- Overhauled global CSS variables for improved theme adaptability
2026-07-10 12:24:14 +02:00
7 changed files with 766 additions and 125 deletions
+47 -2
View File
@@ -98,6 +98,7 @@
import type {
AiSettings,
AppTheme,
AnalyticsSettings,
CommitAiPhase,
ConflictFile,
@@ -165,6 +166,7 @@
const REPO_STATUS_CACHE_KEY = "gitlite.repoStatusCache.v1";
const AI_SETTINGS_KEY = "gitlite.aiSettings.v1";
const ANALYTICS_SETTINGS_KEY = "gitlite.analyticsSettings.v1";
const APP_THEME_KEY = "gitlite.theme.v1";
const COMMIT_PANEL_HEIGHT_KEY = "gitlite.commitPanelHeight.v1";
const LEFT_SIDEBAR_WIDTH_KEY = "gitlite.leftSidebarWidth.v1";
const LEFT_BRANCH_PANEL_HEIGHT_KEY = "gitlite.leftBranchPanelHeight.v1";
@@ -239,6 +241,7 @@
let appSettingsOpen = false;
let analyticsNoticeOpen = false;
let analyticsSettings: AnalyticsSettings = defaultAnalyticsSettings();
let appTheme: AppTheme = loadThemePreference();
let localModelOptions: LocalModelOption[] = [];
let errorMessage = "";
let operation = "";
@@ -337,6 +340,7 @@
let fileHistoryResizeStartX = 0;
let fileHistoryResizeStartWidth = 0;
let fileHistoryCollapsed = true;
let themeMediaQuery: MediaQueryList | undefined;
// ── Derived ────────────────────────────────────────────────────────────────
@@ -389,13 +393,18 @@
$: leftSidebarRows = buildLeftSidebarRows(branchPanelCollapsed, stashPanelCollapsed, explorerPanelCollapsed);
$: allLeftPanelsCollapsed = branchPanelCollapsed && stashPanelCollapsed && explorerPanelCollapsed;
$: applyThemePreference(appTheme);
// ── Lifecycle ──────────────────────────────────────────────────────────────
onMount(() => {
themeMediaQuery = window.matchMedia("(prefers-color-scheme: light)");
themeMediaQuery.addEventListener("change", handleSystemThemeChange);
void runStartupSequence();
});
onDestroy(() => {
themeMediaQuery?.removeEventListener("change", handleSystemThemeChange);
if (autoRefreshTimer) clearInterval(autoRefreshTimer);
if (backgroundRepoStatusTimer) clearInterval(backgroundRepoStatusTimer);
if (backgroundFetchTimer) clearInterval(backgroundFetchTimer);
@@ -754,11 +763,46 @@
trackEvent("app_started", { first_run: 1 });
}
function saveAppSettings(next: AnalyticsSettings) {
function loadThemePreference(): AppTheme {
try {
const stored = localStorage.getItem(APP_THEME_KEY);
if (stored === "system" || stored === "light" || stored === "dark") return stored;
} catch {
// Local storage is optional; system theme is a sane default.
}
return "system";
}
function persistThemePreference(next: AppTheme) {
try {
localStorage.setItem(APP_THEME_KEY, next);
} catch {
// Ignore storage quota/private-mode errors.
}
}
function applyThemePreference(next: AppTheme) {
const prefersLight = themeMediaQuery?.matches ?? window.matchMedia("(prefers-color-scheme: light)").matches;
const resolved = next === "system"
? prefersLight
? "light"
: "dark"
: next;
document.documentElement.dataset.themePreference = next;
document.documentElement.dataset.theme = resolved;
}
function handleSystemThemeChange() {
if (appTheme === "system") applyThemePreference(appTheme);
}
function saveAppSettings(next: AnalyticsSettings, nextTheme: AppTheme) {
analyticsSettings = next;
appTheme = nextTheme;
persistAnalyticsSettings(next);
persistThemePreference(nextTheme);
appSettingsOpen = false;
if (next.enabled) trackEvent("settings_saved", { analytics_enabled: 1 });
if (next.enabled) trackEvent("settings_saved", { analytics_enabled: 1, theme: nextTheme });
}
function updateCommitMessage(message: string) {
@@ -3932,6 +3976,7 @@
{#if appSettingsOpen}
<AppSettingsDialog
analytics={analyticsSettings}
theme={appTheme}
onSave={saveAppSettings}
onClose={() => { appSettingsOpen = false; }}
/>
+581 -92
View File
@@ -1,54 +1,112 @@
@import "tailwindcss";
@theme {
--color-ink: #f5f7ff;
--color-ink-muted: #a8b1d8;
--color-ink-faint: #687197;
--color-ink-dim: #838cb8;
--color-ink-quiet: #949bc8;
--color-ink: #edf3ff;
--color-ink-muted: #b1bad0;
--color-ink-faint: #6f7c96;
--color-ink-dim: #8895ad;
--color-ink-quiet: #98a4bb;
--color-surface: rgba(22, 22, 36, 0.82);
--color-surface-alt: #0b0b14;
--color-surface-dim: rgba(18, 18, 30, 0.9);
--color-surface-hover: rgba(47, 48, 78, 0.76);
--color-surface-raised: rgba(28, 29, 48, 0.88);
--color-surface-solid: #1c1d30;
--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-border: rgba(100, 108, 255, 0.28);
--color-border-subtle: rgba(255, 255, 255, 0.08);
--color-border-input: rgba(65, 209, 255, 0.26);
--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-primary: #646cff;
--color-primary-dark: #535bf2;
--color-accent: #41d1ff;
--color-primary: #6f8cff;
--color-primary-dark: #5d74e8;
--color-accent: #4db6d6;
--color-bar: rgba(9, 9, 18, 0.92);
--color-bar-text: #f4f6ff;
--color-bar-muted: #7b84b2;
--color-bar: rgba(7, 10, 16, 0.94);
--color-bar-text: #f1f5ff;
--color-bar-muted: #7f8ba3;
--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-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: #070a10;
--app-dialog-bg: #101622;
--app-dialog-chrome: #141b29;
--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;
}
:root[data-theme="light"] {
--color-ink: #172033;
--color-ink-muted: #475569;
--color-ink-faint: #728098;
--color-ink-dim: #5f6f89;
--color-ink-quiet: #66758d;
--color-surface: rgba(255, 255, 255, 0.86);
--color-surface-alt: #f3f6fb;
--color-surface-dim: rgba(244, 247, 252, 0.92);
--color-surface-hover: rgba(226, 233, 245, 0.82);
--color-surface-raised: rgba(255, 255, 255, 0.94);
--color-surface-solid: #ffffff;
--color-border: rgba(61, 89, 142, 0.24);
--color-border-subtle: rgba(34, 49, 78, 0.11);
--color-border-input: rgba(46, 117, 182, 0.28);
--color-primary: #315fd6;
--color-primary-dark: #284cb4;
--color-accent: #0f8fb5;
--color-bar: rgba(248, 251, 255, 0.94);
--color-bar-text: #172033;
--color-bar-muted: #64728a;
--app-color-scheme: light;
--app-bg:
radial-gradient(circle at 12% 0%, rgba(49, 95, 214, 0.12), transparent 30%),
radial-gradient(circle at 82% 4%, rgba(15, 143, 181, 0.12), transparent 28%),
linear-gradient(135deg, #f7f9fd 0%, #eef3f9 48%, #f8fafc 100%);
--app-button-bg: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(235, 240, 249, 0.95));
--app-input-bg: rgba(255, 255, 255, 0.9);
--app-select-option-bg: #ffffff;
--app-panel-highlight: linear-gradient(180deg, rgba(255,255,255,0.72), transparent 70%);
--app-panel-shadow: 0 18px 48px rgba(28, 44, 74, 0.12), inset 0 1px 0 rgba(255,255,255,0.86);
--app-dialog-backdrop: rgba(232, 238, 248, 0.96);
--app-dialog-bg: #ffffff;
--app-dialog-chrome: #f4f7fc;
--app-dialog-shadow: 0 24px 72px rgba(28, 44, 74, 0.2), 0 2px 12px rgba(28,44,74,0.1);
--app-settings-row-bg: #f8fafd;
--app-scrollbar-thumb: #c2cada;
--app-scrollbar-thumb-hover: #aeb8cb;
}
@layer base {
*, *::before, *::after { box-sizing: border-box; }
html, body, #app { width: 100%; height: 100%; margin: 0; }
* { scrollbar-width: thin; scrollbar-color: #2a2f45 transparent; }
* { scrollbar-width: thin; scrollbar-color: var(--app-scrollbar-thumb) transparent; }
::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #2a2f45; border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: #3a3f58; }
::-webkit-scrollbar-thumb { background: var(--app-scrollbar-thumb); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--app-scrollbar-thumb-hover); }
html { color-scheme: dark; }
html { color-scheme: var(--app-color-scheme); }
body {
overflow: hidden;
color: var(--color-ink);
background:
radial-gradient(circle at 22% 8%, rgba(189, 52, 254, 0.28), transparent 34%),
radial-gradient(circle at 74% 10%, rgba(65, 209, 255, 0.22), transparent 30%),
radial-gradient(circle at 88% 78%, rgba(255, 211, 67, 0.1), transparent 26%),
linear-gradient(135deg, #090912 0%, #111122 45%, #0b0b14 100%);
background: var(--app-bg);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-synthesis: none;
text-rendering: optimizeLegibility;
@@ -68,7 +126,7 @@
border: 1px solid var(--color-border);
border-radius: 8px;
color: var(--color-ink-muted);
background: linear-gradient(180deg, rgba(42, 43, 70, 0.9), rgba(27, 28, 48, 0.92));
background: var(--app-button-bg);
cursor: pointer;
transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
font-size: 13px;
@@ -85,7 +143,7 @@
border: 1px solid var(--color-border-input);
border-radius: 8px;
color: var(--color-ink);
background: rgba(13, 14, 26, 0.78);
background: var(--app-input-bg);
outline: none;
}
input:focus, textarea:focus, select:focus {
@@ -117,7 +175,7 @@
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(90, 140, 248, 0.18);
}
select option { background: #1c2033; color: var(--color-ink); }
select option { background: var(--app-select-option-bg); color: var(--color-ink); }
}
@layer components {
@@ -126,28 +184,28 @@
.btn-sm { min-height: 26px; padding: 0 8px; font-size: 12px; }
.btn-primary {
border-color: rgba(100, 108, 255, 0.75);
border-color: rgba(111, 140, 255, 0.72);
color: #ffffff;
background: linear-gradient(135deg, #646cff 0%, #bd34fe 100%);
box-shadow: 0 0 24px rgba(100, 108, 255, 0.2);
background: linear-gradient(135deg, #5f7df2 0%, #238eb4 100%);
box-shadow: 0 10px 24px rgba(77, 182, 214, 0.16);
font-weight: 600;
}
.btn-primary:hover:not(:disabled) {
border-color: rgba(65, 209, 255, 0.82);
background: linear-gradient(135deg, #747bff 0%, #c966ff 100%);
border-color: rgba(77, 182, 214, 0.78);
background: linear-gradient(135deg, #6f8cff 0%, #2da0c7 100%);
color: #ffffff;
}
.btn-secondary {
border-color: rgba(65, 209, 255, 0.32);
color: #b9e9ff;
background: linear-gradient(180deg, rgba(65, 209, 255, 0.12), rgba(100, 108, 255, 0.1));
border-color: rgba(77, 182, 214, 0.3);
color: #b8e7f6;
background: linear-gradient(180deg, rgba(77, 182, 214, 0.1), rgba(111, 140, 255, 0.07));
font-weight: 700;
}
.btn-secondary:hover:not(:disabled) {
border-color: rgba(65, 209, 255, 0.64);
border-color: rgba(77, 182, 214, 0.58);
color: #ffffff;
background: linear-gradient(180deg, rgba(65, 209, 255, 0.18), rgba(100, 108, 255, 0.16));
background: linear-gradient(180deg, rgba(77, 182, 214, 0.16), rgba(111, 140, 255, 0.12));
}
.btn-danger {
@@ -169,9 +227,9 @@
border: 1px solid var(--color-border);
border-radius: 12px;
background:
linear-gradient(180deg, rgba(255,255,255,0.045), transparent 72%),
var(--app-panel-highlight),
var(--color-surface);
box-shadow: 0 18px 60px rgba(0,0,0,0.24), inset 0 1px 0 rgba(255,255,255,0.05);
box-shadow: var(--app-panel-shadow);
backdrop-filter: blur(16px);
}
@@ -183,7 +241,7 @@
min-height: 46px;
padding: 8px 12px;
border-bottom: 1px solid var(--color-border-subtle);
background: linear-gradient(90deg, rgba(100,108,255,0.09), rgba(65,209,255,0.025));
background: linear-gradient(90deg, rgba(111,140,255,0.07), rgba(77,182,214,0.025));
}
.section-head h2 { margin: 1px 0 0; color: var(--color-ink); font-size: 14px; line-height: 1.2; font-weight: 600; }
@@ -466,7 +524,7 @@
align-items: center;
height: var(--app-titlebar-height);
background:
linear-gradient(90deg, rgba(100,108,255,0.16), rgba(65,209,255,0.08), rgba(255,211,67,0.035)),
linear-gradient(90deg, rgba(111,140,255,0.08), rgba(77,182,214,0.045), rgba(255,255,255,0.012)),
var(--color-bar);
color: var(--color-bar-text);
user-select: none;
@@ -518,9 +576,9 @@
height: 100%;
overflow: hidden;
}
.titlebar-info svg { color: #41d1ff; flex-shrink: 0; }
.titlebar-info svg { color: var(--color-accent); flex-shrink: 0; }
.tb-repo { color: #8e95c9; font-size: 12px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; }
.tb-repo { color: var(--color-bar-muted); font-size: 12px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; }
.tb-sep { color: rgba(255,255,255,0.22); font-size: 13px; }
.tb-branch { color: #f5f7ff; font-size: 12px; font-weight: 700; font-family: var(--font-mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
@@ -528,7 +586,7 @@
.tb-sync.ahead { color: #e0a040; background: rgba(224,160,64,0.13); }
.tb-sync.behind { color: #7aacff; background: rgba(122,172,255,0.13); }
.tb-no-repo { color: #7b84b2; font-size: 12px; font-style: italic; }
.tb-no-repo { color: var(--color-bar-muted); font-size: 12px; font-style: italic; }
.titlebar-right { display: flex; align-items: stretch; height: 100%; border-left: 1px solid rgba(255,255,255,0.06); }
.titlebar-actions { display: flex; align-items: stretch; }
@@ -549,7 +607,7 @@
transition: background 120ms ease, color 120ms ease;
-webkit-app-region: no-drag;
}
.tb-action:hover:not(:disabled) { background: rgba(255,255,255,0.07); border-color: transparent; color: #c0cce0; }
.tb-action:hover:not(:disabled) { background: rgba(255,255,255,0.06); border-color: transparent; color: #d6def0; }
.tb-action:disabled { opacity: 0.3; cursor: not-allowed; }
.tb-action.auto-toggle.active { color: #4eca76; }
.tb-action.auto-toggle.active:hover:not(:disabled) { color: #6ee090; background: rgba(78,202,118,0.1); }
@@ -570,22 +628,22 @@
border: none;
border-radius: 0;
background: transparent;
color: #3a4a5c;
color: #536078;
cursor: pointer;
transition: background 120ms ease, color 120ms ease;
-webkit-app-region: no-drag;
}
.tb-btn:hover:not(:disabled) { background: rgba(255,255,255,0.09); border-color: transparent; color: #c0cce0; }
.tb-btn:hover:not(:disabled) { background: rgba(255,255,255,0.08); border-color: transparent; color: #d6def0; }
.tb-btn.close:hover:not(:disabled) { background: #c0392b; color: #ffffff; }
/* --- Top bar (repo form) --- */
.topbar {
padding: 9px 10px;
border: 1px solid rgba(100,108,255,0.28);
border: 1px solid var(--color-border);
border-radius: 12px;
background:
linear-gradient(90deg, rgba(189,52,254,0.1), rgba(65,209,255,0.075), rgba(255,211,67,0.035)),
linear-gradient(90deg, rgba(111,140,255,0.055), rgba(77,182,214,0.045), rgba(255,255,255,0.012)),
var(--color-surface);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
backdrop-filter: blur(16px);
@@ -1049,7 +1107,7 @@
inset: 0 auto 0 0;
min-width: 0;
border-radius: inherit;
background: linear-gradient(90deg, #41d1ff, #646cff, #bd34fe);
background: linear-gradient(90deg, #4db6d6, #6f8cff, #238eb4);
transition: width 160ms ease;
}
.update-progress.indeterminate span {
@@ -1077,14 +1135,14 @@
font-weight: 800;
}
.update-toast-primary {
border-color: rgba(100,108,255,0.72);
border-color: rgba(111,140,255,0.72);
color: #ffffff;
background: linear-gradient(135deg, #646cff, #bd34fe);
background: linear-gradient(135deg, #5f7df2, #238eb4);
}
.update-toast-primary:hover:not(:disabled) {
border-color: rgba(65,209,255,0.74);
border-color: rgba(77,182,214,0.74);
color: #ffffff;
background: linear-gradient(135deg, #747bff, #c966ff);
background: linear-gradient(135deg, #6f8cff, #2da0c7);
}
.update-toast-secondary {
border-color: rgba(255,255,255,0.1);
@@ -2308,7 +2366,7 @@
padding: 22px;
overflow: hidden;
background:
radial-gradient(circle at center 42%, rgba(151, 118, 255, 0.12), transparent 52%),
radial-gradient(circle at center 42%, rgba(111, 140, 255, 0.1), transparent 52%),
linear-gradient(180deg, rgba(15, 18, 31, 0.55), transparent);
}
@@ -2324,7 +2382,7 @@
.file-history-loading-halo {
position: absolute;
inset: 10px;
border: 1px solid rgba(151, 118, 255, 0.24);
border: 1px solid rgba(111, 140, 255, 0.22);
border-radius: 18px;
transform: rotate(45deg);
animation: fhl-halo-breathe 2.4s ease-in-out infinite;
@@ -2344,14 +2402,14 @@
stroke-linecap: round;
stroke-dasharray: 92;
stroke-dashoffset: 92;
filter: drop-shadow(0 0 6px rgba(151, 118, 255, 0.5));
filter: drop-shadow(0 0 6px rgba(77, 182, 214, 0.3));
animation: fhl-trace-draw 2.4s ease-in-out infinite;
}
.file-history-loading-traces .fhl-trace-main {
stroke: #9b70ff;
stroke: #6f8cff;
}
.file-history-loading-traces .fhl-trace-branch {
stroke: #ff6d26;
stroke: #4db6d6;
animation-delay: 0.28s;
}
@@ -2363,7 +2421,7 @@
object-fit: contain;
filter:
drop-shadow(0 10px 14px rgba(0, 0, 0, 0.45))
drop-shadow(0 0 12px rgba(151, 118, 255, 0.28));
drop-shadow(0 0 12px rgba(77, 182, 214, 0.2));
animation: fhl-icon-float 2.4s ease-in-out infinite;
}
@@ -2379,15 +2437,15 @@
height: 3px;
overflow: hidden;
border-radius: 999px;
background: rgba(151, 118, 255, 0.14);
background: rgba(111, 140, 255, 0.14);
}
.file-history-loading-bar span {
position: absolute;
inset: 0;
width: 46%;
border-radius: inherit;
background: linear-gradient(90deg, transparent, #9b70ff 42%, #ff6d26 74%, transparent);
box-shadow: 0 0 12px rgba(255, 109, 38, 0.26);
background: linear-gradient(90deg, transparent, #6f8cff 42%, #4db6d6 74%, transparent);
box-shadow: 0 0 12px rgba(77, 182, 214, 0.24);
animation: fhl-bar-slide 1.35s ease-in-out infinite;
}
@@ -2441,8 +2499,10 @@
position: relative;
align-self: stretch;
min-width: 42px;
border-right: 1px solid rgba(94,110,156,0.12);
background: rgba(7,8,16,0.2);
border-right: 1px solid rgba(226,232,240,0.08);
background:
linear-gradient(90deg, rgba(111,140,255,0.025), transparent),
rgba(7,10,16,0.24);
}
.graph-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.graph-svg path {
@@ -2472,8 +2532,8 @@
height: 12px;
border-radius: 999px;
background: var(--dot-color, #5a8cf8);
border: 2px solid #111321;
box-shadow: 0 0 0 1px rgba(255,255,255,0.07);
border: 2px solid var(--app-dialog-bg);
box-shadow: 0 0 0 1px rgba(255,255,255,0.08), 0 2px 8px rgba(0,0,0,0.22);
transform: translate(-50%, -50%);
transition: transform 120ms ease, box-shadow 120ms ease;
}
@@ -2495,7 +2555,7 @@
height: 15px;
background: var(--color-surface-alt);
border-color: var(--dot-color, #5a8cf8);
box-shadow: 0 0 0 1px rgba(255,255,255,0.08);
box-shadow: 0 0 0 1px rgba(255,255,255,0.1);
}
.graph-hover-branches {
position: absolute;
@@ -2525,8 +2585,8 @@
border: 1px solid rgba(91,209,138,0.28);
border-radius: 999px;
color: #b2f0c2;
background: rgba(20,35,29,0.94);
box-shadow: 0 8px 22px rgba(0,0,0,0.3);
background: rgba(14,36,27,0.94);
box-shadow: 0 8px 22px rgba(0,0,0,0.24);
font-family: var(--font-mono);
font-size: 9.5px;
font-weight: 750;
@@ -2559,28 +2619,28 @@
gap: 5px;
min-width: 0;
padding: 8px 10px;
background: rgba(28,29,48,0.34);
background: rgba(18,24,36,0.5);
transition: background 120ms ease;
}
.graph-row + .graph-row .commit-body { border-top: 1px solid rgba(94,110,156,0.1); }
.graph-row + .graph-row .commit-body { border-top: 1px solid rgba(226,232,240,0.075); }
.graph-row.graph-ahead-row .commit-body {
box-shadow: inset 3px 0 0 rgba(224,160,64,0.72);
}
.graph-row.graph-behind-row .commit-body {
box-shadow: inset 3px 0 0 rgba(122,172,255,0.72);
}
.graph-row:hover .commit-body { background: rgba(37,40,62,0.54); }
.graph-row:hover .commit-body { background: rgba(30,39,57,0.72); }
.graph-row:hover .graph-svg path { opacity: 1; stroke-width: 2.65; }
.graph-row:hover .graph-svg path.hidden-branch { opacity: 0.12; stroke-width: 2.2; }
.graph-row:hover .graph-dot { transform: translate(-50%, -50%) scale(1.12); }
.graph-row:hover .graph-dot.hidden-branch { transform: translate(-50%, -50%) scale(1); }
.graph-row.merge-row .commit-body {
background: rgba(36,31,54,0.46);
background: rgba(26,27,43,0.56);
}
.graph-row.tip-row .commit-body {
background:
linear-gradient(90deg, rgba(105,167,255,0.055), transparent 32%),
rgba(28,29,48,0.38);
linear-gradient(90deg, rgba(111,140,255,0.065), transparent 34%),
rgba(20,27,40,0.62);
}
/* --- Compare panel --- */
@@ -2630,7 +2690,7 @@
display: grid;
place-items: center;
padding: 24px;
background-color: #050712;
background-color: var(--app-dialog-backdrop);
background-image: none;
}
@@ -2645,9 +2705,9 @@
height: min(760px, 100%);
border: 1px solid var(--color-border);
border-radius: 12px;
background-color: #111321;
background-color: var(--app-dialog-bg);
background-image: none;
box-shadow: 0 24px 72px rgba(0, 0, 0, 0.6), 0 2px 12px rgba(0,0,0,0.4);
box-shadow: var(--app-dialog-shadow);
overflow: hidden;
}
.compare-dialog {
@@ -2795,6 +2855,56 @@
font-size: 15px;
font-weight: 750;
}
.settings-segmented {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 6px;
min-width: 0;
padding: 4px;
border: 1px solid var(--color-border-subtle);
border-radius: 8px;
background: var(--app-settings-row-bg);
}
.settings-segmented label {
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
min-height: 32px;
padding: 0 10px;
border: 1px solid transparent;
border-radius: 6px;
color: var(--color-ink-dim);
cursor: pointer;
font-size: 12px;
font-weight: 800;
transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.settings-segmented label:hover {
border-color: var(--color-border-subtle);
color: var(--color-ink);
background: var(--color-surface-hover);
}
.settings-segmented label.active {
border-color: var(--color-border-input);
color: var(--color-ink);
background: var(--color-surface-raised);
box-shadow: 0 1px 4px rgba(28,44,74,0.08);
}
.settings-segmented input {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
opacity: 0;
pointer-events: none;
}
.settings-segmented span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.settings-toggle-row {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
@@ -2804,7 +2914,7 @@
padding: 12px;
border: 1px solid var(--color-border-subtle);
border-radius: 8px;
background: #151827;
background: var(--app-settings-row-bg);
color: var(--color-ink-muted);
cursor: pointer;
}
@@ -2970,7 +3080,7 @@
gap: 8px;
}
.dialog-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--color-border-subtle); background: #171a2b; }
.dialog-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--color-border-subtle); background: var(--app-dialog-chrome); }
.dialog-header > div:first-child { min-width: 0; }
.dialog-header-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex: 0 0 auto; min-width: 0; }
.compare-restore { max-width: 170px; min-width: 0; }
@@ -2984,7 +3094,7 @@
.dialog-body { display: grid; grid-template-columns: 280px minmax(0, 1fr); min-height: 0; }
.compare-dialog .dialog-body { grid-template-columns: minmax(260px, 320px) minmax(0, 1fr); }
.dialog-files { display: grid; align-content: start; gap: 4px; padding: 8px; overflow: auto; border-right: 1px solid var(--color-border-subtle); background: #171a2b; }
.dialog-files { display: grid; align-content: start; gap: 4px; padding: 8px; overflow: auto; border-right: 1px solid var(--color-border-subtle); background: var(--app-dialog-chrome); }
.dialog-file-row {
display: grid;
@@ -3132,7 +3242,7 @@
letter-spacing: 0;
}
.dialog-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 16px; border-top: 1px solid var(--color-border-subtle); background: #171a2b; }
.dialog-footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 16px; border-top: 1px solid var(--color-border-subtle); background: var(--app-dialog-chrome); }
.dialog-footer-info { color: var(--color-ink-dim); font-size: 13px; font-weight: 700; }
.prepared-tag { display: inline-flex; align-items: center; gap: 4px; margin-right: auto; color: #4eca76; font-size: 12px; font-weight: 700; }
@@ -4178,9 +4288,9 @@
gap: 6px;
min-height: 36px;
padding: 0 16px;
border: 1px solid rgba(100,108,255,0.78);
border: 1px solid rgba(111,140,255,0.72);
border-radius: 7px;
background: linear-gradient(135deg, #646cff, #bd34fe);
background: linear-gradient(135deg, #5f7df2, #238eb4);
color: #ffffff;
font-size: 13px;
font-weight: 700;
@@ -4188,8 +4298,8 @@
transition: background 0.12s, border-color 0.12s;
}
.cred-submit:hover:not(:disabled) {
background: linear-gradient(135deg, #747bff, #c966ff);
border-color: rgba(65,209,255,0.7);
background: linear-gradient(135deg, #6f8cff, #2da0c7);
border-color: rgba(77,182,214,0.7);
}
.cred-submit:disabled { opacity: 0.45; cursor: not-allowed; }
@@ -4388,6 +4498,381 @@
.resolve-path { overflow: hidden; color: var(--color-ink-faint); font-family: var(--font-mono); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
}
:root[data-theme="light"] button:hover:not(:disabled) {
background: var(--color-surface-hover);
}
:root[data-theme="light"] input:focus,
:root[data-theme="light"] textarea:focus,
:root[data-theme="light"] select:focus {
box-shadow: 0 0 0 3px rgba(49, 95, 214, 0.14), 0 10px 24px rgba(28, 44, 74, 0.06);
}
:root[data-theme="light"] .btn-primary {
border-color: rgba(49, 95, 214, 0.72);
background: linear-gradient(135deg, #315fd6 0%, #0f8fb5 100%);
box-shadow: 0 10px 24px rgba(49, 95, 214, 0.18);
}
:root[data-theme="light"] .btn-primary:hover:not(:disabled) {
border-color: rgba(15, 143, 181, 0.72);
background: linear-gradient(135deg, #3d6ee4 0%, #139dc7 100%);
}
:root[data-theme="light"] .btn-secondary {
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"] .btn-secondary:hover:not(:disabled) {
color: #0d4f9e;
background: linear-gradient(180deg, rgba(15, 143, 181, 0.13), rgba(49, 95, 214, 0.1));
}
:root[data-theme="light"] .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"] .titlebar-brand,
:root[data-theme="light"] .titlebar-right {
border-color: rgba(34,49,78,0.1);
}
:root[data-theme="light"] .titlebar-brand-icon img {
filter: drop-shadow(0 1px 2px rgba(28,44,74,0.18));
}
:root[data-theme="light"] .tb-version {
color: rgba(23,32,51,0.36);
}
:root[data-theme="light"] .titlebar-info svg {
color: var(--color-accent);
}
:root[data-theme="light"] .tb-repo,
:root[data-theme="light"] .tb-no-repo {
color: var(--color-bar-muted);
}
:root[data-theme="light"] .tb-sep {
color: rgba(23,32,51,0.28);
}
:root[data-theme="light"] .tb-branch {
color: var(--color-bar-text);
}
:root[data-theme="light"] .tb-action:hover:not(:disabled),
:root[data-theme="light"] .tb-btn:hover:not(:disabled) {
background: rgba(49,95,214,0.08);
color: var(--color-ink);
}
:root[data-theme="light"] .titlebar-divider {
background: rgba(34,49,78,0.1);
}
:root[data-theme="light"] .tb-btn {
color: var(--color-bar-muted);
}
:root[data-theme="light"] .topbar {
border-color: var(--color-border);
background:
linear-gradient(90deg, rgba(49,95,214,0.06), rgba(15,143,181,0.045), rgba(214,156,49,0.035)),
var(--color-surface);
}
:root[data-theme="light"] .repo-tabbar,
:root[data-theme="light"] .repo-management-tools {
background: rgba(255,255,255,0.78);
}
:root[data-theme="light"] .repo-tab-wrap {
background: rgba(244,247,252,0.72);
}
:root[data-theme="light"] .repo-tab-wrap.active {
background: rgba(49,95,214,0.1);
}
:root[data-theme="light"] .repo-row {
border-bottom-color: rgba(34,49,78,0.08);
}
:root[data-theme="light"] .repo-row-main:hover:not(:disabled) {
background: rgba(49,95,214,0.07);
}
:root[data-theme="light"] .repo-row-icon {
border-left-color: rgba(34,49,78,0.08);
}
:root[data-theme="light"] .notice.error,
:root[data-theme="light"] .cred-error {
color: #b33445;
background: rgba(210, 55, 75, 0.08);
}
:root[data-theme="light"] .notice.busy {
color: #315fd6;
}
:root[data-theme="light"] .notice.conflict,
:root[data-theme="light"] .notice-action.conflict,
:root[data-theme="light"] .resolve-status,
:root[data-theme="light"] .resolve-conflict-label {
color: #96620f;
}
:root[data-theme="light"] .notice.rebase,
:root[data-theme="light"] .notice-action.rebase {
color: #6f3ca8;
}
:root[data-theme="light"] .update-toast {
box-shadow: 0 22px 56px rgba(28,44,74,0.18), 0 0 0 1px rgba(255,255,255,0.75) inset;
}
:root[data-theme="light"] .branch-filter-backdrop {
background: rgba(232,238,248,0.96);
}
:root[data-theme="light"] .branch-filter-dialog {
background:
linear-gradient(180deg, #ffffff 0%, #f4f7fc 72%),
#f4f7fc;
box-shadow: var(--app-dialog-shadow);
}
:root[data-theme="light"] .graph-branch-dialog-button,
:root[data-theme="light"] .branch-filter-option {
color: #16723b;
}
:root[data-theme="light"] .graph-branch-dialog-button span {
color: #ffffff;
background: #22834a;
}
:root[data-theme="light"] .main-panel {
background: var(--color-surface);
box-shadow: var(--app-panel-shadow);
}
:root[data-theme="light"] .repo-management {
background: var(--color-surface);
box-shadow: var(--app-panel-shadow);
}
:root[data-theme="light"] .repo-section {
background: rgba(255,255,255,0.62);
}
:root[data-theme="light"] .repo-section > header {
background: rgba(244,247,252,0.88);
}
:root[data-theme="light"] .repo-empty {
background: rgba(255,255,255,0.48);
}
: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: var(--color-surface-dim);
}
:root[data-theme="light"] .file-row.selected,
:root[data-theme="light"] .branch-row.current,
:root[data-theme="light"] .file-history-row.active {
background: rgba(49,95,214,0.08);
}
:root[data-theme="light"] .graph-list {
background: rgba(248,250,253,0.9);
}
:root[data-theme="light"] .graph-gutter {
border-right-color: rgba(34,49,78,0.1);
background:
linear-gradient(90deg, rgba(49,95,214,0.035), rgba(255,255,255,0.18)),
rgba(238,243,249,0.78);
}
:root[data-theme="light"] .graph-dot {
border-color: #ffffff;
box-shadow: 0 0 0 1px rgba(34,49,78,0.16), 0 2px 6px rgba(28,44,74,0.12);
}
:root[data-theme="light"] .graph-dot.merge {
background: #ffffff;
box-shadow: 0 0 0 1px rgba(34,49,78,0.14);
}
:root[data-theme="light"] .commit-body {
background: rgba(255,255,255,0.72);
}
:root[data-theme="light"] .graph-row + .graph-row .commit-body {
border-top-color: rgba(34,49,78,0.08);
}
:root[data-theme="light"] .graph-row:hover .commit-body {
background: rgba(235,241,250,0.9);
}
:root[data-theme="light"] .graph-row.merge-row .commit-body {
background: rgba(248,244,252,0.82);
}
:root[data-theme="light"] .graph-row.tip-row .commit-body {
background:
linear-gradient(90deg, rgba(49,95,214,0.075), transparent 34%),
rgba(255,255,255,0.82);
}
:root[data-theme="light"] .commit-summary {
color: var(--color-ink);
}
:root[data-theme="light"] .commit-avatar {
border-color: rgba(49,95,214,0.18);
color: #315fd6;
background: rgba(232,238,248,0.92);
}
:root[data-theme="light"] .commit-kind {
background: rgba(244,247,252,0.82);
}
:root[data-theme="light"] .commit-hash {
color: #315fd6;
}
:root[data-theme="light"] .commit-branch-chip,
:root[data-theme="light"] .graph-hover-branches span {
border-color: rgba(31,128,76,0.22);
color: #146b3b;
background: rgba(224,246,233,0.92);
box-shadow: 0 8px 22px rgba(28,44,74,0.12);
}
:root[data-theme="light"] .graph-hover-branches span.remote,
:root[data-theme="light"] .branch-filter-option.remote {
border-color: rgba(49,95,214,0.22);
color: #315fd6;
background: rgba(231,237,255,0.92);
}
:root[data-theme="light"] .graph-hover-branches span.ahead {
border-color: rgba(150,98,15,0.28);
color: #96620f;
background: rgba(255,244,224,0.95);
}
:root[data-theme="light"] .graph-hover-branches span.behind {
border-color: rgba(49,95,214,0.26);
color: #315fd6;
background: rgba(231,237,255,0.95);
}
:root[data-theme="light"] .ref-list .ref-chip.head {
color: #ffffff;
background: linear-gradient(135deg, #0f8fb5, #315fd6);
}
:root[data-theme="light"] .ref-list .ref-chip.branch {
color: #16723b;
background: rgba(78,202,118,0.12);
}
:root[data-theme="light"] .ref-list .ref-chip.remote {
color: #315fd6;
background: rgba(49,95,214,0.09);
}
:root[data-theme="light"] .commit-files,
:root[data-theme="light"] .commit-file-button {
background: rgba(248,250,253,0.78);
}
:root[data-theme="light"] .file-history-rail-toggle {
background: linear-gradient(180deg, rgba(49,95,214,0.08), rgba(15,143,181,0.04));
}
:root[data-theme="light"] .file-history-rail-toggle:hover:not(:disabled) {
background: linear-gradient(180deg, rgba(49,95,214,0.12), rgba(15,143,181,0.08));
}
:root[data-theme="light"] .file-history-loading {
background:
radial-gradient(circle at center 42%, rgba(49,95,214,0.1), transparent 52%),
linear-gradient(180deg, rgba(244,247,252,0.88), transparent);
}
:root[data-theme="light"] .file-history-loading-icon {
filter:
drop-shadow(0 10px 14px rgba(28,44,74,0.18))
drop-shadow(0 0 12px rgba(49,95,214,0.18));
}
:root[data-theme="light"] .branch-context-menu {
box-shadow: 0 18px 50px rgba(28,44,74,0.18);
}
:root[data-theme="light"] .dialog-file-row:hover,
:root[data-theme="light"] .branch-row:hover,
:root[data-theme="light"] .explorer-row:hover,
:root[data-theme="light"] .commit-files-toggle:hover:not(:disabled) {
background: var(--color-surface-hover);
}
:root[data-theme="light"] .split-span.split-meta {
background: #e9eef7;
}
:root[data-theme="light"] .resolve-split,
:root[data-theme="light"] .resolve-num,
:root[data-theme="light"] .resolve-cell.empty,
:root[data-theme="light"] .resolve-num.empty {
background: rgba(234,239,248,0.72);
}
:root[data-theme="light"] .diff-line.meta,
:root[data-theme="light"] .resolve-split-marker {
color: #64728a;
}
:root[data-theme="light"] .cred-input input,
:root[data-theme="light"] .cred-expiry input[type="date"] {
background: rgba(255,255,255,0.92);
color-scheme: light;
}
:root[data-theme="light"] .cred-token-hint code {
color: #0d78a0;
}
:root[data-theme="light"] .status-panel-overlay {
background:
radial-gradient(circle at 50% 38%, rgba(49, 95, 214, 0.12), transparent 55%),
rgba(244, 247, 252, 0.68);
}
:root[data-theme="light"] .status-panel-overlay-card {
background:
linear-gradient(180deg, rgba(255,255,255,0.96), rgba(244,247,252,0.94)),
var(--color-surface-raised);
box-shadow: 0 18px 44px rgba(28,44,74,0.16), inset 0 1px 0 rgba(255,255,255,0.9);
}
/* Custom tooltip — appended to body, not clipped by overflow:hidden parents */
.path-tooltip {
position: fixed;
@@ -4476,6 +4961,10 @@
@media (max-width: 740px) {
body { overflow: auto; }
.shell-body { min-height: 100%; gap: 6px; }
.titlebar-info { padding: 0 8px; }
.titlebar-actions .tb-action:not(.auto-toggle):not(:last-child) { display: none; }
.tb-action { width: 36px; padding: 0 8px; }
.tb-btn { width: 34px; }
.workspace { grid-template-columns: 1fr; gap: 6px; }
.left-sidebar-resize-handle { display: none; }
.history-aside { grid-template-columns: 1fr; grid-template-rows: minmax(200px, 1fr) minmax(150px, 0.5fr); min-height: 380px; }
+27 -5
View File
@@ -24,22 +24,44 @@
export let onToggleAutoRefresh: () => void = () => {};
export let onOpenSettings: () => void = () => {};
const win = getCurrentWindow();
let win: ReturnType<typeof getCurrentWindow> | null = null;
let isMaximized = false;
let unlisten: (() => void) | undefined;
let appVersion = "";
onMount(async () => {
try {
win = getCurrentWindow();
isMaximized = await win.isMaximized();
unlisten = await win.onResized(async () => {
isMaximized = await win.isMaximized();
isMaximized = await win?.isMaximized() ?? false;
});
} catch {
win = null;
}
try {
appVersion = await getVersion();
} catch {
appVersion = "";
}
});
onDestroy(() => {
unlisten?.();
});
function minimizeWindow() {
void win?.minimize();
}
function toggleMaximizeWindow() {
void win?.toggleMaximize();
}
function closeWindow() {
void win?.close();
}
</script>
<header class="titlebar" data-tauri-drag-region>
@@ -200,12 +222,12 @@
<div class="titlebar-divider" aria-hidden="true"></div>
<div class="titlebar-controls">
<button class="tb-btn" onclick={() => win.minimize()} title="Minimize" aria-label="Minimize">
<button class="tb-btn" onclick={minimizeWindow} title="Minimize" aria-label="Minimize">
<Minus size={12} aria-hidden="true" />
</button>
<button
class="tb-btn"
onclick={() => win.toggleMaximize()}
onclick={toggleMaximizeWindow}
title={isMaximized ? "Restore" : "Maximize"}
aria-label={isMaximized ? "Restore" : "Maximize"}
>
@@ -220,7 +242,7 @@
</svg>
{/if}
</button>
<button class="tb-btn close" onclick={() => win.close()} title="Close" aria-label="Close">
<button class="tb-btn close" onclick={closeWindow} title="Close" aria-label="Close">
<X size={12} aria-hidden="true" />
</button>
</div>
+32 -4
View File
@@ -1,19 +1,22 @@
<script lang="ts">
import { Check, Settings, X } from "@lucide/svelte";
import type { AnalyticsSettings } from "../types";
import type { AnalyticsSettings, AppTheme } from "../types";
interface Props {
analytics: AnalyticsSettings;
onSave: (settings: AnalyticsSettings) => void;
theme: AppTheme;
onSave: (settings: AnalyticsSettings, theme: AppTheme) => void;
onClose: () => void;
}
let { analytics, onSave = () => {}, onClose = () => {} }: Props = $props();
let { analytics, theme = "system", onSave = () => {}, onClose = () => {} }: Props = $props();
let analyticsEnabled = $state(true);
let selectedTheme = $state<AppTheme>("system");
$effect(() => {
analyticsEnabled = analytics.enabled;
selectedTheme = theme;
});
function save() {
@@ -21,7 +24,7 @@
...analytics,
enabled: analyticsEnabled,
noticeSeen: true,
});
}, selectedTheme);
}
</script>
@@ -38,6 +41,31 @@
</header>
<form class="app-settings-form" onsubmit={(event) => { event.preventDefault(); save(); }}>
<section class="settings-section">
<header>
<Settings size={16} aria-hidden="true" />
<div>
<span class="eyebrow">Appearance</span>
<h3>Theme</h3>
</div>
</header>
<div class="settings-segmented" role="radiogroup" aria-label="Theme">
<label class:active={selectedTheme === "system"}>
<input type="radio" bind:group={selectedTheme} value="system" />
<span>System</span>
</label>
<label class:active={selectedTheme === "light"}>
<input type="radio" bind:group={selectedTheme} value="light" />
<span>Light</span>
</label>
<label class:active={selectedTheme === "dark"}>
<input type="radio" bind:group={selectedTheme} value="dark" />
<span>Dark</span>
</label>
</div>
</section>
<section class="settings-section">
<header>
<Settings size={16} aria-hidden="true" />
+58 -19
View File
@@ -41,9 +41,7 @@
display: grid;
place-items: center;
overflow: hidden;
background:
radial-gradient(circle at 50% 42%, rgba(137, 92, 255, 0.18), transparent 34%),
linear-gradient(135deg, #050712 0%, #080b16 46%, #120b18 100%);
background: linear-gradient(135deg, #070a10 0%, #0c111a 48%, #090e16 100%);
animation: overlay-in 180ms ease;
}
@@ -52,8 +50,8 @@
inset: 0;
opacity: 0.28;
background-image:
linear-gradient(rgba(151, 118, 255, 0.12) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 109, 38, 0.08) 1px, transparent 1px);
linear-gradient(rgba(111, 140, 255, 0.09) 1px, transparent 1px),
linear-gradient(90deg, rgba(77, 182, 214, 0.07) 1px, transparent 1px);
background-size: 42px 42px;
mask-image: radial-gradient(circle at center, black 0%, transparent 68%);
animation: grid-drift 10s linear infinite;
@@ -67,14 +65,14 @@
gap: 18px;
width: min(420px, calc(100vw - 42px));
padding: 30px 34px 28px;
border: 1px solid rgba(160, 124, 255, 0.24);
border: 1px solid rgba(90, 111, 154, 0.28);
border-radius: 16px;
background:
linear-gradient(180deg, rgba(23, 26, 43, 0.9), rgba(12, 15, 27, 0.92)),
linear-gradient(180deg, rgba(23, 29, 43, 0.92), rgba(12, 17, 27, 0.94)),
var(--color-surface-raised);
box-shadow:
0 26px 90px rgba(0, 0, 0, 0.62),
inset 0 1px 0 rgba(255, 255, 255, 0.06);
0 26px 78px rgba(0, 0, 0, 0.54),
inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.repo-loading-mark {
@@ -89,7 +87,7 @@
.repo-loading-halo {
position: absolute;
inset: 10px;
border: 1px solid rgba(151, 118, 255, 0.24);
border: 1px solid rgba(111, 140, 255, 0.22);
border-radius: 34px;
transform: rotate(45deg);
}
@@ -98,7 +96,7 @@
}
.repo-loading-halo.halo-two {
inset: 24px;
border-color: rgba(255, 109, 38, 0.26);
border-color: rgba(77, 182, 214, 0.24);
animation: halo-breathe 2.4s ease-in-out infinite reverse;
}
@@ -116,18 +114,18 @@
stroke-linecap: round;
stroke-dasharray: 165;
stroke-dashoffset: 165;
filter: drop-shadow(0 0 8px rgba(151, 118, 255, 0.55));
filter: drop-shadow(0 0 8px rgba(77, 182, 214, 0.32));
animation: trace-draw 2.6s ease-in-out infinite;
}
.repo-loading-traces .trace-main {
stroke: #9b70ff;
stroke: #6f8cff;
}
.repo-loading-traces .trace-branch {
stroke: #ff6d26;
stroke: #4db6d6;
animation-delay: 0.28s;
}
.repo-loading-traces .trace-cut {
stroke: rgba(255, 255, 255, 0.42);
stroke: rgba(177, 186, 208, 0.42);
stroke-dasharray: 128;
stroke-dashoffset: 128;
animation-delay: 0.55s;
@@ -141,7 +139,7 @@
object-fit: contain;
filter:
drop-shadow(0 18px 24px rgba(0, 0, 0, 0.55))
drop-shadow(0 0 18px rgba(151, 118, 255, 0.28));
drop-shadow(0 0 18px rgba(77, 182, 214, 0.2));
animation: icon-float 2.4s ease-in-out infinite;
}
@@ -175,18 +173,59 @@
height: 4px;
overflow: hidden;
border-radius: 999px;
background: rgba(151, 118, 255, 0.14);
background: rgba(111, 140, 255, 0.14);
}
.repo-loading-bar span {
position: absolute;
inset: 0;
width: 46%;
border-radius: inherit;
background: linear-gradient(90deg, transparent, #9b70ff 40%, #ff6d26 74%, transparent);
box-shadow: 0 0 16px rgba(255, 109, 38, 0.32);
background: linear-gradient(90deg, transparent, #6f8cff 40%, #4db6d6 74%, transparent);
box-shadow: 0 0 16px rgba(77, 182, 214, 0.26);
animation: bar-slide 1.35s ease-in-out infinite;
}
:global(:root[data-theme="light"]) .repo-loading {
background:
radial-gradient(circle at 50% 42%, rgba(49, 95, 214, 0.12), transparent 34%),
linear-gradient(135deg, #f7f9fd 0%, #eef3f9 48%, #f8fafc 100%);
}
:global(:root[data-theme="light"]) .repo-loading-grid {
opacity: 0.38;
background-image:
linear-gradient(rgba(49, 95, 214, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(15, 143, 181, 0.08) 1px, transparent 1px);
}
:global(:root[data-theme="light"]) .repo-loading-card {
border-color: rgba(61, 89, 142, 0.2);
background:
linear-gradient(180deg, rgba(255,255,255,0.96), rgba(244,247,252,0.94)),
var(--color-surface-raised);
box-shadow:
0 26px 72px rgba(28,44,74,0.18),
inset 0 1px 0 rgba(255,255,255,0.9);
}
:global(:root[data-theme="light"]) .repo-loading-traces .trace {
filter: drop-shadow(0 0 8px rgba(49,95,214,0.22));
}
:global(:root[data-theme="light"]) .repo-loading-traces .trace-cut {
stroke: rgba(49,95,214,0.34);
}
:global(:root[data-theme="light"]) .repo-loading-icon {
filter:
drop-shadow(0 18px 24px rgba(28,44,74,0.2))
drop-shadow(0 0 18px rgba(49,95,214,0.18));
}
:global(:root[data-theme="light"]) .repo-loading-bar {
background: rgba(49,95,214,0.12);
}
@keyframes overlay-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes grid-drift { to { transform: translate3d(42px, 42px, 0); } }
@keyframes icon-float {
+1
View File
@@ -10,6 +10,7 @@ export type FileStatusKind =
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 interface CommitAiStatus {
phase: CommitAiPhase;
+17
View File
@@ -3,12 +3,29 @@ import { mount } from "svelte";
import App from "./App.svelte";
import "./app.css";
const THEME_KEY = "gitlite.theme.v1";
const target = document.getElementById("app");
if (!target) {
throw new Error("App target element was not found.");
}
try {
const storedTheme = localStorage.getItem(THEME_KEY);
const preference = storedTheme === "light" || storedTheme === "dark" || storedTheme === "system"
? storedTheme
: "system";
const resolved = preference === "system" && window.matchMedia("(prefers-color-scheme: light)").matches
? "light"
: preference === "system"
? "dark"
: preference;
document.documentElement.dataset.themePreference = preference;
document.documentElement.dataset.theme = resolved;
} catch {
// Storage is best-effort; the CSS system theme fallback still applies.
}
const app = mount(App, { target });
export default app;