refactor(ui): modernize status bar and component structure

This commit introduces a comprehensive overhaul of the application's UI, focusing on modernizing the global workspace status bar and improving overall theming consistency. Several components were refactored to simplify prop handling and improve separation of concerns, particularly within the TitleBar and RepoToolbar. The CSS includes extensive new variables and styles for better visual fidelity across light and dark themes.

- Overhauled the main application footer to display version, branch status, and sync metrics.
- Added global CSS variables and component styling for a modern look.
- Simplified repository state management by removing redundant props from TitleBar.
This commit is contained in:
Christoph Brandau
2026-07-12 23:32:55 +02:00
parent f9c0c00618
commit 735acd2551
8 changed files with 565 additions and 175 deletions
+389 -3
View File
@@ -2145,15 +2145,15 @@
align-items: center;
gap: 6px;
width: 100%;
min-height: 32px;
padding: 4px 8px 4px calc(8px + var(--depth, 0) * 14px);
min-height: 28px;
padding: 2px 7px 2px calc(7px + var(--depth, 0) * 14px);
border: 1px solid transparent;
border-radius: 6px;
background: transparent;
text-align: left;
transition: background 120ms ease, border-color 120ms ease;
}
.explorer-row + .explorer-row { margin-top: 2px; }
.explorer-row + .explorer-row { margin-top: 0; }
.explorer-row:hover { background: var(--color-surface-hover); border-color: var(--color-border-subtle); }
.explorer-row.active { background: rgba(90,140,248,0.1); border-color: rgba(90,140,248,0.28); }
.explorer-row.folder { font-weight: 700; }
@@ -4974,6 +4974,290 @@
background: rgba(247,249,252,0.96);
}
/* 2026 workspace refresh --------------------------------------------------
A single, quiet product system shared by management, repository workspace,
dialogs and both color themes. Kept as an override layer so existing Git
behavior and component ownership stay unchanged. */
:root {
--ui-radius: 7px;
--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-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;
}
:root[data-theme="light"] {
--ui-shadow: 0 10px 28px rgba(23, 40, 72, 0.09);
--app-bg: #f4f6f9;
--app-button-bg: #ffffff;
--app-input-bg: #ffffff;
--app-panel-highlight: none;
--app-panel-shadow: none;
--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;
}
body { background: var(--app-bg); }
button {
min-height: var(--ui-control-height);
border-radius: var(--ui-radius-sm);
box-shadow: none;
font-size: 12px;
font-weight: 650;
}
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;
}
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); }
.shell { --app-titlebar-height: 40px; --app-toolbar-height: 64px; background: var(--app-bg); }
.shell-body { gap: 0; padding: 0; }
.titlebar {
border-bottom: 1px solid var(--color-border-subtle);
background: var(--color-surface-solid);
}
.titlebar-brand { min-width: 140px; padding-left: 14px; border-right: 0; font-size: 14px; }
.titlebar-brand-icon,
.titlebar-brand-icon img { width: 22px; height: 22px; }
.titlebar-brand-icon { flex-basis: 22px; }
.titlebar-drag { align-self: stretch; min-width: 0; }
.titlebar-info { justify-self: center; width: min(480px, 100%); }
.titlebar-context { justify-content: center; }
.tb-repo, .tb-branch { color: var(--color-ink); font-size: 13px; }
.tb-version { color: var(--color-ink-faint); }
.titlebar-globals { margin-left: auto; }
.titlebar-divider { background: var(--color-border-subtle); }
.repo-tabbar {
min-height: 46px;
padding: 0 16px;
border-bottom: 1px solid var(--color-border);
border-radius: 0;
background: var(--color-surface-dim);
}
.repo-tab-wrap { min-height: 45px; border-right: 1px solid var(--color-border-subtle); border-radius: 0; }
.repo-tab-wrap:first-child { border-left: 1px solid var(--color-border-subtle); }
.repo-tab-wrap.active { background: var(--color-surface-solid); box-shadow: inset 0 -3px 0 var(--color-primary); }
.repo-tab { min-height: 45px; padding-left: 14px; font-size: 12.5px; }
.repo-tab-add { min-height: 45px; }
.repo-toolbar {
height: var(--app-toolbar-height);
padding: 7px 18px 8px;
border: 0;
border-bottom: 1px solid var(--color-border);
border-radius: 0;
background: var(--color-surface-solid);
}
.repo-toolbar-sync { grid-template-rows: 10px 36px; }
.repo-toolbar-group-label { padding-left: 1px; font-size: 8.5px; letter-spacing: .13em; }
.repo-action-group { height: 36px; border-color: var(--color-border); background: transparent; }
.repo-action { height: 34px; min-height: 34px; padding-inline: 15px; font-weight: 650; }
.repo-action.sync-primary { color: var(--color-primary); }
.repo-toolbar-divider { height: 34px; margin-inline: 6px; }
.workspace {
grid-template-columns: minmax(220px, var(--left-sidebar-width, 280px)) 7px minmax(360px, 1fr) 7px minmax(560px, var(--history-aside-width, 620px));
flex: 1 1 0;
padding: 0;
background: var(--color-border-subtle);
row-gap: 0;
}
.left-sidebar { background: var(--color-surface-solid); }
.main-panel { border: 0; border-radius: 0; background: var(--color-surface-solid); }
.history-aside { background: var(--color-border-subtle); row-gap: 0; }
.panel {
border: 0;
border-radius: 0;
background: var(--color-surface-solid);
box-shadow: none;
backdrop-filter: none;
}
.left-sidebar .panel + .panel { border-top: 1px solid var(--color-border); }
.section-head {
min-height: 50px;
padding: 8px 12px;
border-bottom-color: var(--color-border-subtle);
background: var(--color-surface-solid);
}
.section-head h2 { font-size: 14px; font-weight: 750; }
.eyebrow { font-size: 9px; font-weight: 750; letter-spacing: .11em; }
.pill { min-height: 19px; padding-inline: 6px; border-radius: 5px; }
.pill-count { color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 10%, transparent); }
.repo-summary { height: 48px; padding-inline: 16px; background: var(--color-surface-dim); }
.repo-branch { font-size: 14px; }
.repo-path { opacity: .82; }
.sync-stats strong, .sync-stats span { border-radius: 5px; background: transparent !important; }
.top-section { grid-template-rows: minmax(160px, 1fr) 7px var(--commit-panel-height, 220px); padding: 0; }
.left-sidebar-resize-handle,
.history-resize-handle,
.file-history-resize-handle,
.panel-resize-handle,
.left-panel-resize-handle { background: var(--color-border-subtle); }
.left-sidebar-resize-handle::before,
.history-resize-handle::before,
.file-history-resize-handle::before { width: 1px; height: 48px; background: var(--color-border); }
.panel-resize-handle::before { width: 44px; height: 2px; }
.status-toolbar {
min-height: 40px;
padding: 5px 10px;
border-bottom: 1px solid var(--color-border-subtle);
background: var(--color-surface-dim);
}
.status-toolbar .danger { margin-left: auto; }
.status-lanes { display: grid; align-content: start; min-height: 0; }
.status-lane + .status-lane { border-top: 1px solid var(--color-border); }
.status-lane-head {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 42px;
padding: 5px 12px;
background: var(--color-surface-dim);
}
.status-lane-head > div { display: flex; align-items: center; gap: 7px; }
.status-lane-head strong { color: var(--color-ink); font-size: 12px; }
.status-lane-head span { display: grid; place-items: center; min-width: 20px; height: 20px; border-radius: 5px; color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 10%, transparent); font-size: 10.5px; font-weight: 750; }
.status-file-list { padding: 5px 0; }
.status-file-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto;
align-items: center;
min-height: 42px;
padding: 3px 8px 3px 12px;
border-left: 3px solid transparent;
border-bottom: 1px solid var(--color-border-subtle);
}
.status-file-row:last-child { border-bottom: 0; }
.status-file-row:hover { background: var(--color-surface-hover); }
.status-file-row.selected { background: color-mix(in srgb, var(--color-primary) 9%, var(--color-surface-solid)); }
.status-file-row.active { border-left-color: var(--color-primary); }
.status-file-main { display: grid; justify-content: start; gap: 1px; min-width: 0; padding: 3px 8px; border: 0; background: transparent; text-align: left; }
.status-file-main:hover:not(:disabled) { background: transparent; }
.status-file-main strong, .status-file-main span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.status-file-main strong { color: var(--color-ink); font: 650 12px/1.3 var(--font-mono); }
.status-file-main span { color: var(--color-ink-faint); font: 10px/1.2 var(--font-mono); }
.status-file-actions { display: flex; margin-left: 5px; opacity: 0; transition: opacity 120ms ease; }
.status-file-row:hover .status-file-actions, .status-file-row:focus-within .status-file-actions { opacity: 1; }
.status-file-actions button { width: 28px; min-width: 28px; min-height: 28px; padding: 0; border-color: transparent; background: transparent; }
.status-file-actions .danger:hover:not(:disabled) { color: #e86060; background: rgba(232,96,96,.1); }
.status-lane-empty { margin: 0; padding: 14px 16px; color: var(--color-ink-faint); font-size: 11.5px; }
.status-badge { min-width: 58px; padding-inline: 5px; border: 0; border-radius: 4px; font-size: 9px; letter-spacing: .04em; }
.commit-panel { border-top: 1px solid var(--color-border); }
.commit-head-actions { display: flex; align-items: center; gap: 5px; }
.commit-generate-button { color: var(--color-primary); background: transparent; }
.commit-settings-button { width: 30px; min-width: 30px; padding: 0; background: transparent; }
.commit-form { padding: 10px 12px 12px; }
.commit-form textarea { min-height: 72px; resize: none; }
.commit-amend-row { min-height: 34px; }
.commit-actions-row .btn-primary { min-height: 38px; border-radius: var(--ui-radius-sm); background: var(--color-primary); box-shadow: none; }
.commit-actions-row .btn-primary:hover:not(:disabled) { background: var(--color-primary-dark); }
.branch-list, .explorer-list, .stash-list { padding: 5px !important; }
.branch-row, .explorer-row, .stash-row { border-radius: var(--ui-radius-sm); }
.branch-row.current, .explorer-row.active { background: color-mix(in srgb, var(--color-primary) 11%, var(--color-surface-solid)); box-shadow: inset 3px 0 0 var(--color-primary); }
.branch-group-toggle { background: transparent; }
.explorer-row .status-badge { min-width: 18px; overflow: hidden; color: #d9891b; background: transparent; text-indent: -999px; }
.explorer-row .status-badge::after { content: "M"; float: right; text-indent: 0; }
.history-panel, .file-history-panel { min-height: 0; }
.graph-list { background: var(--color-surface-solid); }
.graph-gutter { background: var(--color-surface-dim); }
.commit-body { border-radius: var(--ui-radius-sm); background: transparent; box-shadow: none; }
.graph-row + .graph-row .commit-body { border-top: 1px solid var(--color-border-subtle); }
.graph-row:hover .commit-body { background: var(--color-surface-hover); }
.graph-row.tip-row .commit-body { background: color-mix(in srgb, var(--color-primary) 7%, var(--color-surface-solid)); }
.commit-avatar { border-radius: 50%; }
.commit-kind, .commit-branch-chip, .ref-chip { border-radius: 4px !important; }
.file-history-row { margin: 0; border: 0; border-bottom: 1px solid var(--color-border-subtle); border-radius: 0; background: transparent; }
.workspace-statusbar {
display: flex;
align-items: center;
gap: 14px;
min-height: 30px;
padding: 0 14px;
border-top: 1px solid var(--color-border);
color: var(--color-ink-faint);
background: var(--color-surface-solid);
font-size: 10.5px;
}
.workspace-statusbar > span { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.workspace-status-spacer { flex: 1 1 auto; }
.workspace-health > span { width: 8px; height: 8px; border-radius: 50%; background: #d9891b; }
.workspace-health.clean > span { background: #2da44e; }
.workspace-statusbar .ahead { color: #d9891b; }
.workspace-statusbar .behind { color: var(--color-primary); }
.workspace-auto i { width: 7px; height: 7px; border-radius: 50%; background: var(--color-ink-faint); }
.workspace-auto.active i { background: #2da44e; }
.app-version {
padding-left: 12px;
border-left: 1px solid var(--color-border-subtle);
color: var(--color-ink-faint);
font-family: var(--font-mono);
font-size: 9.5px;
}
.repo-management { margin: 14px; border-radius: var(--ui-radius); background: var(--color-surface-solid); box-shadow: var(--ui-shadow); }
.repo-management-head, .repo-management-tools { background: var(--color-surface-solid); }
.repo-section { border-radius: var(--ui-radius-sm); background: var(--color-surface-solid); }
.repo-section > header { background: var(--color-surface-dim); }
.repo-row-main:hover:not(:disabled) { background: var(--color-surface-hover); }
@media (max-width: 1180px) {
.repo-action { padding-inline: 10px; }
.repo-toolbar-divider { margin-inline: 2px; }
.repo-action-label { display: none; }
.repo-action.sync-primary .repo-action-label { display: inline; }
}
@media (max-width: 900px) {
.shell-body { overflow: auto; }
.workspace { grid-template-columns: minmax(190px, 230px) 7px minmax(420px, 1fr); min-height: 760px; }
.history-resize-handle, .history-aside { display: none; }
.workspace-statusbar { position: sticky; bottom: 0; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { scroll-behavior: auto !important; transition-duration: .01ms !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; }
}
:root[data-theme="light"] .repo-tab-wrap {
background: rgba(255,255,255,0.5);
}
@@ -5480,3 +5764,105 @@
.repo-toolbar-divider { margin-inline: 0; }
.repo-auto-toggle { padding-left: 7px; gap: 6px; }
}
/* Keep the refreshed workspace rules authoritative after legacy theme/media
compatibility declarations above. */
.commit-actions-row .btn-primary,
:root[data-theme="light"] .commit-actions-row .btn-primary {
border-color: var(--color-primary);
color: #fff;
background: var(--color-primary);
box-shadow: none;
}
.commit-actions-row .btn-primary:hover:not(:disabled),
:root[data-theme="light"] .commit-actions-row .btn-primary:hover:not(:disabled) {
border-color: var(--color-primary-dark);
color: #fff;
background: var(--color-primary-dark);
}
:root[data-theme="light"] .panel,
:root[data-theme="light"] .main-panel,
:root[data-theme="light"] .graph-list,
:root[data-theme="light"] .commit-body { box-shadow: none; }
@media (max-width: 1100px) {
.shell-body { overflow: auto; }
.workspace {
grid-template-columns: minmax(200px, 250px) 7px minmax(480px, 1fr);
min-width: 760px;
min-height: 680px;
}
.history-resize-handle,
.history-aside { display: none; }
.workspace-statusbar { position: sticky; bottom: 0; z-index: 20; }
}
/* Repository workflow order: inspect first, then remote synchronization. */
.repo-toolbar > .repo-inspect-actions { order: 1; }
.repo-toolbar > .repo-toolbar-divider:not(.utility) { order: 2; }
.repo-toolbar > .repo-toolbar-sync {
order: 3;
display: block;
align-self: auto;
margin-bottom: 1px;
}
.repo-toolbar > .repo-toolbar-spacer { order: 4; }
.repo-toolbar > .repo-toolbar-divider.utility { order: 5; }
.repo-toolbar > .repo-utility-actions { order: 6; }
/* Compact change map for long compare and line-patch views. */
.split-diff-shell,
.line-patch-workspace {
display: grid;
grid-template-columns: minmax(0, 1fr) 16px;
flex: 1 1 0;
min-width: 0;
min-height: 0;
overflow: hidden;
}
.split-diff-shell .split-diff { min-height: 0; }
.line-patch-workspace .line-patch-scroll { min-height: 0; }
.diff-overview {
position: relative;
min-width: 16px;
min-height: 0;
overflow: hidden;
border-left: 1px solid var(--color-border-subtle);
background: var(--code-surface-subtle);
}
.diff-overview::before {
content: "";
position: absolute;
inset: 5px 6px;
border-radius: 999px;
background: var(--color-border-subtle);
}
.diff-overview-marker {
position: absolute;
z-index: 1;
top: var(--marker-position);
left: 2px;
width: 11px;
min-width: 11px;
height: 5px;
min-height: 5px;
padding: 0;
border: 0;
border-radius: 2px;
transform: translateY(-50%);
box-shadow: 0 0 0 1px color-mix(in srgb, currentColor 28%, transparent);
}
.diff-overview-marker.add { color: var(--code-add-strong); background: var(--code-add-strong); }
.diff-overview-marker.delete { color: var(--code-delete-strong); background: var(--code-delete-strong); }
.diff-overview-marker.mixed {
color: var(--color-accent);
background: linear-gradient(90deg, var(--code-delete-strong) 0 48%, var(--code-add-strong) 52% 100%);
}
.diff-overview-marker:hover:not(:disabled),
.diff-overview-marker:focus-visible {
width: 13px;
left: 1px;
filter: brightness(1.18);
outline: 1px solid var(--color-ink);
outline-offset: 1px;
}