Compare commits

...
3 Commits
Author SHA1 Message Date
Christoph 22da397e39 fix(git): make unsetting upstream idempotent
Saving sync settings with no upstream could cause a fatal Git
error when unsetting upstream on a branch that never had tracking
information. This change guards the operation by checking for an existing
merge configuration before unsetting, making it idempotent. A test was
added to verify that clearing an unconfigured upstream is a no-op.

- Add test ensuring clearing an unconfigured upstream is a no-op
2026-08-26 00:35:30 +02:00
Christoph f160e48777 Update version to 2026.8.7 2026-08-23 23:41:30 +02:00
Christoph 4533f8aa38 style(theme): add dialog & panel CSS vars and refactor status panel styles
publish / Build and publish Ubuntu AppImage (release) Successful in 19m39s
publish / Build and publish Windows installer (release) Successful in 22m14s
publish / Build and publish AUR packages (release) Successful in 48m41s
Add CSS custom properties for dialog backdrop, shadows, and panel
highlights to centralize visual theming. Refactor the status panel
overlay to consume these tokens and use color-mix instead of hardcoded
rgba values. This improves visual consistency and lets overlays adapt
cleanly to appearance changes and theme variants.

- Centralize dialog and panel visuals with new CSS variables
- Replace fixed rgba values with tokenized colors and color-mix
- Move borders, shadows, and gradients to use the new theme tokens
2026-08-23 23:38:42 +02:00
7 changed files with 223 additions and 23 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "gitty",
"version": "2026.8.6",
"version": "2026.8.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gitty",
"version": "2026.8.6",
"version": "2026.8.7",
"dependencies": {
"@lucide/svelte": "^1.21.0",
"@tailwindcss/vite": "^4.3.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gitty",
"version": "2026.8.6",
"version": "2026.8.7",
"private": true,
"type": "module",
"scripts": {
+26 -1
View File
@@ -836,7 +836,13 @@ pub fn set_branch_upstream(
)?;
}
None => {
run_git(&repo, ["branch", "--unset-upstream", branch.as_str()])?;
// Saving sync settings with "No upstream" must be idempotent. Git
// exits with a fatal error when --unset-upstream is used on a
// branch that never had tracking information, which is the normal
// state immediately after adding the first remote.
if git_config_value(&repo, &format!("branch.{branch}.merge")).is_some() {
run_git(&repo, ["branch", "--unset-upstream", branch.as_str()])?;
}
}
}
status_for_repo(&repo)
@@ -7661,6 +7667,25 @@ mod tests {
assert_eq!(remote.upstream, None);
}
#[test]
fn clearing_an_unconfigured_upstream_is_a_noop() {
let repo = init_temp_repo("unset_missing_upstream");
commit_initial_file(&repo.path);
let branch = git_output_test(&repo.path, ["branch", "--show-current"]);
run_git_test(&repo.path, ["remote", "add", "origin", "."]);
let status = set_branch_upstream(
repo.path.to_string_lossy().to_string(),
branch.clone(),
None,
)
.expect("saving an empty upstream should not fail");
assert_eq!(status.current_branch.as_deref(), Some(branch.as_str()));
assert_eq!(status.upstream, None);
assert!(git_config_value(&repo.path, &format!("branch.{branch}.merge")).is_none());
}
#[test]
fn commit_notes_can_be_created_updated_and_deleted_without_changing_commit() {
let repo = init_temp_repo("commit_notes_crud");
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Gitty",
"version": "2026.8.6",
"version": "2026.8.7",
"identifier": "com.gitty",
"build": {
"beforeDevCommand": "npm run prepare:lfs && npm run dev",
+5 -1
View File
@@ -1179,7 +1179,8 @@
root.dataset.appearance = next;
const customProperties = [
"--app-bg", "--app-button-bg", "--app-input-bg", "--app-dialog-bg", "--app-dialog-chrome",
"--app-settings-row-bg", "--color-surface", "--color-surface-alt", "--color-surface-dim",
"--app-dialog-backdrop", "--app-dialog-shadow", "--app-panel-shadow", "--app-settings-row-bg",
"--color-surface", "--color-surface-alt", "--color-surface-dim",
"--color-surface-hover", "--color-surface-raised", "--color-surface-solid", "--color-border",
"--color-border-subtle", "--color-border-input", "--color-primary", "--color-primary-dark",
"--color-accent", "--color-ink", "--color-ink-muted", "--color-ink-faint", "--color-ink-dim",
@@ -1195,6 +1196,9 @@
"--app-input-bg": `color-mix(in srgb, ${surface} 88%, white)`,
"--app-dialog-bg": surface,
"--app-dialog-chrome": `color-mix(in srgb, ${surface} 90%, ${background})`,
"--app-dialog-backdrop": `color-mix(in srgb, ${background} 72%, transparent)`,
"--app-dialog-shadow": `0 24px 68px color-mix(in srgb, ${text} 24%, transparent), 0 2px 12px color-mix(in srgb, ${text} 12%, transparent)`,
"--app-panel-shadow": `0 18px 48px color-mix(in srgb, ${text} 18%, transparent), inset 0 1px 0 color-mix(in srgb, ${surface} 88%, white)`,
"--app-settings-row-bg": `color-mix(in srgb, ${surface} 92%, ${background})`,
"--color-surface": surface,
"--color-surface-alt": `color-mix(in srgb, ${surface} 82%, ${background})`,
+166
View File
@@ -8672,3 +8672,169 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
.branch-filter-summary { align-items: stretch; flex-direction: column; }
.branch-filter-actions { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* Authentication and token dialogs ------------------------------------
Keep credentials, access tokens and API-key forms on the active theme
instead of the legacy violet/black palette. */
.cred-card,
:root[data-theme="light"] .cred-card {
border-color: var(--color-border-input);
background: var(--app-dialog-bg);
box-shadow: var(--app-dialog-shadow);
}
.cred-hero,
:root[data-theme="light"] .cred-hero {
border-bottom-color: var(--color-border);
background:
radial-gradient(circle at 8% 0%, color-mix(in srgb, var(--color-accent) 14%, transparent), transparent 44%),
var(--app-dialog-chrome);
}
.cred-hero-icon,
:root[data-theme="light"] .cred-hero-icon {
border-color: color-mix(in srgb, var(--color-accent) 42%, var(--color-border));
color: var(--color-accent);
background: color-mix(in srgb, var(--color-accent) 12%, var(--color-surface-raised));
box-shadow: 0 10px 24px color-mix(in srgb, var(--color-accent) 18%, transparent);
}
.cred-hero-label,
:root[data-theme="light"] .cred-hero-label {
color: var(--color-accent);
}
.cred-hero-title,
:root[data-theme="light"] .cred-hero-title {
color: var(--color-ink);
}
.cred-hero-copy,
:root[data-theme="light"] .cred-hero-copy {
color: var(--color-ink-muted);
}
.cred-security-note,
:root[data-theme="light"] .cred-security-note {
border-color: color-mix(in srgb, var(--color-accent) 32%, var(--color-border));
color: var(--color-ink-muted);
background: color-mix(in srgb, var(--color-accent) 8%, var(--color-surface-raised));
}
.cred-security-note svg,
:root[data-theme="light"] .cred-security-note svg {
color: var(--color-accent);
}
.cred-close,
:root[data-theme="light"] .cred-close {
border-color: var(--color-border);
color: var(--color-ink-faint);
background: var(--color-surface-raised);
}
.cred-close:hover:not(:disabled),
:root[data-theme="light"] .cred-close:hover:not(:disabled) {
border-color: var(--color-border-input);
color: var(--color-ink);
background: var(--color-surface-hover);
}
.cred-body,
:root[data-theme="light"] .cred-body {
background: var(--app-dialog-bg);
}
.cred-segment,
:root[data-theme="light"] .cred-segment {
border-color: var(--color-border);
background: var(--color-surface-alt);
}
.cred-seg-btn,
:root[data-theme="light"] .cred-seg-btn {
color: var(--color-ink-faint);
}
.cred-seg-btn:hover:not(.active),
:root[data-theme="light"] .cred-seg-btn:hover:not(.active) {
color: var(--color-ink);
background: var(--color-surface-hover);
}
.cred-seg-btn.active,
:root[data-theme="light"] .cred-seg-btn.active {
border-color: color-mix(in srgb, var(--color-accent) 46%, var(--color-border));
color: var(--color-ink);
background: color-mix(in srgb, var(--color-accent) 12%, var(--color-surface-raised));
box-shadow: inset 0 -2px 0 var(--color-accent);
}
.cred-input input,
.cred-expiry input[type="date"],
:root[data-theme="light"] .cred-input input,
:root[data-theme="light"] .cred-expiry input[type="date"] {
border-color: var(--color-border-input);
color: var(--color-ink);
background: var(--app-input-bg);
color-scheme: var(--app-color-scheme);
}
.cred-input input::placeholder,
:root[data-theme="light"] .cred-input input::placeholder {
color: var(--color-ink-faint);
opacity: 0.72;
}
.cred-token-hint,
:root[data-theme="light"] .cred-token-hint {
border-color: color-mix(in srgb, var(--color-accent) 34%, var(--color-border));
color: var(--color-ink-muted);
background: color-mix(in srgb, var(--color-accent) 8%, var(--color-surface-dim));
}
.cred-token-hint code,
:root[data-theme="light"] .cred-token-hint code {
color: var(--color-accent);
background: color-mix(in srgb, var(--color-accent) 12%, var(--color-surface-raised));
}
.cred-footer {
border-top-color: var(--color-border-subtle);
}
.cred-save input[type="checkbox"] {
accent-color: var(--color-accent);
}
.cred-save span {
color: var(--color-ink-muted);
}
.cred-cancel {
border-color: var(--color-border);
color: var(--color-ink-muted);
background: var(--color-surface-raised);
}
.cred-submit {
border-color: color-mix(in srgb, var(--color-accent) 62%, var(--color-border));
color: var(--color-surface-solid);
background: var(--color-primary-dark);
box-shadow: none;
}
.cred-submit:hover:not(:disabled) {
border-color: var(--color-accent);
color: var(--color-surface-solid);
background: var(--color-primary);
}
@media (max-width: 560px) {
.cred-card { width: calc(100vw - 16px); max-height: calc(100vh - 16px); }
.cred-hero { padding: 16px; }
.cred-body { padding: 16px; }
.cred-security-note { align-items: flex-start; border-radius: 8px; padding-block: 7px; }
.cred-footer { align-items: stretch; flex-direction: column; }
.cred-btns { display: grid; grid-template-columns: 1fr 1fr; }
}
+22 -17
View File
@@ -660,8 +660,12 @@
display: grid;
place-items: center;
background:
radial-gradient(circle at 50% 38%, rgba(111, 140, 255, 0.1), transparent 55%),
rgba(7, 10, 16, 0.62);
radial-gradient(
circle at 50% 38%,
color-mix(in srgb, var(--color-accent) 13%, transparent),
transparent 55%
),
var(--app-dialog-backdrop);
backdrop-filter: blur(4px);
animation: status-panel-overlay-in 120ms ease;
}
@@ -673,13 +677,13 @@
gap: 12px;
width: min(300px, calc(100% - 32px));
padding: 26px 28px 26px;
border: 1px solid rgba(90, 111, 154, 0.28);
border: 1px solid var(--color-border-input);
border-radius: 16px;
background:
linear-gradient(180deg, rgba(23, 29, 43, 0.92), rgba(12, 17, 27, 0.94)),
var(--color-surface-raised);
var(--app-panel-highlight),
var(--app-dialog-bg);
color: var(--color-ink);
box-shadow: 0 18px 44px rgba(0, 0, 0, 0.34), inset 0 1px 0 rgba(255, 255, 255, 0.05);
box-shadow: var(--app-dialog-shadow);
}
.status-panel-overlay-mark {
@@ -694,7 +698,7 @@
.status-panel-overlay-halo {
position: absolute;
inset: 6px;
border: 1px solid rgba(111, 140, 255, 0.22);
border: 1px solid color-mix(in srgb, var(--color-primary) 34%, transparent);
border-radius: 22px;
transform: rotate(45deg);
}
@@ -703,7 +707,7 @@
}
.status-panel-overlay-halo.halo-two {
inset: 16px;
border-color: rgba(77, 182, 214, 0.24);
border-color: color-mix(in srgb, var(--color-accent) 38%, transparent);
animation: status-panel-overlay-halo-breathe 2.4s ease-in-out infinite reverse;
}
@@ -721,16 +725,16 @@
stroke-linecap: round;
stroke-dasharray: 165;
stroke-dashoffset: 165;
filter: drop-shadow(0 0 6px rgba(77, 182, 214, 0.32));
filter: drop-shadow(0 0 6px color-mix(in srgb, var(--color-accent) 38%, transparent));
animation: status-panel-overlay-trace-draw 2.6s ease-in-out infinite;
}
.status-panel-overlay-traces .trace-main { stroke: #6f8cff; }
.status-panel-overlay-traces .trace-main { stroke: var(--color-primary); }
.status-panel-overlay-traces .trace-branch {
stroke: #4db6d6;
stroke: var(--color-accent);
animation-delay: 0.28s;
}
.status-panel-overlay-traces .trace-cut {
stroke: rgba(177, 186, 208, 0.42);
stroke: color-mix(in srgb, var(--color-ink-muted) 52%, transparent);
stroke-dasharray: 128;
stroke-dashoffset: 128;
animation-delay: 0.55s;
@@ -743,8 +747,8 @@
height: 64px;
object-fit: contain;
filter:
drop-shadow(0 8px 12px rgba(0, 0, 0, 0.5))
drop-shadow(0 0 10px rgba(77, 182, 214, 0.2));
drop-shadow(0 8px 12px color-mix(in srgb, var(--color-ink) 24%, transparent))
drop-shadow(0 0 10px color-mix(in srgb, var(--color-accent) 24%, transparent));
animation: status-panel-overlay-icon-float 2.4s ease-in-out infinite;
}
@@ -765,15 +769,16 @@
height: 4px;
overflow: hidden;
border-radius: 999px;
background: rgba(111, 140, 255, 0.14);
border: 1px solid var(--color-border-subtle);
background: color-mix(in srgb, var(--color-primary) 12%, var(--color-surface-dim));
}
.status-panel-overlay-bar span {
position: absolute;
inset: 0;
width: 46%;
border-radius: inherit;
background: linear-gradient(90deg, transparent, #6f8cff 40%, #4db6d6 74%, transparent);
box-shadow: 0 0 12px rgba(77, 182, 214, 0.26);
background: linear-gradient(90deg, transparent, var(--color-primary) 40%, var(--color-accent) 74%, transparent);
box-shadow: 0 0 12px color-mix(in srgb, var(--color-accent) 32%, transparent);
animation: status-panel-overlay-bar-slide 1.35s ease-in-out infinite;
}