diff --git a/CHANGELOG.md b/CHANGELOG.md index ad10d25..8304910 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,25 @@ All notable user-facing changes to Gitty are documented in this file. The project uses calendar-style versions in the form `YYYY.M.PATCH`. +## [2026.8.4] - 2026-08-15 + +### Added + +- Branch folders now have a context-menu action for deleting all contained + local or remote branches at once. The top-level remote folder such as + `origin` is protected, while its nested folders remain manageable. The + currently checked-out branch is kept, + and individual failures are reported after the remaining branches have been + processed. + +### Changed + +- The Compare selector is fully localized in German and uses the same visual + language as the external-tool selectors for its fields, groups, typography, + and dialog surfaces. +- Repository-tab close buttons are square and have clearer spacing, hover + behavior, and keyboard-focus feedback. + ## [2026.8.3] - 2026-08-13 ### Added @@ -161,6 +180,7 @@ The project uses calendar-style versions in the form `YYYY.M.PATCH`. [2026.07.22]: https://git.cbsk-tech.de/Christoph/GitLite/releases/tag/2026.7.22 [2026.07.21]: https://git.cbsk-tech.de/Christoph/GitLite/releases/tag/2026.7.21 [2026.7.20]: https://git.cbsk-tech.de/Christoph/GitLite/releases/tag/2026.7.20 +[2026.8.4]: https://git.cbsk-tech.de/Christoph/GitLite/releases/tag/2026.8.4 [2026.8.3]: https://git.cbsk-tech.de/Christoph/GitLite/releases/tag/2026.8.3 [2026.8.2]: https://git.cbsk-tech.de/Christoph/GitLite/releases/tag/2026.8.2 [2026.8.1]: https://git.cbsk-tech.de/Christoph/GitLite/releases/tag/2026.8.1 diff --git a/PKGBUILD-bin b/PKGBUILD-bin index 40704ee..8b581e9 100644 --- a/PKGBUILD-bin +++ b/PKGBUILD-bin @@ -1,7 +1,7 @@ # Maintainer: Christoph Brandau pkgname=gitty-desktop-bin -pkgver=2026.8.3 +pkgver=2026.8.4 pkgrel=1 pkgdesc="A lightweight, modern Git client built with Tauri (prebuilt AppImage)" arch=('x86_64') @@ -14,7 +14,7 @@ options=('!strip') _appimage="Gitty_${pkgver}_amd64.AppImage" _artifact_url="https://cdn.cbsk-tech.de/gitty/${pkgver}/${_appimage}" -_tag=2026.8.3 +_tag=2026.8.4 source=("${_appimage}::${_artifact_url}" "gitty-desktop.png::${url}/raw/tag/${_tag}/src-tauri/icons/icon.png") sha256sums=('SKIP' diff --git a/package-lock.json b/package-lock.json index 4f445a2..d0e808a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gitty", - "version": "2026.8.3", + "version": "2026.8.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gitty", - "version": "2026.8.3", + "version": "2026.8.4", "dependencies": { "@lucide/svelte": "^1.21.0", "@tailwindcss/vite": "^4.3.1", diff --git a/package.json b/package.json index 59b4370..c537c24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gitty", - "version": "2026.8.3", + "version": "2026.8.4", "private": true, "type": "module", "scripts": { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 41a9a07..1ec8080 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Gitty", - "version": "2026.8.3", + "version": "2026.8.4", "identifier": "com.gitty", "build": { "beforeDevCommand": "npm run dev", diff --git a/src/App.svelte b/src/App.svelte index be33802..522e9a6 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -2656,8 +2656,13 @@ trackEvent("branch_delete_dialog_opened"); } - async function deleteBranchFolder(folderName: string, folderBranches: GitBranchInfo[]) { + async function deleteBranchFolder(folderName: string, folderBranches: GitBranchInfo[], folderDepth: number) { if (!activeRepoPath || isBusy) return; + const remoteFolder = folderBranches.every((branch) => branch.remote); + if (remoteFolder && folderDepth === 0) { + errorMessage = "The top-level remote folder cannot be deleted as a group."; + return; + } const deletableBranches = folderBranches.filter((branch) => !branch.current); const currentBranchKept = folderBranches.some((branch) => branch.current); if (deletableBranches.length === 0) { @@ -2665,7 +2670,7 @@ return; } - const scope = deletableBranches.every((branch) => branch.remote) ? "remote" : "local"; + const scope = remoteFolder ? "remote" : "local"; const currentNote = currentBranchKept ? "\n\nThe current branch will be kept." : ""; if (!window.confirm(`Delete ${deletableBranches.length} ${scope} branches in “${folderName}”?${currentNote}`)) return; @@ -2691,7 +2696,7 @@ trackEvent("branch_folder_deleted", { attempted: deletableBranches.length, failed: failures.length, - remote: scope === "remote" ? 1 : 0, + remote: remoteFolder ? 1 : 0, }); if (failures.length > 0) { errorMessage = `${failures.length} branch${failures.length === 1 ? "" : "es"} could not be deleted:\n${failures.join("\n")}`; diff --git a/src/app.css b/src/app.css index 7ea5445..516ef25 100644 --- a/src/app.css +++ b/src/app.css @@ -1116,14 +1116,15 @@ display: grid; place-items: center; align-self: center; - min-width: 24px; - width: 24px; - min-height: 24px; - height: 24px; - flex: 0 0 24px; - aspect-ratio: 1; + min-width: 26px; + width: 26px; + max-width: 26px; + min-height: 26px; + height: 26px; + max-height: 26px; + flex: 0 0 26px; margin-right: 6px; - border-radius: 50%; + border-radius: 5px; opacity: 0.58; transition: opacity 120ms ease, color 120ms ease, background 120ms ease; } diff --git a/src/lib/components/BranchPanel.svelte b/src/lib/components/BranchPanel.svelte index 2f3eadd..57239e9 100644 --- a/src/lib/components/BranchPanel.svelte +++ b/src/lib/components/BranchPanel.svelte @@ -59,7 +59,7 @@ onRenameBranch: (branch: GitBranchInfo) => void | Promise; onDeleteBranch: (branch: GitBranchInfo) => void | Promise; onDeleteRemoteBranch: (branch: GitBranchInfo) => void | Promise; - onDeleteBranchFolder: (folderName: string, branches: GitBranchInfo[]) => void | Promise; + onDeleteBranchFolder: (folderName: string, branches: GitBranchInfo[], depth: number) => void | Promise; onCreateTag: (name: string, message: string) => void | Promise; onDeleteTag: (tag: GitTag) => void | Promise; onPushTag: (tag: GitTag) => void | Promise; @@ -283,7 +283,7 @@ async function openFolderContextMenu(event: MouseEvent, folder: BranchFolderRow) { event.preventDefault(); event.stopPropagation(); - if (isBusy) return; + if (isBusy || (folder.depth === 0 && folder.branches.every((branch) => branch.remote))) return; contextFolder = folder; contextMenuX = event.clientX + 2; @@ -324,9 +324,9 @@ async function deleteContextFolder() { const folder = contextFolder; - if (!folder || isBusy) return; + if (!folder || isBusy || (folder.depth === 0 && folder.branches.every((branch) => branch.remote))) return; closeBranchContextMenu(); - await onDeleteBranchFolder(folder.name, folder.branches); + await onDeleteBranchFolder(folder.name, folder.branches, folder.depth); } async function createContextWorktree() { @@ -584,7 +584,7 @@ style={`--branch-indent: ${row.depth * 16}px;`} type="button" onclick={() => toggleBranchFolder(row.id)} - oncontextmenu={(event) => openFolderContextMenu(event, row)} + oncontextmenu={row.depth > 0 ? (event) => openFolderContextMenu(event, row) : undefined} aria-expanded={isBranchFolderOpen(row.id)} title={`${row.name} (${row.branchCount})`} > diff --git a/src/lib/components/HelpOverlay.svelte b/src/lib/components/HelpOverlay.svelte index 8fe8916..08871c0 100644 --- a/src/lib/components/HelpOverlay.svelte +++ b/src/lib/components/HelpOverlay.svelte @@ -1399,6 +1399,17 @@ label: "Neu in Gitty", description: "Änderungen seit der letzten veröffentlichten Version und wichtige Neuerungen früherer Releases.", sections: [ + { + id: "changelog-2026-8-4", + title: "Version 2026.8.4", + summary: "Dieses Release vereinfacht die Verwaltung zusammengehöriger Branches und sorgt für eine einheitlichere, klarere Oberfläche.", + steps: [ + "Lokale und verschachtelte Remote-Branch-Ordner lassen sich über ihr Kontextmenü gesammelt löschen. Der oberste Remote-Ordner wie origin ist geschützt. Der aktuell ausgecheckte Branch bleibt erhalten und einzelne Fehler werden nach Abschluss verständlich aufgeführt.", + "Der Compare-Auswahldialog ist vollständig auf Deutsch verfügbar und orientiert sich bei Feldern, Gruppen, Typografie und Dialogflächen am Styling der externen Tools.", + "Die Schließen-Schaltflächen der Repository-Tabs sind quadratisch und haben ausgewogenere Abstände sowie deutlichere Hover- und Tastaturfokus-Zustände.", + ], + note: "Der oberste Remote-Ordner wie origin kann nicht gesammelt gelöscht werden. Seine Unterordner können weiterhin gezielt verwaltet werden.", + }, { id: "changelog-2026-8-3", title: "Version 2026.8.3", @@ -1488,6 +1499,17 @@ label: "What's new", description: "Changes since the latest published version and notable additions from earlier releases.", sections: [ + { + id: "changelog-2026-8-4", + title: "Version 2026.8.4", + summary: "This release simplifies managing related branches and makes the interface more consistent and easier to read.", + steps: [ + "Local and nested remote branch folders can be deleted in one action from their context menu. The top-level remote folder such as origin is protected. The currently checked-out branch is kept, and individual failures are summarized after processing.", + "The Compare selector is fully localized in German and now follows the external-tool selectors for fields, groups, typography, and dialog surfaces.", + "Repository-tab close buttons are square and have more balanced spacing and clearer hover and keyboard-focus states.", + ], + note: "The top-level remote folder such as origin cannot be deleted in bulk. Its nested folders can still be managed selectively.", + }, { id: "changelog-2026-8-3", title: "Version 2026.8.3",