From 79f4ec21e421a064895425193bf858c4a1b91851 Mon Sep 17 00:00:00 2001 From: Christoph Brandau Date: Sun, 23 Aug 2026 23:20:13 +0200 Subject: [PATCH] feat(history): make branch filter groups collapsible Add collapsible local and remote branch groups to the branch visibility dialog, including toggle buttons and selection counts. Introduce comprehensive dialog styling and responsive rules to match the app UI. Opening the dialog now defaults to local open and remote closed for faster access. - Add CSS for branch-filter dialog layout, theming, and responsiveness - Implement group toggles with chevrons and visible selected counts - Default to local group open and remote group closed on dialog open --- src/app.css | 149 +++++++++++++++++++++++++ src/lib/components/HistoryPanel.svelte | 82 ++++++++++---- 2 files changed, 207 insertions(+), 24 deletions(-) diff --git a/src/app.css b/src/app.css index 74a49aa..6e725fd 100644 --- a/src/app.css +++ b/src/app.css @@ -8523,3 +8523,152 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s :root[data-appearance="custom"] .graph-gutter { background: var(--color-surface-dim); } + +/* Branch visibility dialog --------------------------------------------- + Local and remote branches share one visual and interaction language. */ +.branch-filter-backdrop, +:root[data-theme="light"] .branch-filter-backdrop { + padding: 24px; + background: var(--app-dialog-backdrop); + backdrop-filter: blur(5px); +} + +.branch-filter-dialog, +:root[data-theme="light"] .branch-filter-dialog { + width: min(560px, 100%); + max-height: min(680px, calc(100vh - 48px)); + border-color: var(--color-border); + background: var(--app-dialog-bg); + box-shadow: var(--app-dialog-shadow); +} + +.branch-filter-dialog-head { + min-height: 64px; + padding: 12px 14px; + border-bottom-color: var(--color-border); + background: var(--app-dialog-chrome); +} + +.branch-filter-dialog-head h3 { + color: var(--color-ink); + font-size: 15px; +} + +.branch-filter-summary { + min-height: 48px; + padding: 8px 14px; + border-bottom-color: var(--color-border); + color: var(--color-ink-muted); + background: var(--color-surface-dim); +} + +.branch-filter-actions button { + min-height: 28px; + border-color: var(--color-border); + color: var(--color-ink-muted); + background: var(--color-surface-raised); +} + +.branch-filter-actions button:hover:not(:disabled) { + border-color: var(--color-border-input); + color: var(--color-ink); + background: var(--color-surface-hover); +} + +.branch-filter-dialog-list { + gap: 8px; + padding: 10px; + background: var(--color-surface-alt); +} + +.branch-filter-group { + display: grid; + min-width: 0; + overflow: hidden; + border: 1px solid var(--color-border); + background: var(--color-surface); +} + +.branch-filter-group-toggle { + display: grid; + grid-template-columns: 16px minmax(0, 1fr) auto; + align-items: center; + gap: 8px; + width: 100%; + min-height: 36px; + padding: 0 10px; + border: 0; + color: var(--color-ink-muted); + background: var(--color-surface-dim); + text-align: left; +} + +.branch-filter-group-toggle:hover:not(:disabled) { + color: var(--color-ink); + background: var(--color-surface-hover); +} + +.branch-filter-group-toggle > svg { + color: var(--color-accent); +} + +.branch-filter-group-toggle > span { + font-size: 10px; + font-weight: 850; + letter-spacing: 0.09em; + text-transform: uppercase; +} + +.branch-filter-group-toggle > em { + min-width: 34px; + padding: 2px 5px; + border: 1px solid var(--color-border-subtle); + color: var(--color-ink-faint); + background: var(--color-surface-raised); + font-size: 9px; + font-style: normal; + font-weight: 800; + text-align: center; +} + +.branch-filter-group-list { + display: grid; + gap: 4px; + padding: 6px; + border-top: 1px solid var(--color-border-subtle); +} + +.branch-filter-option, +:root[data-theme="light"] .branch-filter-option, +:root[data-theme="light"] .branch-filter-option.remote { + min-height: 34px; + border-color: color-mix(in srgb, var(--color-accent) 32%, var(--color-border)); + color: var(--color-ink); + background: color-mix(in srgb, var(--color-accent) 8%, var(--color-surface-raised)); + opacity: 1; +} + +.branch-filter-option:hover, +:root[data-theme="light"] .branch-filter-option:hover { + border-color: color-mix(in srgb, var(--color-accent) 52%, var(--color-border)); + color: var(--color-ink); + background: color-mix(in srgb, var(--color-accent) 13%, var(--color-surface-hover)); +} + +.branch-filter-option.muted, +:root[data-theme="light"] .branch-filter-option.muted { + border-color: var(--color-border-subtle); + color: var(--color-ink-faint); + background: var(--color-surface-raised); + opacity: 0.72; +} + +.branch-filter-option input { + accent-color: var(--color-accent); +} + +@media (max-width: 560px) { + .branch-filter-backdrop { padding: 8px; } + .branch-filter-summary { align-items: stretch; flex-direction: column; } + .branch-filter-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); } +} diff --git a/src/lib/components/HistoryPanel.svelte b/src/lib/components/HistoryPanel.svelte index c0fe304..c863e5b 100644 --- a/src/lib/components/HistoryPanel.svelte +++ b/src/lib/components/HistoryPanel.svelte @@ -117,6 +117,8 @@ let customVisibleBranches = $state>(new Set()); let loadedVisibilityRepository = $state(""); let branchDialogOpen = $state(false); + let localBranchGroupOpen = $state(true); + let remoteBranchGroupOpen = $state(false); let expandedRefsCommitHash = $state(""); let panelElement = $state(null); let contextCommit = $state(null); @@ -428,6 +430,8 @@ } function openBranchDialog() { + localBranchGroupOpen = true; + remoteBranchGroupOpen = false; branchDialogOpen = true; } @@ -1202,32 +1206,62 @@
{#if localBranchNames.length > 0} - Local - {#each localBranchNames as branch} - - {/each} +
+ + {#if localBranchGroupOpen} +
+ {#each localBranchNames as branch} + + {/each} +
+ {/if} +
{/if} {#if remoteBranchNames.length > 0} - Remote - {#each remoteBranchNames as branch} - - {/each} +
+ + {#if remoteBranchGroupOpen} +
+ {#each remoteBranchNames as branch} + + {/each} +
+ {/if} +
{/if}