From 735acd255133a5afd0b0de38ed0584e17092724c Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Sun, 12 Jul 2026 23:32:55 +0200 Subject: [PATCH] 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. --- src/App.svelte | 21 +- src/app.css | 392 +++++++++++++++++++++- src/lib/RepoToolbar.svelte | 1 - src/lib/TitleBar.svelte | 44 +-- src/lib/components/CommitPanel.svelte | 47 ++- src/lib/components/CompareDialog.svelte | 50 +++ src/lib/components/LinePatchDialog.svelte | 36 +- src/lib/components/StatusPanel.svelte | 149 +++----- 8 files changed, 565 insertions(+), 175 deletions(-) diff --git a/src/App.svelte b/src/App.svelte index 94d1185..494eccd 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,5 +1,6 @@
+
+ +
{/if}
diff --git a/src/lib/components/LinePatchDialog.svelte b/src/lib/components/LinePatchDialog.svelte index c200c4f..7f81838 100644 --- a/src/lib/components/LinePatchDialog.svelte +++ b/src/lib/components/LinePatchDialog.svelte @@ -47,6 +47,7 @@ }: Props = $props(); let parsed = $state({ headerLines: [], hunks: [], binary: false }); + let patchScroll = $state(null); let scopeLabel = $derived(staged ? "Staged changes" : "Unstaged changes"); let displayPath = $derived(file.old_path ? `${file.old_path} -> ${file.path}` : file.path); @@ -118,6 +119,23 @@ if (isBusy || isLoading) return; await onApply(action, buildHunkPatch(hunk)); } + + function hunkPosition(index: number): number { + const totalLines = parsed.hunks.reduce((sum, hunk) => sum + Math.max(hunk.lines.length, 1), 0); + const precedingLines = parsed.hunks.slice(0, index).reduce((sum, hunk) => sum + Math.max(hunk.lines.length, 1), 0); + return (precedingLines / Math.max(totalLines - 1, 1)) * 100; + } + + function hunkKind(hunk: PatchHunk): "add" | "delete" | "mixed" { + const hasAdd = hunk.lines.some((line) => line.kind === "add"); + const hasDelete = hunk.lines.some((line) => line.kind === "delete"); + return hasAdd && hasDelete ? "mixed" : hasAdd ? "add" : "delete"; + } + + function scrollToHunk(hunkId: string) { + const target = patchScroll?.querySelector(`[data-hunk-id="${hunkId}"]`); + if (patchScroll && target) patchScroll.scrollTop = Math.max(target.offsetTop - 8, 0); + } diff --git a/src/lib/components/StatusPanel.svelte b/src/lib/components/StatusPanel.svelte index 2a6027b..df88eb1 100644 --- a/src/lib/components/StatusPanel.svelte +++ b/src/lib/components/StatusPanel.svelte @@ -156,11 +156,11 @@ }); -
+
- Working tree -

Status

+ Workspace +

Changes

{stagedCount} staged @@ -170,26 +170,6 @@ {#if hasRepository && changedFiles.length > 0}
- -
{:else} -
- {#each changedFiles as file (`${file.old_path ?? ""}:${file.path}`)} -
-
- -
+
+
+
+
Unstaged{unstagedCount}
+ +
+
+ {#each changedFiles.filter((file) => file.unstaged !== null) as file (`unstaged:${fileKey(file)}`)} + {@const stageTargets = selectedStageTargets(file)} +
+ + {statusLabel(file.unstaged)} +
+ + + +
+
+ {/each} + {#if unstagedCount === 0}

No unstaged changes.

{/if} +
+
-
-
-
- Staged - {statusLabel(file.staged)} +
+
+
Staged{stagedCount}
+ +
+
+ {#each changedFiles.filter((file) => file.staged !== null) as file (`staged:${fileKey(file)}`)} + {@const unstageTargets = selectedUnstageTargets(file)} +
+ + {statusLabel(file.staged)} +
+ + +
-
- {#if file.staged} - {@const unstageTargets = selectedUnstageTargets(file)} - - - - {:else} - No staged change - {/if} -
-
- -
-
- Unstaged - {statusLabel(file.unstaged)} -
-
- {#if file.unstaged} - {@const stageTargets = selectedStageTargets(file)} - - - - {:else} - No unstaged change - {/if} -
-
-
-
- {/each} + + {/each} + {#if stagedCount === 0}

Stage files to include them in the next commit.

{/if} +
+
{/if}