From 7bea2f35efbb098a7a3c139d71526ad227a72772 Mon Sep 17 00:00:00 2001 From: Silke pilon Date: Sat, 21 Jun 2025 20:10:49 +0200 Subject: [PATCH 01/26] feat(windows): add custom Windows title bar and hide default - Introduce a new WindowsTitleBar component for a native-like title bar experience on Windows platform. - Conditionally render WindowsTitleBar in the main layout when running on Windows. - Modify window creation logic to disable default window decorations (title bar) on Windows, enabling the custom title bar to be used. - Keep default decorations on other platforms to preserve native look. - Improve app branding by showing version and build type badges in the custom title bar. - Enhance user experience with zoom controls and window management integrated into the custom title bar. This change improves UI consistency and usability for Windows users by providing a tailored window chrome that matches platform conventions. --- .../src/components/WindowsTitleBar.svelte | 411 ++++++++++++++++++ apps/desktop/src/routes/+layout.svelte | 7 + crates/gitbutler-tauri/src/window.rs | 17 + 3 files changed, 435 insertions(+) create mode 100644 apps/desktop/src/components/WindowsTitleBar.svelte diff --git a/apps/desktop/src/components/WindowsTitleBar.svelte b/apps/desktop/src/components/WindowsTitleBar.svelte new file mode 100644 index 0000000000..a9eda5066a --- /dev/null +++ b/apps/desktop/src/components/WindowsTitleBar.svelte @@ -0,0 +1,411 @@ + + +{#if showTitleBar} +
+ +
+
+ {#if appIcon} + GitButler + {/if} +
+
+ GitButler + + {getBadgeText()} + +
+
+ + +
+ + + File + {#snippet contextMenuSlot()} + + + + + + { + goto(newSettingsPath()); + }} + /> + + {/snippet} + + + + + View + {#snippet contextMenuSlot()} + + + + + + + + + + {#if import.meta.env.DEV} + + + { + location.reload(); + }} + /> + + {/if} + {/snippet} + + + {#if project} + + + Project + {#snippet contextMenuSlot()} + + + { + const path = getEditorUri({ + schemeId: $userSettings.defaultCodeEditor.schemeIdentifer, + path: [project.vscodePath], + searchParams: { windowId: '_blank' } + }); + openExternalUrl(path); + }} + /> + + + { + goto(projectSettingsPath(project.id)); + }} + /> + + {/snippet} + + {/if} + + + + Help + {#snippet contextMenuSlot()} + + { + openExternalUrl('https://docs.gitbutler.com'); + }} + /> + + + + + + + {}} /> + + {/snippet} + +
+ + +
+
+{/if} + + diff --git a/apps/desktop/src/routes/+layout.svelte b/apps/desktop/src/routes/+layout.svelte index 33415af80e..0012d63783 100644 --- a/apps/desktop/src/routes/+layout.svelte +++ b/apps/desktop/src/routes/+layout.svelte @@ -86,6 +86,7 @@ import { Toaster } from 'svelte-french-toast'; import type { LayoutData } from './$types'; import { env } from '$env/dynamic/public'; + import WindowsTitleBar from '$components/WindowsTitleBar.svelte'; const { data, children }: { data: LayoutData; children: Snippet } = $props(); @@ -301,6 +302,12 @@ {#if platformName === 'macos' && !$settingsStore?.featureFlags.v3}
{/if} + + + {#if platformName === 'windows'} + + {/if} + {@render children()} diff --git a/crates/gitbutler-tauri/src/window.rs b/crates/gitbutler-tauri/src/window.rs index af2a9783d8..745c1c6add 100644 --- a/crates/gitbutler-tauri/src/window.rs +++ b/crates/gitbutler-tauri/src/window.rs @@ -255,6 +255,8 @@ pub fn create( window_relative_url: String, ) -> tauri::Result { tracing::info!("creating window '{label}' created at '{window_relative_url}'"); + + #[cfg(target_os = "windows")] let window = tauri::WebviewWindowBuilder::new( handle, label, @@ -265,7 +267,22 @@ pub fn create( .disable_drag_drop_handler() .min_inner_size(1000.0, 600.0) .inner_size(1160.0, 720.0) + .decorations(false) // Hide default title bar on Windows .build()?; + + #[cfg(not(any(target_os = "windows", target_os = "macos")))] + let window = tauri::WebviewWindowBuilder::new( + handle, + label, + tauri::WebviewUrl::App(window_relative_url.into()), + ) + .resizable(true) + .title(handle.package_info().name.clone()) + .disable_drag_drop_handler() + .min_inner_size(1000.0, 600.0) + .inner_size(1160.0, 720.0) + .build()?; + Ok(window) } From 188f5dd6548214fef6ed6e00d7db1d26bf47cd0b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 23 Jun 2025 16:40:49 +0200 Subject: [PATCH 02/26] Apply `cargo fmt` and auto-fix node lints --- .../src/components/WindowsTitleBar.svelte | 20 +++++++++---------- apps/desktop/src/routes/+layout.svelte | 2 +- crates/gitbutler-tauri/src/window.rs | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/desktop/src/components/WindowsTitleBar.svelte b/apps/desktop/src/components/WindowsTitleBar.svelte index a9eda5066a..4f61ef0a2f 100644 --- a/apps/desktop/src/components/WindowsTitleBar.svelte +++ b/apps/desktop/src/components/WindowsTitleBar.svelte @@ -1,23 +1,23 @@ + +{#if showTitleBar} +
+ +
+
+ {#if appIcon} + GitButler + {/if} +
+
+ GitButler + + {getBadgeText()} + +
+
+ + +
+ + + File + {#snippet contextMenuSlot()} + + + + + + { + goto(newSettingsPath()); + }} + /> + + {/snippet} + + + + + View + {#snippet contextMenuSlot()} + + + + + + + + + + {#if import.meta.env.DEV} + + + { + location.reload(); + }} + /> + + {/if} + {/snippet} + + + {#if project} + + + Project + {#snippet contextMenuSlot()} + + + { + const path = getEditorUri({ + schemeId: $userSettings.defaultCodeEditor.schemeIdentifer, + path: [project.vscodePath], + searchParams: { windowId: '_blank' } + }); + openExternalUrl(path); + }} + /> + + + { + goto(projectSettingsPath(project.id)); + }} + /> + + {/snippet} + + {/if} + + + + Help + {#snippet contextMenuSlot()} + + { + openExternalUrl('https://docs.gitbutler.com'); + }} + /> + + + + + + + {}} /> + + {/snippet} + +
+ + +
+ + +
+ + + +
+
+{/if} + + diff --git a/apps/desktop/src/lib/backend/tauri.ts b/apps/desktop/src/lib/backend/tauri.ts index df857c60c2..7eb289e6cc 100644 --- a/apps/desktop/src/lib/backend/tauri.ts +++ b/apps/desktop/src/lib/backend/tauri.ts @@ -1,10 +1,32 @@ import { invoke as invokeIpc, listen as listenIpc } from '$lib/backend/ipc'; import { getVersion } from '@tauri-apps/api/app'; import { check } from '@tauri-apps/plugin-updater'; +import { getCurrentWindow } from '@tauri-apps/api/window'; export class Tauri { invoke = invokeIpc; listen = listenIpc; checkUpdate = check; currentVersion = getVersion; + + // Window control methods + async minimize() { + const window = getCurrentWindow(); + await window.minimize(); + } + + async toggleMaximize() { + const window = getCurrentWindow(); + const isMaximized = await window.isMaximized(); + if (isMaximized) { + await window.unmaximize(); + } else { + await window.maximize(); + } + } + + async close() { + const window = getCurrentWindow(); + await window.close(); + } } diff --git a/apps/desktop/src/routes/+layout.svelte b/apps/desktop/src/routes/+layout.svelte index 33415af80e..bf6b36da9d 100644 --- a/apps/desktop/src/routes/+layout.svelte +++ b/apps/desktop/src/routes/+layout.svelte @@ -20,6 +20,7 @@ import { AIService } from '$lib/ai/service'; import { PostHogWrapper } from '$lib/analytics/posthog'; import { CommandService, invoke } from '$lib/backend/ipc'; + import { Tauri } from '$lib/backend/tauri'; import BaseBranchService from '$lib/baseBranch/baseBranchService.svelte'; import { BranchService } from '$lib/branches/branchService.svelte'; import { @@ -98,6 +99,7 @@ const gitLabClient = new GitLabClient(); setContext(GitHubClient, gitHubClient); setContext(GitLabClient, gitLabClient); + setContext(Tauri, data.tauri); const user = data.userService.user; const accessToken = $derived($user?.github_access_token); $effect(() => gitHubClient.setToken(accessToken)); diff --git a/apps/desktop/src/routes/[projectId]/+layout.svelte b/apps/desktop/src/routes/[projectId]/+layout.svelte index dd725eb90b..b03a70cb4f 100644 --- a/apps/desktop/src/routes/[projectId]/+layout.svelte +++ b/apps/desktop/src/routes/[projectId]/+layout.svelte @@ -126,11 +126,22 @@ setContext(StackingReorderDropzoneManagerFactory, stackingReorderDropzoneManagerFactory); }); + const focusManager = new FocusManager(); + setContext(FocusManager, focusManager); + + // Set the Project context immediately so child components can access it + // Even if project is undefined, we set the context to prevent "no instance" errors + setContext(Project, data.project); + + // Debug logging to help diagnose the issue + if (!data.project) { + console.warn('Project is undefined in [projectId] layout, projectId:', data.projectId); + } + $effect.pre(() => { setContext(HistoryService, data.historyService); setContext(TemplateService, data.templateService); setContext(BaseBranch, baseBranch); - setContext(Project, project); setContext(GitBranchService, data.gitBranchService); setContext(UncommitedFilesWatcher, data.uncommitedFileWatcher); setContext(ProjectService, data.projectService); @@ -141,9 +152,6 @@ setContext(StackPublishingService, data.stackPublishingService); }); - const focusManager = new FocusManager(); - setContext(FocusManager, focusManager); - let intervalId: any; const forgeFactory = getContext(DefaultForgeFactory); diff --git a/apps/desktop/static/icons/32x32.png b/apps/desktop/static/icons/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..2a42f60ad80d22f9796223158256d50bcdb41188 GIT binary patch literal 1327 zcmV+~1YF7)YZ#GdxQSVku0)rVY1EJ<;K0VySU6pPbxW^q=a)r!TyS z=-eC%%94&`s|ZHOJq2PoCTDoI|5TU4a&T2SJ3U2g8!5C+aDpXt^1wk1_Vl9j_Txx1!gBE5RF7siP;4NAsliG3o$)5hEI;XiZ9xZ;P1g9Toc@cecQT{*>h}U zXha&4WvQYOZ`D$27wNPE-LJQ! zuj4Z~4NqFS!b<6+8tjg#U#yWhPD>#vpz-s6;^h8kaA;ElJ~(hl92iGlQ4zxDenHRi zchL9I$FSliD(Y%g+TB=LtHT?iZDQ$~a%6IJ6dxWujKjeOoOtwcga-z2+3FIkuC7*G z3FPI$2n4*9=aMSRv>nlGN5X%hOYZu$hjwFZ_;=)$6w9^w;TPkE%wC3p|9LFQ0bYTo z+odQ^LFp9;?%0mn<{J@{st6DK3VGwH3W>?QVh%VdU+8RNxU3A#t&gDT;T9B?mt&;w zCk%Y`wUphU@FR@K%#3pAUpZiRFE!%qf-;IK%G1hlMk=9n-C7h?R-&k?N|oXHP(R$d z<6^IJV^JG&sTnpI5fy4F8X>I_O-Q8N!zVT$71rlq!yUI{ZPR9a_r}pgBVyLL$JNG@ zcG5B+{l{rU?Av!fyB{MzhtRNVr=U5`%sSFOTL zdmmF=h)hqz!KIC4Ted92j)1Dwq=w@=fbR{F6p%IMB&tgpPGPLtOGl=dEy3esnwG_x zHrzJ#h4RwXOaZCx%XU#|IvUoNp~!4UG(Dm0En?G#+otYp=Ae3|fOM?6fGl%493YHhJFi=! l&h&w*Ed_094D?2te*mi^+1X)CR)zoo002ovPDHLkV1nYPj?@4E literal 0 HcmV?d00001 diff --git a/apps/desktop/static/icons/dev/32x32.png b/apps/desktop/static/icons/dev/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..4285bbd7fc6197888d0f1d7126dec9e41222e3e0 GIT binary patch literal 1205 zcmV;m1WNmfP)O)1W zpsy2S(U(St!=t%C{?gm`%+42ODW6JT6?rAU!J-XL)UxbTot*>6TAn@L+K^~XL?ela))8<-!Vz$@uA5!UWY-oRtSww#Tpapp zYWnMpAPJYq^5yL)1CaD-E!WKL+tVk1`0?b;)zt+v z63Wjxi-tX)=zshAp{8e&>Gf2a*(zQ&3eXfHFZMWAACJu}-fM<^Fi$L5}Rb3b!B1- z0atzi3ywGCqfY-xn{xE*?JWFq)-3>uO?nm#1JjRyJh0kXaFQRo>u3aaJkEzh6Y+uh z44>7Jhxab|2BgT1|Yx4R2<4Glm#jhy4Kkc7B+NdLA7XmfKD=l}Q< zXUE4uC5M-rn(%9XTX~E?BT_KSjXaI${N6b-GPaB4EX0 zm|a=Hg&Q;Yer^uj;<_6f5syT+*{Zbcs){OTg7ZtYE!T1?g-=F)!RHj_{=-R}Xm7** zx;ju7rPR3icVh!o`$%Q8RYj|7DJ{P&nFL4VpVS7J=mZ`4G+<5#5N|T4*4jPht%EqFj=Axlc|S) zm;@tHPE?i7lpzrM(@a%Ru;RI$h3m>&xRg-13@AwetB58ir`#8FXmLHN&-4EPl}VgE Tir@3g00000NkvXXu0mjf!v#(v literal 0 HcmV?d00001 diff --git a/apps/desktop/static/icons/nightly/32x32.png b/apps/desktop/static/icons/nightly/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..6ba8af81e07e001b5016d6ed8e6aca2590396e2d GIT binary patch literal 1052 zcmV+%1mpXOP)6kLfv{Gi4UC@w_>7lJEM6b=4A zxYe}^qLOID4=NZ@RM3cuK_e!Hbh`Upt8U->a{Hw_{jos{iU*xn=bWlrRrke3;pU(? zlZCt#8HLOx7sY^OF`+p`E(|9}kpC5xka+}UV7pl=lG48~CvPF2NFF2iG(aH&m?S~o zN8U|-nfxSq(&8AAjZw#h7swk?UVB77R|^U%;aEbX&isKUk88CKif=%>8d7H*)gu1U zl~A0*Dm`@B4S7@xGEG#9M>IxMV>W7zfK!ANw}b?h(;^`b*aA#vPPBW&5dy-c1e_91 zfMPh7F>FkW!_Oul7K9Uk^nLhAIxZ;-7ov$dhGQASNyj-MjzEBo>Y2&z@OHe4D>rk7bNk;JFZAMs;-Jr*B2fNi%sF>^yJDypiG z(n2_EesacB=FG;*Q^&Dj_b${n)T>y=urU!DYmxmNgX2WR^N<)EM1M~Y#{V`6i}vrs z_B)-JwP_=wW5=qjnQYp!C1{#I4}#u*`}he4KlQ2Dj7^ip+(LEda9yG6O#ocq~@wB}IpL=`p{>4l6URBLFBojjg^{gmrvP8PWlS4!3d-o3Ge*Fb= zwrs}Iwu7jttHZ!YE_njUcw9XTF&E{wB3DLH0;Dg=snf@dL1iqa&N_Vr*Xg%P{M67u z)8WCTNl@os9s!Q(avneK{%CbI5kJP2w!>&Yb`tUae$|A3w=`q??~@R#twjY1Ma7gQxdy;cD9vTt9V2jU*c{A|63@o)T`%hZis5$<=FWB%9Z_;*X~P z6o!qN!GqzYV19T=KAG00Pdi-j8m*h$h|V)-6@ki_h$WHAEcNATuppHg9l_M4i}AXv z3(s%dgu$dgb&*dQzBw}O9{In#RVgcBlL(!0-ho5Fj*Jp0UX zmB*gasr(Yo!H;j5IrBr`%rw06LuIK!LpvVNveeoKWo zf+hsM;YaCr^I2}}oBm@Gu0+m3D?mUl8-eYNLSjCn{XBw@hfr8eD2vUe)OYh$BCs!B WgPjZ0qTp`;0000 Date: Mon, 23 Jun 2025 23:54:29 +0200 Subject: [PATCH 04/26] feat(windows-title-bar): add keyboard shortcuts and reactive project - Replace static project context with reactive project state updated on route changes to reflect the active project dynamically. - Import and integrate KeyboardShortcutsModal component to display shortcuts UI. - Register global keyboard shortcuts for common actions (add repo, clone, settings, theme switch, zoom, reload, share debug) via ShortcutService. - Enhance File menu with keyboard shortcut hints and auto-close behavior on selection. - Remove unused toggleSidebar function and related event emission. - Improve user experience by enabling quick access to features through shortcuts and keeping project context in sync with navigation. --- .../src/components/WindowsTitleBar.svelte | 257 +++++++++++++----- 1 file changed, 183 insertions(+), 74 deletions(-) diff --git a/apps/desktop/src/components/WindowsTitleBar.svelte b/apps/desktop/src/components/WindowsTitleBar.svelte index 58365cb9f5..6786d6e25a 100644 --- a/apps/desktop/src/components/WindowsTitleBar.svelte +++ b/apps/desktop/src/components/WindowsTitleBar.svelte @@ -2,12 +2,13 @@ import { platformName } from '$lib/platform/platform'; import { Tauri } from '$lib/backend/tauri'; import { getContext } from '@gitbutler/shared/context'; - import { maybeGetContext } from '@gitbutler/shared/context'; - import DropDownButton from '$components/DropDownButton.svelte'; + import DropDownButton from '@gitbutler/ui/DropDownButton.svelte'; import ContextMenuSection from '@gitbutler/ui/ContextMenuSection.svelte'; import ContextMenuItem from '@gitbutler/ui/ContextMenuItem.svelte'; import Badge from '@gitbutler/ui/Badge.svelte'; + import KeyboardShortcutsModal from '$components/KeyboardShortcutsModal.svelte'; import { goto } from '$app/navigation'; + import { page } from '$app/stores'; import { settingsPath, newSettingsPath, clonePath } from '$lib/routes/routes.svelte'; import { openExternalUrl } from '$lib/utils/url'; import { getEditorUri } from '$lib/utils/url'; @@ -18,15 +19,39 @@ import { ProjectsService } from '$lib/project/projectsService'; import { ShortcutService } from '$lib/shortcuts/shortcutService.svelte'; import * as events from '$lib/utils/events'; + import { shortcuts } from '$lib/utils/hotkeys'; import { showHistoryView } from '$lib/config/config'; import type { Writable } from 'svelte/store'; const tauri = getContext(Tauri); const userSettings = getContextStoreBySymbol>(SETTINGS); - const project = maybeGetContext(Project); // Use maybeGetContext for optional project context const projectsService = getContext(ProjectsService); const shortcutService = getContext(ShortcutService); + // Get the current active project reactively + let project = $state(undefined); + + // Update project when page route changes + $effect(() => { + // Watch the current page URL to trigger updates when navigating between projects + $page.url.pathname; + + const updateProject = async () => { + try { + const activeProject = await projectsService.getActiveProject(); + project = activeProject; + } catch (error) { + // No active project or error getting it + project = undefined; + } + }; + + updateProject(); + }); + + // Modal references + let keyboardShortcutsModal = $state(); + // App version and build type information let appVersion = $state(''); let buildType = $state<'stable' | 'nightly' | 'dev'>('stable'); @@ -122,12 +147,6 @@ goto(clonePath()); } - // Toggle sidebar functionality - function toggleSidebar() { - // Emit the toggle-sidebar event - events.emit('toggle-sidebar'); - } - // Switch theme functionality function switchTheme() { userSettings.update((s) => ({ @@ -156,10 +175,24 @@ // Keyboard shortcuts function openKeyboardShortcuts() { - // Implementation for keyboard shortcuts modal - console.log('Opening keyboard shortcuts...'); + keyboardShortcutsModal?.show(); } + // Register keyboard shortcuts + shortcutService.on('add-local-repo', addLocalRepository); + shortcutService.on('clone-repo', cloneRepository); + shortcutService.on('global-settings', () => goto(newSettingsPath())); + shortcutService.on('switch-theme', switchTheme); + shortcutService.on('zoom-in', zoomIn); + shortcutService.on('zoom-out', zoomOut); + shortcutService.on('zoom-reset', resetZoom); + shortcutService.on('reload', () => location.reload()); + shortcutService.on('keyboard-shortcuts', openKeyboardShortcuts); + shortcutService.on('share-debug', shareDebugInfo); + + // Note: Project-specific shortcuts ('history', 'project-settings', 'open-in-vscode') + // are handled by ProjectSettingsMenuAction.svelte to avoid conflicts + // Only show on Windows const showTitleBar = $derived(platformName === 'windows'); @@ -184,56 +217,81 @@
- + File {#snippet contextMenuSlot()} - + { goto(newSettingsPath()); }} /> + { + try { + await tauri.checkUpdate(); + } catch (error) { + console.error('Failed to check for updates:', error); + } + }} + /> {/snippet} - + View {#snippet contextMenuSlot()} - - - - + + + {#if import.meta.env.DEV} { location.reload(); }} @@ -243,43 +301,48 @@ {/snippet} - {#if project} - - - Project - {#snippet contextMenuSlot()} - - - { + + + Project + {#snippet contextMenuSlot()} + + + { + if (project) { const path = getEditorUri({ schemeId: $userSettings.defaultCodeEditor.schemeIdentifer, path: [project.vscodePath], searchParams: { windowId: '_blank' } }); openExternalUrl(path); - }} - /> - - - { + } + }} + /> + + + { + if (project) { goto(projectSettingsPath(project.id)); - }} - /> - - {/snippet} - - {/if} + } + }} + /> + + {/snippet} + - + Help {#snippet contextMenuSlot()} @@ -289,10 +352,53 @@ openExternalUrl('https://docs.gitbutler.com'); }} /> + { + openExternalUrl('https://github.com/gitbutlerapp/gitbutler'); + }} + /> + { + openExternalUrl('https://github.com/gitbutlerapp/gitbutler/releases'); + }} + /> + + + { + openExternalUrl('https://github.com/gitbutlerapp/gitbutler/issues/new/choose'); + }} + /> + + + { + openExternalUrl('https://discord.com/invite/MmFkmaJ42D'); + }} + /> + { + openExternalUrl('https://www.youtube.com/@gitbutlerapp'); + }} + /> + { + openExternalUrl('https://x.com/gitbutler'); + }} + /> {}} /> @@ -340,6 +446,8 @@
{/if} + + diff --git a/apps/desktop/src/components/v3/projectSettings/AppearanceSettings.svelte b/apps/desktop/src/components/v3/projectSettings/AppearanceSettings.svelte index 39907f3c36..0452c2135e 100644 --- a/apps/desktop/src/components/v3/projectSettings/AppearanceSettings.svelte +++ b/apps/desktop/src/components/v3/projectSettings/AppearanceSettings.svelte @@ -17,6 +17,7 @@ import Toggle from '@gitbutler/ui/Toggle.svelte'; import Select from '@gitbutler/ui/select/Select.svelte'; import SelectItem from '@gitbutler/ui/select/SelectItem.svelte'; + import { slide } from 'svelte/transition'; import type { Writable } from 'svelte/store'; const tauri = getContext(Tauri); diff --git a/apps/desktop/static/icons/128x128.png b/apps/desktop/static/icons/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..2a6955a943fe8f03ef11279c08eb254851b35180 GIT binary patch literal 6206 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 literal 0 HcmV?d00001 diff --git a/apps/desktop/static/icons/32x32.png b/apps/desktop/static/icons/32x32.png deleted file mode 100644 index 2a42f60ad80d22f9796223158256d50bcdb41188..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1327 zcmV+~1YF7)YZ#GdxQSVku0)rVY1EJ<;K0VySU6pPbxW^q=a)r!TyS z=-eC%%94&`s|ZHOJq2PoCTDoI|5TU4a&T2SJ3U2g8!5C+aDpXt^1wk1_Vl9j_Txx1!gBE5RF7siP;4NAsliG3o$)5hEI;XiZ9xZ;P1g9Toc@cecQT{*>h}U zXha&4WvQYOZ`D$27wNPE-LJQ! zuj4Z~4NqFS!b<6+8tjg#U#yWhPD>#vpz-s6;^h8kaA;ElJ~(hl92iGlQ4zxDenHRi zchL9I$FSliD(Y%g+TB=LtHT?iZDQ$~a%6IJ6dxWujKjeOoOtwcga-z2+3FIkuC7*G z3FPI$2n4*9=aMSRv>nlGN5X%hOYZu$hjwFZ_;=)$6w9^w;TPkE%wC3p|9LFQ0bYTo z+odQ^LFp9;?%0mn<{J@{st6DK3VGwH3W>?QVh%VdU+8RNxU3A#t&gDT;T9B?mt&;w zCk%Y`wUphU@FR@K%#3pAUpZiRFE!%qf-;IK%G1hlMk=9n-C7h?R-&k?N|oXHP(R$d z<6^IJV^JG&sTnpI5fy4F8X>I_O-Q8N!zVT$71rlq!yUI{ZPR9a_r}pgBVyLL$JNG@ zcG5B+{l{rU?Av!fyB{MzhtRNVr=U5`%sSFOTL zdmmF=h)hqz!KIC4Ted92j)1Dwq=w@=fbR{F6p%IMB&tgpPGPLtOGl=dEy3esnwG_x zHrzJ#h4RwXOaZCx%XU#|IvUoNp~!4UG(Dm0En?G#+otYp=Ae3|fOM?6fGl%493YHhJFi=! l&h&w*Ed_094D?2te*mi^+1X)CR)zoo002ovPDHLkV1nYPj?@4E diff --git a/apps/desktop/static/icons/dev/128x128.png b/apps/desktop/static/icons/dev/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..958d0c65d79f478ee235e0551ebf665b56552ff1 GIT binary patch literal 5893 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 Tir@3g00000NkvXXu0mjf!v#(v diff --git a/apps/desktop/static/icons/nightly/128x128.png b/apps/desktop/static/icons/nightly/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..266e75898f2d9eb3d4a052ee1d4440d25cd7dd64 GIT binary patch literal 5012 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 eC;=$+68r6kLfv{Gi4UC@w_>7lJEM6b=4A zxYe}^qLOID4=NZ@RM3cuK_e!Hbh`Upt8U->a{Hw_{jos{iU*xn=bWlrRrke3;pU(? zlZCt#8HLOx7sY^OF`+p`E(|9}kpC5xka+}UV7pl=lG48~CvPF2NFF2iG(aH&m?S~o zN8U|-nfxSq(&8AAjZw#h7swk?UVB77R|^U%;aEbX&isKUk88CKif=%>8d7H*)gu1U zl~A0*Dm`@B4S7@xGEG#9M>IxMV>W7zfK!ANw}b?h(;^`b*aA#vPPBW&5dy-c1e_91 zfMPh7F>FkW!_Oul7K9Uk^nLhAIxZ;-7ov$dhGQASNyj-MjzEBo>Y2&z@OHe4D>rk7bNk;JFZAMs;-Jr*B2fNi%sF>^yJDypiG z(n2_EesacB=FG;*Q^&Dj_b${n)T>y=urU!DYmxmNgX2WR^N<)EM1M~Y#{V`6i}vrs z_B)-JwP_=wW5=qjnQYp!C1{#I4}#u*`}he4KlQ2Dj7^ip+(LEda9yG6O#ocq~@wB}IpL=`p{>4l6URBLFBojjg^{gmrvP8PWlS4!3d-o3Ge*Fb= zwrs}Iwu7jttHZ!YE_njUcw9XTF&E{wB3DLH0;Dg=snf@dL1iqa&N_Vr*Xg%P{M67u z)8WCTNl@os9s!Q(avneK{%CbI5kJP2w!>&Yb`tUae$|A3w=`q??~@R#twjY1Ma7gQxdy;cD9vTt9V2jU*c{A|63@o)T`%hZis5$<=FWB%9Z_;*X~P z6o!qN!GqzYV19T=KAG00Pdi-j8m*h$h|V)-6@ki_h$WHAEcNATuppHg9l_M4i}AXv z3(s%dgu$dgb&*dQzBw}O9{In#RVgcBlL(!0-ho5Fj*Jp0UX zmB*gasr(Yo!H;j5IrBr`%rw06LuIK!LpvVNveeoKWo zf+hsM;YaCr^I2}}oBm@Gu0+m3D?mUl8-eYNLSjCn{XBw@hfr8eD2vUe)OYh$BCs!B WgPjZ0qTp`;0000 void; + borderRadius?: string; } const { @@ -24,7 +25,8 @@ reversedDirection, tooltip, children, - onclick + onclick, + borderRadius = '20px' }: Props = $props(); @@ -32,7 +34,12 @@ -
+
{#if children} Date: Tue, 24 Jun 2025 19:21:49 +0200 Subject: [PATCH 11/26] feat(windows): always use custom title bar and remove toggle Always show the custom title bar on Windows by default, removing the user setting and toggle to enable or disable it. Update window decorations initialization to always hide the default title bar on Windows. This simplifies the UI and ensures a consistent appearance across Windows installations. --- .../src/components/WindowsTitleBar.svelte | 4 +-- .../projectSettings/AppearanceSettings.svelte | 28 ------------------- apps/desktop/src/lib/settings/userSettings.ts | 4 +-- apps/desktop/src/routes/+layout.svelte | 9 +++--- 4 files changed, 7 insertions(+), 38 deletions(-) diff --git a/apps/desktop/src/components/WindowsTitleBar.svelte b/apps/desktop/src/components/WindowsTitleBar.svelte index 8ea0c09df1..1f7c31bd36 100644 --- a/apps/desktop/src/components/WindowsTitleBar.svelte +++ b/apps/desktop/src/components/WindowsTitleBar.svelte @@ -215,8 +215,8 @@ // Note: Project-specific shortcuts ('history', 'project-settings', 'open-in-vscode') // are handled by ProjectSettingsMenuAction.svelte to avoid conflicts - // Only show on Windows and when custom title bar is enabled - const showTitleBar = $derived(platformName === 'windows' && $userSettings.useCustomTitleBar); + // Always show custom title bar on Windows + const showTitleBar = $derived(platformName === 'windows'); {#snippet editorBadgeSnippet()} diff --git a/apps/desktop/src/components/v3/projectSettings/AppearanceSettings.svelte b/apps/desktop/src/components/v3/projectSettings/AppearanceSettings.svelte index 0452c2135e..c986513e1f 100644 --- a/apps/desktop/src/components/v3/projectSettings/AppearanceSettings.svelte +++ b/apps/desktop/src/components/v3/projectSettings/AppearanceSettings.svelte @@ -292,31 +292,3 @@ /> {/snippet} - -{#if platformName === 'windows'} - - {#snippet title()} - Use custom title bar - {/snippet} - {#snippet caption()} - Use GitButler's custom title bar with menu items. When disabled, the default Windows title bar - will be used. - {/snippet} - {#snippet actions()} - { - const newValue = !$userSettings.useCustomTitleBar; - userSettings.update((s) => ({ - ...s, - useCustomTitleBar: newValue - })); - // Update window decorations immediately - // Decorations are inverted: true = show default title bar, false = hide default title bar - await tauri.setDecorations(!newValue); - }} - /> - {/snippet} - -{/if} diff --git a/apps/desktop/src/lib/settings/userSettings.ts b/apps/desktop/src/lib/settings/userSettings.ts index 6296d542a5..959bd92164 100644 --- a/apps/desktop/src/lib/settings/userSettings.ts +++ b/apps/desktop/src/lib/settings/userSettings.ts @@ -29,7 +29,6 @@ export interface Settings { inlineUnifiedDiffs: boolean; diffContrast: 'light' | 'medium' | 'strong'; defaultCodeEditor: CodeEditorSettings; - useCustomTitleBar: boolean; } const defaults: Settings = { @@ -50,8 +49,7 @@ const defaults: Settings = { diffLigatures: false, inlineUnifiedDiffs: false, diffContrast: 'light', - defaultCodeEditor: { schemeIdentifer: 'vscode', displayName: 'VSCode' }, - useCustomTitleBar: true + defaultCodeEditor: { schemeIdentifer: 'vscode', displayName: 'VSCode' } }; export function loadUserSettings(): Writable { diff --git a/apps/desktop/src/routes/+layout.svelte b/apps/desktop/src/routes/+layout.svelte index 6da2f8da0d..ec5193e962 100644 --- a/apps/desktop/src/routes/+layout.svelte +++ b/apps/desktop/src/routes/+layout.svelte @@ -262,12 +262,11 @@ let shareIssueModal: ShareIssueModal; onMount(() => { - // Initialize window decorations based on user settings - // Only on Windows platform + // Initialize window decorations for Windows + // Always use custom title bar on Windows, so hide default decorations if (platformName === 'windows') { - const currentSettings = $userSettings; // Decorations are inverted: true = show default title bar, false = hide default title bar - data.tauri.setDecorations(!currentSettings.useCustomTitleBar); + data.tauri.setDecorations(false); } return unsubscribe( @@ -310,7 +309,7 @@
!dev && e.preventDefault()} > From 7a8070655bc437d51d7ffdd1f42258a2d17642ab Mon Sep 17 00:00:00 2001 From: Silke pilon Date: Tue, 24 Jun 2025 19:27:12 +0200 Subject: [PATCH 12/26] style(desktop): adjust WindowsTitleBar menu button spacing Update dropdown menu styles to remove margin on the wrapper and increase horizontal padding on menu buttons for better alignment. Set width to fit-content and min-width to auto to improve button sizing and layout consistency. These changes enhance the visual appearance and usability of the title bar menu. --- apps/desktop/src/components/WindowsTitleBar.svelte | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/components/WindowsTitleBar.svelte b/apps/desktop/src/components/WindowsTitleBar.svelte index 1f7c31bd36..adfaf370c0 100644 --- a/apps/desktop/src/components/WindowsTitleBar.svelte +++ b/apps/desktop/src/components/WindowsTitleBar.svelte @@ -567,6 +567,7 @@ .title-bar__menu :global(.dropdown-wrapper) { display: flex; + margin: 0; } /* Hide dropdown icons, separators, and vertical lines */ @@ -582,7 +583,7 @@ /* Style individual menu buttons as plain text */ .title-bar__menu :global(.dropdown-wrapper .btn) { height: 24px; - padding: 4px 1px; + padding: 4px 2px; gap: 0 !important; border: none !important; border-radius: 0 !important; @@ -593,6 +594,8 @@ opacity: 0.5; pointer-events: all !important; transition: opacity var(--transition-fast); + width: fit-content; + min-width: auto; } .title-bar__menu :global(.dropdown-wrapper .btn:hover) { From 6329bcccf9b7e3293437460ab614c18daf95fa1b Mon Sep 17 00:00:00 2001 From: Silke pilon Date: Tue, 24 Jun 2025 19:33:38 +0200 Subject: [PATCH 13/26] refactor: reorganize imports and streamline project state logic Rearrange import statements in WindowsTitleBar.svelte for better readability and grouping by functionality. Simplify the reactive effect that updates the active project on route changes by using promise chaining instead of an async function. Remove redundant comments and unused variables to clean up the component state initialization. These changes improve code clarity andability without altering component behavior. --- .../src/components/WindowsTitleBar.svelte | 295 ++++++------------ 1 file changed, 101 insertions(+), 194 deletions(-) diff --git a/apps/desktop/src/components/WindowsTitleBar.svelte b/apps/desktop/src/components/WindowsTitleBar.svelte index adfaf370c0..2898e38c99 100644 --- a/apps/desktop/src/components/WindowsTitleBar.svelte +++ b/apps/desktop/src/components/WindowsTitleBar.svelte @@ -1,35 +1,33 @@ @@ -34,12 +32,7 @@ -
+
{#if children} Date: Tue, 24 Jun 2025 23:38:43 +0200 Subject: [PATCH 16/26] refactor(ui): improve badge components and title bar UI Refactor Badge.svelte to use individual class bindings instead of string interpolation for better clarity and type safety. Reorder Tauri imports for consistency. Fix warning in WindowsTitleBar.svelte by adding void operator to pathname dependency. Upgrade console.log to console.warn for developer tools message to increase visibility. Add missing style and kind attributes to DropDownButtons in the title bar menu to ensure consistent styling. Add explicit type="button" attributes to window control buttons for better accessibility. --- .../src/components/WindowsTitleBar.svelte | 15 +++++++++++++-- apps/desktop/src/lib/backend/tauri.ts | 2 +- packages/ui/src/lib/Badge.svelte | 16 +++++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/components/WindowsTitleBar.svelte b/apps/desktop/src/components/WindowsTitleBar.svelte index 237c7a5a84..33df7f0610 100644 --- a/apps/desktop/src/components/WindowsTitleBar.svelte +++ b/apps/desktop/src/components/WindowsTitleBar.svelte @@ -51,7 +51,7 @@ // Update project when route changes (we need access to the current project for menus) $effect(() => { - $page.url.pathname; // Reactive dependency on route changes + void $page.url.pathname; // Reactive dependency on route changes projectsService .getActiveProject() .then((activeProject) => (project = activeProject)) @@ -126,7 +126,7 @@ document.documentElement.style.fontSize = '1rem'; userSettings.update((s) => ({ ...s, zoom: 1 })); }, - openDevTools: () => import.meta.env.DEV && console.log('Opening developer tools...'), + openDevTools: () => import.meta.env.DEV && console.warn('Opening developer tools...'), shareDebugInfo: () => events.emit('openSendIssueModal'), openKeyboardShortcuts: () => { // Keyboard shortcuts modal is handled by existing global shortcut registration @@ -191,6 +191,8 @@ fileDropdown?.show()} @@ -232,6 +234,8 @@ viewDropdown?.show()} @@ -282,6 +286,8 @@ projectDropdown?.show()} @@ -315,6 +321,8 @@ helpDropdown?.show()} @@ -379,6 +387,7 @@