Compare commits

...
2 Commits
Author SHA1 Message Date
Christoph Brandau d0bca62362 refactor(ui): Improve title bar layout using flex and grid
The structure of the application title bar has been updated to utilize modern CSS layout techniques like Grid and Flexbox. This refactoring improves the responsiveness and organization of key elements such as repository name, branch indicator, and synchronization status. The changes ensure better alignment and handling of varying content lengths across different viewports.

- Restructures repo/branch info into a dedicated context container
- Uses flex properties for dynamic sizing of title bar sections
- Groups sync indicators into a cohesive unit
2026-07-10 22:21:53 +02:00
Christoph Brandau d3cde83518 style(css): standardize code surface and highlight colors
Introduces a comprehensive set of CSS variables defining surfaces, syntax elements, and diff coloring across both light and dark themes. This refactoring replaces numerous hardcoded color values throughout the stylesheet with these new variables, ensuring that all components consistently adhere to the defined theme palette.

- Added detailed variable definitions for code surfaces (e.g., `--code-surface`, `--code-input-bg`).
- Updated diff, hunk, and blame sections to use variable colors for better thematic consistency.
- Replaced fixed hex codes with variables across various component backgrounds and text colors.
2026-07-10 22:16:06 +02:00
2 changed files with 200 additions and 89 deletions
+183 -78
View File
@@ -44,6 +44,27 @@
--app-settings-row-bg: #141b29;
--app-scrollbar-thumb: #303a4f;
--app-scrollbar-thumb-hover: #44506a;
--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-add-text: #5dd88a;
--code-add-strong: #4eca76;
--code-add-bg: rgba(78, 202, 118, 0.09);
--code-add-gutter-bg: rgba(78, 202, 118, 0.1);
--code-delete-text: #ef8080;
--code-delete-strong: #e86060;
--code-delete-bg: rgba(232, 96, 96, 0.1);
--code-delete-gutter-bg: rgba(232, 96, 96, 0.12);
--code-hunk-text: #7aacff;
--code-hunk-bg: rgba(122, 172, 255, 0.08);
--code-match-text: #f3c969;
--code-match-bg: rgba(240, 182, 72, 0.22);
--code-match-gutter-bg: rgba(240, 182, 72, 0.2);
}
:root[data-theme="light"] {
@@ -89,6 +110,27 @@
--app-settings-row-bg: #f8fafd;
--app-scrollbar-thumb: #c2cada;
--app-scrollbar-thumb-hover: #aeb8cb;
--code-surface: #fbfcfe;
--code-surface-raised: #f1f5fa;
--code-surface-subtle: #f3f6fb;
--code-surface-muted: #edf1f7;
--code-surface-meta: #e9eef7;
--code-input-bg: #ffffff;
--code-hover-bg: #e8eef7;
--code-add-text: #146c37;
--code-add-strong: #19723d;
--code-add-bg: rgba(25, 114, 61, 0.1);
--code-add-gutter-bg: rgba(25, 114, 61, 0.14);
--code-delete-text: #a91f36;
--code-delete-strong: #b4233b;
--code-delete-bg: rgba(180, 35, 59, 0.09);
--code-delete-gutter-bg: rgba(180, 35, 59, 0.13);
--code-hunk-text: #245cc7;
--code-hunk-bg: rgba(36, 92, 199, 0.09);
--code-match-text: #744500;
--code-match-bg: rgba(230, 158, 31, 0.2);
--code-match-gutter-bg: rgba(230, 158, 31, 0.24);
}
@layer base {
@@ -568,7 +610,8 @@
}
.titlebar-info {
display: flex;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 6px;
padding: 0 12px;
@@ -576,12 +619,20 @@
height: 100%;
overflow: hidden;
}
.titlebar-info svg { color: var(--color-accent); flex-shrink: 0; }
.titlebar-context {
display: flex;
align-items: center;
min-width: 0;
gap: 6px;
overflow: hidden;
}
.titlebar-context svg { color: var(--color-accent); flex: 0 0 auto; }
.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; }
.tb-repo { flex: 0 1 160px; min-width: 0; color: var(--color-bar-muted); font-size: 12px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-sep { flex: 0 0 auto; color: rgba(255,255,255,0.22); font-size: 13px; }
.tb-branch { flex: 1 1 auto; min-width: 0; max-width: 220px; color: #f5f7ff; font-size: 12px; font-weight: 700; font-family: var(--font-mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-sync-group { display: inline-flex; align-items: center; gap: 4px; min-width: max-content; }
.tb-sync { display: inline-flex; align-items: center; padding: 1px 6px; border-radius: 999px; font-size: 11px; font-weight: 800; white-space: nowrap; flex-shrink: 0; }
.tb-sync.ahead { color: #e0a040; background: rgba(224,160,64,0.13); }
.tb-sync.behind { color: #7aacff; background: rgba(122,172,255,0.13); }
@@ -3124,7 +3175,7 @@
gap: 8px;
padding: 7px 12px;
border-bottom: 1px solid var(--color-border-subtle);
background: #171a2b;
background: var(--code-surface-raised);
font-family: var(--font-mono);
font-size: 12px;
color: var(--color-ink-muted);
@@ -3146,7 +3197,7 @@
font-size: 12px;
line-height: 1.5;
tab-size: 2;
background: #111321;
background: var(--code-surface);
}
.split-pane {
@@ -3170,8 +3221,8 @@
white-space: pre-wrap;
word-break: break-all;
}
.split-span.split-meta { color: var(--color-ink-faint); background: #0c0e18; font-size: 11px; }
.split-span.split-hunk { color: #7aacff; background: rgba(122,172,255,0.08); padding: 3px 10px; }
.split-span.split-meta { color: var(--color-ink-faint); background: var(--code-surface-meta); font-size: 11px; }
.split-span.split-hunk { color: var(--code-hunk-text); background: var(--code-hunk-bg); padding: 3px 10px; }
.split-num {
padding: 0 6px 0 4px;
@@ -3180,11 +3231,11 @@
font-size: 11px;
user-select: none;
border-right: 1px solid var(--color-border-subtle);
background: #0d101a;
background: var(--code-surface-subtle);
}
.split-num.del { background: rgba(232,96,96,0.12); color: rgba(232,96,96,0.6); border-right-color: rgba(232,96,96,0.2); }
.split-num.add { background: rgba(78,202,118,0.1); color: rgba(78,202,118,0.6); border-right-color: rgba(78,202,118,0.2); }
.split-num.empty { background: #10131e; }
.split-num.del { background: var(--code-delete-gutter-bg); color: var(--code-delete-strong); border-right-color: rgba(232,96,96,0.2); }
.split-num.add { background: var(--code-add-gutter-bg); color: var(--code-add-strong); border-right-color: rgba(78,202,118,0.2); }
.split-num.empty { background: var(--code-surface-muted); }
.split-cell {
padding: 0 8px;
@@ -3193,20 +3244,20 @@
min-width: 0;
overflow: visible;
}
.split-cell.del { background: rgba(232,96,96,0.1); color: #ef8080; }
.split-cell.add { background: rgba(78,202,118,0.09); color: #5dd88a; }
.split-cell.empty { background: #10131e; }
.split-cell.del { background: var(--code-delete-bg); color: var(--code-delete-text); }
.split-cell.add { background: var(--code-add-bg); color: var(--code-add-text); }
.split-cell.empty { background: var(--code-surface-muted); }
/* Search-hit highlight: amber, distinct from add (green) / del (red).
Higher specificity so it overrides the add/del backgrounds on a matched line. */
.split-diff .split-cell.match {
background: rgba(240,182,72,0.22);
color: #f3c969;
background: var(--code-match-bg);
color: var(--code-match-text);
box-shadow: inset 2px 0 0 rgba(240,182,72,0.9);
}
.split-diff .split-num.match {
background: rgba(240,182,72,0.2);
color: rgba(240,182,72,0.9);
background: var(--code-match-gutter-bg);
color: var(--code-match-text);
border-right-color: rgba(240,182,72,0.35);
}
@@ -3226,7 +3277,7 @@
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-ink-faint);
background: #0d101a;
background: var(--code-surface-subtle);
}
.split-col-label + .split-col-label { border-left: 1px solid var(--color-border-subtle); }
.split-col-hash {
@@ -3338,7 +3389,7 @@
.line-patch-scroll {
min-height: 0;
overflow: auto;
background: #0b0b14;
background: var(--code-surface);
}
.line-patch-hunk {
@@ -3358,7 +3409,7 @@
min-width: 100%;
padding: 7px 10px;
border-bottom: 1px solid var(--color-border-subtle);
background: rgba(20, 22, 36, 0.96);
background: color-mix(in srgb, var(--code-surface-raised) 96%, transparent);
}
.line-patch-hunk-head code {
color: var(--color-accent);
@@ -3378,23 +3429,23 @@
padding: 0 8px;
border: 1px solid var(--color-border-subtle);
border-radius: 3px;
background: rgba(255, 255, 255, 0.03);
background: var(--code-surface-subtle);
color: var(--color-ink);
font-size: 12px;
font-weight: 700;
line-height: 1;
}
.line-patch-hunk-button:hover:not(:disabled) {
background: rgba(255, 255, 255, 0.08);
background: var(--code-hover-bg);
}
.line-patch-hunk-button.discard {
border-color: rgba(255, 90, 103, 0.7);
color: #ffccd1;
color: var(--code-delete-text);
}
.line-patch-hunk-button.stage,
.line-patch-hunk-button.unstage {
border-color: rgba(78, 202, 118, 0.72);
color: #bff1ce;
color: var(--code-add-text);
}
.line-patch-lines {
@@ -3412,12 +3463,12 @@
color: var(--color-ink-muted);
}
.line-patch-row.add {
background: rgba(78, 202, 118, 0.09);
color: #bff1ce;
background: var(--code-add-bg);
color: var(--code-add-text);
}
.line-patch-row.delete {
background: rgba(255, 90, 103, 0.1);
color: #ffccd1;
background: var(--code-delete-bg);
color: var(--code-delete-text);
}
.line-patch-row.meta {
color: var(--color-ink-faint);
@@ -3427,8 +3478,8 @@
text-align: center;
user-select: none;
}
.line-patch-row.add .line-patch-prefix { color: #4eca76; }
.line-patch-row.delete .line-patch-prefix { color: #ff6b7a; }
.line-patch-row.add .line-patch-prefix { color: var(--code-add-strong); }
.line-patch-row.delete .line-patch-prefix { color: var(--code-delete-strong); }
.line-patch-row code {
white-space: pre;
font-family: var(--font-mono);
@@ -3437,7 +3488,7 @@
.blame-body {
min-height: 0;
overflow: hidden;
background: #111321;
background: var(--code-surface);
}
.blame-code-header strong {
@@ -3455,7 +3506,7 @@
min-height: 38px;
padding: 6px 10px;
border-bottom: 1px solid var(--color-border-subtle);
background: #111321;
background: var(--code-surface);
}
.blame-search-bar svg {
position: absolute;
@@ -3469,7 +3520,7 @@
padding: 0 34px;
border: 1px solid var(--color-border-subtle);
border-radius: 6px;
background: #0b0e18;
background: var(--code-input-bg);
color: var(--color-ink);
font-size: 12px;
}
@@ -3522,7 +3573,7 @@
border-bottom: 1px solid var(--color-border-subtle);
}
.blame-group.uncommitted {
background: #171725;
background: var(--code-surface-raised);
}
.blame-meta {
@@ -3535,8 +3586,8 @@
min-width: 0;
padding: 8px 12px;
border-right: 1px solid var(--color-border-subtle);
background: #0d101a;
box-shadow: 8px 0 18px rgba(0, 0, 0, 0.18);
background: var(--code-surface-subtle);
box-shadow: 8px 0 18px color-mix(in srgb, var(--color-ink) 8%, transparent);
}
.blame-hash {
align-self: flex-start;
@@ -3545,7 +3596,7 @@
padding: 2px 7px;
border: 1px solid rgba(90,140,248,0.2);
border-radius: 5px;
background: #141b2d;
background: var(--code-surface-raised);
color: var(--color-accent);
font-size: 10.5px;
font-weight: 700;
@@ -3562,7 +3613,7 @@
}
.blame-summary {
overflow: hidden;
color: #aeb6d8;
color: var(--color-ink-muted);
font-size: 11px;
text-overflow: ellipsis;
white-space: nowrap;
@@ -3572,7 +3623,7 @@
font-size: 10.5px;
}
.blame-group:hover .blame-meta {
background: #111728;
background: var(--code-hover-bg);
}
.blame-group.uncommitted .blame-hash,
.blame-group.uncommitted .blame-author {
@@ -3580,7 +3631,7 @@
}
.blame-group.uncommitted .blame-hash {
border-color: rgba(232, 180, 90, 0.26);
background: #271f14;
background: color-mix(in srgb, #e8b45a 13%, var(--code-surface));
}
.blame-lines {
@@ -3595,16 +3646,16 @@
min-height: 20px;
}
.blame-group:hover .blame-line-number {
background: #111728;
background: var(--code-hover-bg);
}
.blame-group:hover .blame-line-code {
background: #151a2b;
background: var(--code-hover-bg);
}
.blame-search-hit {
padding: 0 1px;
border-radius: 3px;
background: rgba(240,182,72,0.28);
color: #f3d487;
background: var(--code-match-bg);
color: var(--code-match-text);
}
.global-search-body {
@@ -3800,8 +3851,9 @@
margin: 0;
padding: 8px 10px;
border-radius: 7px;
color: #5dd88a;
background: rgba(78,202,118,0.08);
border: 1px solid color-mix(in srgb, var(--code-add-strong) 18%, transparent);
color: var(--code-add-text);
background: var(--code-add-bg);
font-family: var(--font-mono);
font-size: 12px;
line-height: 1.45;
@@ -4321,14 +4373,14 @@
}
.diff-line { display: block; white-space: pre-wrap; word-break: break-word; }
.diff-line.meta { color: var(--color-ink-faint); }
.diff-line.hunk { color: #7aacff; background: rgba(122,172,255,0.07); }
.diff-line.add { color: #4eca76; background: rgba(78,202,118,0.09); }
.diff-line.del { color: #e86060; background: rgba(232,96,96,0.09); }
.diff-line.hunk { color: var(--code-hunk-text); background: var(--code-hunk-bg); }
.diff-line.add { color: var(--code-add-text); background: var(--code-add-bg); }
.diff-line.del { color: var(--code-delete-text); background: var(--code-delete-bg); }
.diff-line.context { color: var(--color-ink-muted); }
.diff-counts { display: flex; gap: 8px; font-family: var(--font-mono); font-size: 12px; font-weight: 700; }
.diff-counts .adds { color: #4eca76; }
.diff-counts .dels { color: #e86060; }
.diff-counts .adds { color: var(--code-add-strong); }
.diff-counts .dels { color: var(--code-delete-strong); }
/* --- Conflict resolver --- */
@@ -4399,7 +4451,7 @@
overflow: hidden;
border: 1px solid var(--color-border-subtle);
border-radius: 6px;
background: rgba(0,0,0,0.12);
background: var(--code-surface);
font-family: var(--font-mono);
font-size: 12px;
line-height: 1.5;
@@ -4431,19 +4483,19 @@
font-weight: 800;
text-transform: uppercase;
}
.resolve-split-marker.unresolved { color: #ef8080; background: rgba(232,96,96,0.12); }
.resolve-split-marker.unresolved { color: var(--code-delete-text); background: var(--code-delete-gutter-bg); }
.resolve-num {
padding: 0 6px 0 4px;
border-right: 1px solid var(--color-border-subtle);
color: var(--color-ink-faint);
background: rgba(0,0,0,0.14);
background: var(--code-surface-subtle);
text-align: right;
user-select: none;
}
.resolve-num.ours { color: rgba(78,202,118,0.65); background: rgba(78,202,118,0.11); border-right-color: rgba(78,202,118,0.2); }
.resolve-num.theirs { color: rgba(122,172,255,0.65); background: rgba(122,172,255,0.11); border-right-color: rgba(122,172,255,0.2); }
.resolve-num.empty { background: rgba(0,0,0,0.07); }
.resolve-num.ours { color: var(--code-add-strong); background: var(--code-add-gutter-bg); border-right-color: rgba(78,202,118,0.2); }
.resolve-num.theirs { color: var(--code-hunk-text); background: var(--code-hunk-bg); border-right-color: rgba(122,172,255,0.2); }
.resolve-num.empty { background: var(--code-surface-muted); }
.resolve-cell {
min-width: 0;
@@ -4452,9 +4504,9 @@
color: var(--color-ink-muted);
white-space: pre;
}
.resolve-cell.ours { color: #5dd88a; background: rgba(78,202,118,0.1); }
.resolve-cell.theirs { color: #8fb4ff; background: rgba(90,140,248,0.11); }
.resolve-cell.empty { background: rgba(0,0,0,0.06); }
.resolve-cell.ours { color: var(--code-add-text); background: var(--code-add-bg); }
.resolve-cell.theirs { color: var(--code-hunk-text); background: var(--code-hunk-bg); }
.resolve-cell.empty { background: var(--code-surface-muted); }
.resolve-cell.dimmed { opacity: 0.42; filter: grayscale(0.5); }
.resolve-context { margin: 0; padding: 2px 8px; overflow-x: auto; font-family: var(--font-mono); font-size: 12px; line-height: 1.5; tab-size: 2; color: var(--color-ink-muted); }
@@ -4474,13 +4526,13 @@
.resolve-side.dimmed { opacity: 0.4; filter: grayscale(0.5); }
.resolve-side-label { font-size: 11px; font-weight: 800; text-transform: uppercase; }
.resolve-side.ours .resolve-side-label { color: #4eca76; }
.resolve-side.theirs .resolve-side-label { color: #6a9aff; }
.resolve-side.ours .resolve-side-label { color: var(--code-add-strong); }
.resolve-side.theirs .resolve-side-label { color: var(--code-hunk-text); }
.resolve-lines { margin: 0; overflow-x: auto; font-family: var(--font-mono); font-size: 12px; line-height: 1.5; tab-size: 2; }
.resolve-line { display: block; white-space: pre-wrap; word-break: break-word; }
.resolve-line.ours { color: #4eca76; }
.resolve-line.theirs { color: #7aacff; }
.resolve-line.ours { color: var(--code-add-text); }
.resolve-line.theirs { color: var(--code-hunk-text); }
.resolve-line.context { color: var(--color-ink-muted); }
.resolve-binary { display: grid; align-content: start; gap: 12px; padding: 4px; }
@@ -4834,22 +4886,75 @@
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"] .global-search-tabs,
:root[data-theme="light"] .file-search-history,
:root[data-theme="light"] .file-search-history-head {
background: var(--color-surface-dim);
}
:root[data-theme="light"] .discard-target {
background: var(--code-surface-subtle);
}
:root[data-theme="light"] .commit-amend-toggle input {
border-color: var(--color-border-input);
background: var(--app-input-bg);
}
:root[data-theme="light"] .commit-amend-toggle input:checked {
border-color: var(--color-primary);
box-shadow: inset 0 0 0 2px #ffffff;
}
:root[data-theme="light"] .cred-segment {
border-color: rgba(49,95,214,0.2);
background: #eef3f9;
}
:root[data-theme="light"] .cred-seg-btn.active {
border-color: rgba(49,95,214,0.26);
background: linear-gradient(135deg, rgba(49,95,214,0.12), rgba(15,143,181,0.08));
box-shadow: 0 8px 18px rgba(28,44,74,0.1), inset 0 1px 0 rgba(255,255,255,0.9);
}
:root[data-theme="light"] .cred-close {
border-color: var(--color-border-subtle);
color: var(--color-ink-dim);
background: rgba(255,255,255,0.76);
}
:root[data-theme="light"] .cred-close:hover:not(:disabled) {
border-color: var(--color-border-input);
color: var(--color-ink);
background: var(--color-surface-hover);
}
:root[data-theme="light"] .status-badge.modified,
:root[data-theme="light"] .resolve-status,
:root[data-theme="light"] .resolve-conflict-label {
color: #8a580a;
}
:root[data-theme="light"] .status-badge.added,
:root[data-theme="light"] .status-badge.untracked,
:root[data-theme="light"] .pill-active,
:root[data-theme="light"] .prepared-tag {
color: #19723d;
}
:root[data-theme="light"] .status-badge.deleted {
color: #b4233b;
}
:root[data-theme="light"] .status-badge.renamed {
color: #245cc7;
}
:root[data-theme="light"] .cred-input input,
:root[data-theme="light"] .cred-expiry input[type="date"] {
background: rgba(255,255,255,0.92);
+17 -11
View File
@@ -79,17 +79,23 @@
<!-- Center: repo + branch info -->
<div class="titlebar-info" data-tauri-drag-region>
{#if hasRepository}
{#if repoName}
<span class="tb-repo" data-tauri-drag-region>{repoName}</span>
<span class="tb-sep" data-tauri-drag-region aria-hidden="true">/</span>
{/if}
<GitBranch size={12} aria-hidden="true" />
<span class="tb-branch" data-tauri-drag-region>{branch}</span>
{#if ahead > 0}
<span class="tb-sync ahead" title="{ahead} commits ahead">{ahead}</span>
{/if}
{#if behind > 0}
<span class="tb-sync behind" title="{behind} commits behind">{behind}</span>
<div class="titlebar-context" data-tauri-drag-region>
{#if repoName}
<span class="tb-repo" data-tauri-drag-region>{repoName}</span>
<span class="tb-sep" data-tauri-drag-region aria-hidden="true">/</span>
{/if}
<GitBranch size={12} aria-hidden="true" />
<span class="tb-branch" data-tauri-drag-region title={branch}>{branch}</span>
</div>
{#if ahead > 0 || behind > 0}
<div class="tb-sync-group" aria-label="Branch synchronization status">
{#if ahead > 0}
<span class="tb-sync ahead" title="{ahead} commits ahead">{ahead}</span>
{/if}
{#if behind > 0}
<span class="tb-sync behind" title="{behind} commits behind">{behind}</span>
{/if}
</div>
{/if}
{:else}
<span class="tb-no-repo" data-tauri-drag-region>No repository open</span>