From 982dbf136d216dd84402bd78e703ab33f5e46af7 Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Sat, 11 Jul 2026 23:11:34 +0200 Subject: [PATCH] feat(toolbar): overhaul repository action bar UI and status display This refactors the entire appearance and structure of the repository toolbar, modernizing its layout and improving visual consistency across different states. The component now dynamically displays remote tracking information (ahead/behind) directly on Pull and Push buttons for immediate user feedback. - Implemented a comprehensive CSS overhaul using grid and flexbox for better responsiveness. - Added support for German localization within the toolbar actions. - Enhanced visibility of sync status by displaying commit counts next to pull/push buttons. --- src/App.svelte | 3 + src/app.css | 179 ++++++++++++++++++++- src/lib/RepoToolbar.svelte | 312 ++++++++++++++++++++++--------------- 3 files changed, 361 insertions(+), 133 deletions(-) diff --git a/src/App.svelte b/src/App.svelte index 7505982..435115a 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -3604,8 +3604,11 @@ hasRepository={workspaceActive} {isBusy} {operation} + ahead={status?.ahead ?? 0} + behind={status?.behind ?? 0} {autoRefreshEnabled} {autoRefreshInFlight} + language={appLanguage} onFetch={fetchRepo} onPull={pullRepo} onPush={pushRepo} diff --git a/src/app.css b/src/app.css index aee954a..a396146 100644 --- a/src/app.css +++ b/src/app.css @@ -541,7 +541,7 @@ .shell { --app-titlebar-height: 42px; - --app-toolbar-height: 34px; + --app-toolbar-height: 58px; display: flex; flex-direction: column; height: 100%; @@ -648,22 +648,179 @@ height: 100%; } - /* Repo action toolbar: its own row under the repo tab bar (hidden in Repository - Management). Its own row means a narrow window can never push the window - controls out of the titlebar; overflow-x is the last-resort safety net. */ + /* Repository actions are ordered by workflow: sync, inspect/history, utilities. */ .repo-toolbar { display: flex; - align-items: stretch; + align-items: flex-end; + gap: 8px; height: var(--app-toolbar-height); + padding: 5px 8px; border: 1px solid var(--color-border-subtle); border-radius: 10px; background: rgba(16, 17, 29, 0.9); flex-shrink: 0; - overflow-x: auto; - scrollbar-width: none; + overflow: visible; user-select: none; } - .repo-toolbar::-webkit-scrollbar { display: none; } + + .repo-toolbar-sync { + display: grid; + grid-template-rows: 11px 34px; + gap: 2px; + align-self: stretch; + min-width: 0; + } + .repo-toolbar-group-label { + padding-left: 6px; + color: var(--color-ink-faint); + font-size: 8px; + font-weight: 850; + line-height: 11px; + letter-spacing: 0.12em; + text-transform: uppercase; + } + .repo-action-group { + display: flex; + align-items: stretch; + height: 34px; + min-width: 0; + border: 1px solid var(--color-border-subtle); + border-radius: 7px; + background: rgba(255,255,255,0.018); + } + .repo-action-group > .repo-action, + .repo-action-group > .repo-history-wrap > .repo-action { + border-right: 1px solid var(--color-border-subtle); + } + .repo-action-group > .repo-action:last-child, + .repo-action-group > .repo-history-wrap:last-child > .repo-action { + border-right: 0; + } + .repo-action { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 6px; + min-width: 38px; + height: 32px; + min-height: 32px; + padding: 0 12px; + border: 0; + border-radius: 0; + color: var(--color-ink-muted); + background: transparent; + font-size: 12px; + font-weight: 700; + white-space: nowrap; + cursor: pointer; + transition: color 120ms ease, background 120ms ease; + -webkit-app-region: no-drag; + } + .repo-action:first-child { border-radius: 6px 0 0 6px; } + .repo-action:last-child { border-radius: 0 6px 6px 0; } + .repo-action:only-child { border-radius: 6px; } + .repo-action:hover:not(:disabled), + .repo-action.active { + color: var(--color-ink); + background: var(--color-surface-hover); + } + .repo-action:disabled { opacity: 0.34; cursor: not-allowed; } + .repo-action.sync-primary { color: var(--color-accent); } + .repo-action.sync-primary:hover:not(:disabled) { background: rgba(90,140,248,0.1); } + .repo-action-label { font-size: 12px; font-weight: 750; } + .repo-action-count { + color: currentColor; + font-family: var(--font-mono); + font-size: 9.5px; + font-weight: 850; + } + .repo-action-count.behind { color: #7aacff; } + .repo-action-count.ahead { color: #e0a040; } + .repo-toolbar-divider { + width: 1px; + height: 30px; + margin: 0 1px 2px; + background: var(--color-border-subtle); + flex: 0 0 auto; + } + .repo-toolbar-spacer { flex: 1 1 auto; min-width: 6px; } + .repo-inspect-actions, + .repo-utility-actions { margin-bottom: 1px; } + .repo-history-wrap { position: relative; height: 32px; } + .history-trigger { border-radius: 0 6px 6px 0; } + .history-trigger .history-chevron { transition: transform 120ms ease; } + .history-trigger.active .history-chevron { transform: rotate(180deg); } + .repo-history-menu { + position: absolute; + z-index: 90; + top: calc(100% + 7px); + right: -1px; + display: grid; + width: 240px; + padding: 5px; + border: 1px solid var(--color-border); + border-radius: 9px; + background: var(--color-surface-raised); + box-shadow: 0 16px 42px rgba(0,0,0,0.36); + } + .repo-history-menu > button { + display: grid; + grid-template-columns: 24px minmax(0, 1fr); + align-items: center; + gap: 8px; + min-height: 48px; + padding: 7px 8px; + border: 0; + border-radius: 6px; + color: var(--color-ink-muted); + background: transparent; + text-align: left; + } + .repo-history-menu > button:hover { color: var(--color-ink); background: var(--color-surface-hover); } + .repo-history-menu > button > svg { color: var(--color-accent); } + .repo-history-menu > button > span { display: grid; gap: 2px; min-width: 0; } + .repo-history-menu strong { color: inherit; font-size: 11px; } + .repo-history-menu small { overflow: hidden; color: var(--color-ink-faint); font-size: 9.5px; text-overflow: ellipsis; white-space: nowrap; } + .repo-utility-actions { flex: 0 0 auto; } + .repo-action.icon-action { width: 36px; padding: 0; } + .repo-auto-toggle { + display: inline-flex; + align-items: center; + gap: 8px; + height: 32px; + min-height: 32px; + padding: 0 8px 0 10px; + border: 0; + border-radius: 0 6px 6px 0; + color: var(--color-ink-muted); + background: transparent; + font-size: 11.5px; + font-weight: 750; + } + .repo-auto-toggle:hover { color: var(--color-ink); background: var(--color-surface-hover); } + .repo-switch { + position: relative; + width: 27px; + height: 15px; + border-radius: 999px; + background: var(--color-border-input); + transition: background 140ms ease; + } + .repo-switch > span { + position: absolute; + top: 2px; + left: 2px; + width: 11px; + height: 11px; + border-radius: 50%; + background: #ffffff; + box-shadow: 0 1px 3px rgba(0,0,0,0.28); + transition: transform 140ms ease; + } + .repo-auto-toggle.active { color: #4eca76; } + .repo-auto-toggle.active .repo-switch { background: #26924f; } + .repo-auto-toggle.active .repo-switch > span { transform: translateX(12px); } + .repo-switch.busy { box-shadow: 0 0 0 3px rgba(78,202,118,0.12); } .tb-action { display: flex; @@ -5220,6 +5377,7 @@ .branch-actions { flex-direction: column; align-items: flex-end; gap: 4px; } .branch-actions button { width: 100%; } .tb-action-label { display: none; } + .repo-action-label.utility-label { display: none; } } /* Narrow: single column */ @@ -5293,4 +5451,9 @@ .dialog-files { border-right: none; border-bottom: 1px solid var(--color-border-subtle); } .branch-actions { flex-direction: row; justify-content: flex-start; } .tb-action-label { display: none; } + .repo-action-label { display: none; } + .repo-action { padding-inline: 8px; } + .repo-toolbar { gap: 5px; padding-inline: 6px; } + .repo-toolbar-divider { margin-inline: 0; } + .repo-auto-toggle { padding-left: 7px; gap: 6px; } } diff --git a/src/lib/RepoToolbar.svelte b/src/lib/RepoToolbar.svelte index 0b68148..e7062b4 100644 --- a/src/lib/RepoToolbar.svelte +++ b/src/lib/RepoToolbar.svelte @@ -1,11 +1,26 @@ -