Compare commits

..
6 Commits
Author SHA1 Message Date
Christoph 8bec7dfc9a style(ui): refine tab and dialog close button visuals
publish / Build and publish Ubuntu AppImage (release) Successful in 9m31s
publish / Build and publish Windows installer (release) Successful in 10m28s
publish / Build and publish AUR packages (release) Successful in 19m9s
Adjust spacing and sizing for repo tabs and close controls. Add
transitions, larger hit areas, and updated hover/focus styles. Introduce
theme-aware variants and neutral dialog close styling for consistency.
Also update help overlay close to match the new behavior.

- increase close button size and tweak padding for alignment
- add transitions and inset focus/hover visuals with themes
- normalize dialog and help close appearance for consistency
2026-08-31 11:14:56 +02:00
Christoph 7950edb145 fix(clone-dialog): improve layout and scrolling
Adjust grid templates and overflow rules to improve layout.
Replace fixed heights with flexible rows so content fills space.
Hide overflow and tweak alignment to avoid double scrollbars.

- Use grid-template-rows to allocate header, controls, and list area
- Make repository list shell and list use height: 100% and overflow:auto
- Align URL field to the top to prevent unexpected scrolling
2026-08-31 10:25:07 +02:00
Christoph e3af6653cd fix(layout): account for repo tab bar in loading overlay
Adjust the fixed loading overlay to avoid overlapping the repo tab bar.
The top offset now adds the app titlebar and repo tabbar heights using
CSS calc with reasonable fallbacks. This keeps the overlay aligned with
top UI elements when a repository tab bar is present.

- Offset top by titlebar plus repo tabbar heights via CSS calc.
- Provide sensible fallback values to maintain stable layout.
2026-08-31 10:10:00 +02:00
Christoph b752c0804b style(repo-loading-overlay): adjust overlay position and backdrop
Remove the extra vertical offset so the loading overlay aligns with the
app titlebar. Update the backdrop color mix and increase blur to improve
contrast and perceived depth while the overlay is visible.

- Align overlay using the titlebar height variable instead of adding a
  fixed offset
- Use a denser color mix and stronger blur for a clearer backdrop effect
2026-08-31 09:05:10 +02:00
Christoph 8f98e79df9 feat(clone-dialog): redesign UI and group Azure DevOps repos
Rework CloneRepositoryDialog into a two-column layout with a source
sidebar and focused content area to make browsing sources easier.
Group Azure DevOps repositories by project with a new derived value
and render sticky project headers for clearer navigation.
Replace showIntegrations with selectIntegrationSource to load the
chosen integration, refresh repositories, and update labels and styles.

- Introduce source sidebar and refreshed dialog layout
- Add azureRepositoryGroups and project grouping UI
- Rename flow to selectIntegrationSource and improve loading logic
2026-08-31 08:43:00 +02:00
Christoph f0a1d89152 Update version to 2026.8.9 2026-08-30 20:26:46 +02:00
7 changed files with 179 additions and 67 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "gitty", "name": "gitty",
"version": "2026.8.8", "version": "2026.8.9",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "gitty", "name": "gitty",
"version": "2026.8.8", "version": "2026.8.9",
"dependencies": { "dependencies": {
"@lucide/svelte": "^1.21.0", "@lucide/svelte": "^1.21.0",
"@tailwindcss/vite": "^4.3.1", "@tailwindcss/vite": "^4.3.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "gitty", "name": "gitty",
"version": "2026.8.8", "version": "2026.8.9",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Gitty", "productName": "Gitty",
"version": "2026.8.8", "version": "2026.8.9",
"identifier": "com.gitty", "identifier": "com.gitty",
"build": { "build": {
"beforeDevCommand": "npm run prepare:lfs && npm run dev", "beforeDevCommand": "npm run prepare:lfs && npm run dev",
+46 -12
View File
@@ -8843,7 +8843,7 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
.repo-tab { .repo-tab {
min-height: 35px; min-height: 35px;
height: 35px; height: 35px;
padding: 0 31px 0 15px; padding: 0 34px 0 15px;
gap: 6px; gap: 6px;
font-size: 12.5px; font-size: 12.5px;
font-weight: 650; font-weight: 650;
@@ -8869,19 +8869,21 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
.repo-tab-close { .repo-tab-close {
position: absolute; position: absolute;
top: 8px; top: 6px;
right: 6px; right: 5px;
width: 19px; width: 23px;
min-width: 19px; min-width: 23px;
max-width: 19px; max-width: 23px;
height: 19px; height: 23px;
min-height: 19px; min-height: 23px;
max-height: 19px; max-height: 23px;
margin: 0; margin: 0;
border-radius: 2px; border-radius: 3px;
color: var(--color-ink-faint); color: var(--color-ink-faint);
background: transparent; background: transparent;
box-shadow: none;
opacity: 0.62; opacity: 0.62;
transition: opacity 120ms ease, color 120ms ease, background 120ms ease, box-shadow 120ms ease;
} }
.repo-tab-wrap.active .repo-tab-close { opacity: 0.72; } .repo-tab-wrap.active .repo-tab-close { opacity: 0.72; }
@@ -8889,8 +8891,16 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
.repo-tab-wrap:focus-within .repo-tab-close { opacity: 1; } .repo-tab-wrap:focus-within .repo-tab-close { opacity: 1; }
.repo-tab-close:hover:not(:disabled), .repo-tab-close:hover:not(:disabled),
.repo-tab-close:focus-visible:not(:disabled) { .repo-tab-close:focus-visible:not(:disabled) {
color: #e1848b; color: #ffffff;
background: transparent; background: #d93641;
box-shadow: inset 0 0 0 1px #f0646d;
}
:root[data-theme="light"] .repo-tab-close:hover:not(:disabled),
:root[data-theme="light"] .repo-tab-close:focus-visible:not(:disabled) {
color: #ffffff;
background: #c92f3a;
box-shadow: inset 0 0 0 1px #a9212b;
} }
.repo-tab-add { .repo-tab-add {
@@ -8939,3 +8949,27 @@ input:focus, textarea:focus, select:focus { box-shadow: 0 0 0 3px color-mix(in s
:root:not([data-theme="light"]) .repo-tab.management.active > svg { :root:not([data-theme="light"]) .repo-tab.management.active > svg {
color: #d7dae0; color: #d7dae0;
} }
/* Keep every dialog close action neutral until it is intentionally targeted. */
:root .dialog-close:hover:not(:disabled),
:root .dialog-close:focus-visible:not(:disabled),
:root .dialog-icon-button:hover:not(:disabled),
:root .dialog-icon-button:focus-visible:not(:disabled),
:root .cred-close:hover:not(:disabled),
:root .cred-close:focus-visible:not(:disabled) {
color: #ffffff;
border-color: #f0646d;
background: #d93641;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}
:root[data-theme="light"] .dialog-close:hover:not(:disabled),
:root[data-theme="light"] .dialog-close:focus-visible:not(:disabled),
:root[data-theme="light"] .dialog-icon-button:hover:not(:disabled),
:root[data-theme="light"] .dialog-icon-button:focus-visible:not(:disabled),
:root[data-theme="light"] .cred-close:hover:not(:disabled),
:root[data-theme="light"] .cred-close:focus-visible:not(:disabled) {
color: #ffffff;
border-color: #a9212b;
background: #c92f3a;
}
+115 -38
View File
@@ -55,6 +55,18 @@
if (!query) return activeRepositories; if (!query) return activeRepositories;
return activeRepositories.filter((repository) => `${repository.fullName} ${repository.description}`.toLocaleLowerCase().includes(query)); return activeRepositories.filter((repository) => `${repository.fullName} ${repository.description}`.toLocaleLowerCase().includes(query));
}); });
const azureRepositoryGroups = $derived.by(() => {
if (activeSource?.provider !== "azure-devops") return [];
const groups = new Map<string, GitIntegrationRepository[]>();
for (const repository of filteredRepositories) {
const separator = repository.fullName.indexOf("/");
const project = separator > 0 ? repository.fullName.slice(0, separator) : (isGerman ? "Weitere Repositories" : "Other repositories");
const repositories = groups.get(project) ?? [];
repositories.push(repository);
groups.set(project, repositories);
}
return [...groups.entries()].map(([project, repositories]) => ({ project, repositories }));
});
const selectedRepository = $derived(activeRepositories.find((repository) => repository.id === selectedRepositoryId)); const selectedRepository = $derived(activeRepositories.find((repository) => repository.id === selectedRepositoryId));
const directorySuggestion = $derived(directoryNameFromRemoteUrl(remoteUrl)); const directorySuggestion = $derived(directoryNameFromRemoteUrl(remoteUrl));
const canSubmit = $derived(!isBusy && remoteUrl.trim().length > 0 && parentPath.trim().length > 0); const canSubmit = $derived(!isBusy && remoteUrl.trim().length > 0 && parentPath.trim().length > 0);
@@ -230,10 +242,9 @@
} }
} }
function showIntegrations() { function selectIntegrationSource(integrationSource: GitIntegrationSource) {
source = "integrations"; source = "integrations";
const nextSource = configuredSources.find((candidate) => candidate.id === selectedSourceId) ?? configuredSources[0]; void loadRepositories(integrationSource);
if (nextSource) void loadRepositories(nextSource);
} }
function showUrlInput() { function showUrlInput() {
@@ -255,20 +266,41 @@
<div class="dialog-backdrop" role="presentation"> <div class="dialog-backdrop" role="presentation">
<div class="dialog clone-repository-dialog" role="dialog" aria-modal="true" aria-label={isGerman ? "Repository klonen" : "Clone repository"} tabindex="-1"> <div class="dialog clone-repository-dialog" role="dialog" aria-modal="true" aria-label={isGerman ? "Repository klonen" : "Clone repository"} tabindex="-1">
<header class="dialog-header"> <header class="dialog-header clone-dialog-header">
<div><span class="eyebrow">Repository Management</span><h2 class="mt-0.5 text-ink text-base font-bold leading-tight">{isGerman ? "Repository klonen" : "Clone repository"}</h2></div> <div><h2>{isGerman ? "Repository klonen" : "Clone a Repository"}</h2></div>
<button class="dialog-close" type="button" onclick={onClose} disabled={isBusy} title={isGerman ? "Schließen" : "Close"} aria-label={isGerman ? "Klonen schließen" : "Close clone dialog"}><X size={18} /></button> <button class="dialog-close" type="button" onclick={onClose} disabled={isBusy} title={isGerman ? "Schließen" : "Close"} aria-label={isGerman ? "Klonen schließen" : "Close clone dialog"}><X size={18} /></button>
</header> </header>
<form class="clone-dialog-form" onsubmit={submit}> <form class="clone-dialog-form" onsubmit={submit}>
<div class="clone-source-tabs" role="tablist" aria-label={isGerman ? "Repository-Quelle" : "Repository source"}> <div class="clone-dialog-layout">
<button type="button" role="tab" aria-selected={source === "url"} class:active={source === "url"} onclick={showUrlInput}><Globe2 size={15} />URL</button> <aside class="clone-source-nav" aria-label={isGerman ? "Repository-Quellen" : "Repository sources"}>
<button type="button" role="tab" aria-selected={source === "integrations"} class:active={source === "integrations"} onclick={showIntegrations}><Cloud size={15} />{isGerman ? "Integrationen" : "Integrations"}{#if configuredSources.length}<em>{configuredSources.length}</em>{/if}</button> <div class="clone-source-heading">{isGerman ? "Quelle" : "Source"}</div>
<div class="clone-source-list" role="tablist" aria-label={isGerman ? "Repository-Quelle" : "Repository source"}>
<button type="button" role="tab" aria-selected={source === "url"} class:active={source === "url"} onclick={showUrlInput}><Globe2 size={15} /><span>{isGerman ? "Mit URL klonen" : "Clone with URL"}</span></button>
{#each configuredSources as integrationSource}
<button type="button" role="tab" aria-selected={source === "integrations" && selectedSourceId === integrationSource.id} class:active={source === "integrations" && selectedSourceId === integrationSource.id} onclick={() => selectIntegrationSource(integrationSource)}>
{#if integrationSource.provider === "azure-devops"}<Cloud size={15} />{:else}<GitBranch size={15} />{/if}
<span>{integrationSource.provider === "azure-devops" ? `Azure · ${integrationSource.label}` : integrationSource.label}</span>
</button>
{/each}
</div>
{#if configuredSources.length === 0}<p>{isGerman ? "Integrationen kannst du in den Einstellungen einrichten." : "Set up integrations in Settings."}</p>{/if}
</aside>
<section class="clone-dialog-content">
<div class="clone-dialog-title">
<span>{source === "integrations" ? (activeSource?.label ?? "Integration") : "URL"}</span>
<h3>{isGerman ? "Repository klonen" : "Clone a Repo"}</h3>
</div>
<div class="clone-target-grid">
<label class="clone-dialog-field"><span>{isGerman ? "Klonen nach" : "Where to clone to"}</span><div class="clone-dialog-path-field"><input bind:value={parentPath} autocomplete="off" spellcheck="false" placeholder={isGerman ? "Übergeordneten Ordner auswählen" : "Choose parent folder"} disabled={isBusy} /><button class="btn-secondary" type="button" onclick={chooseParentFolder} disabled={isBusy}><FolderOpen size={14} />{isGerman ? "Durchsuchen" : "Browse"}</button></div></label>
<label class="clone-dialog-field"><span>{isGerman ? "Ordnername" : "Folder name"}</span><input bind:value={directoryName} oninput={handleDirectoryInput} autocomplete="off" spellcheck="false" placeholder={directorySuggestion || "Optional"} disabled={isBusy} /></label>
</div> </div>
{#if source === "url"} {#if source === "url"}
<label class="clone-dialog-field"> <label class="clone-dialog-field clone-url-field">
<span>{isGerman ? "Remote-URL" : "Remote URL"}</span> <span>{isGerman ? "Repository-URL" : "Repository URL"}</span>
<!-- svelte-ignore a11y_autofocus --> <!-- svelte-ignore a11y_autofocus -->
<input value={remoteUrl} oninput={handleRemoteInput} autocomplete="off" spellcheck="false" placeholder="https://gitlab.com/org/project.git" disabled={isBusy} autofocus /> <input value={remoteUrl} oninput={handleRemoteInput} autocomplete="off" spellcheck="false" placeholder="https://gitlab.com/org/project.git" disabled={isBusy} autofocus />
</label> </label>
@@ -277,11 +309,8 @@
{#if configuredSources.length === 0} {#if configuredSources.length === 0}
<div class="integration-empty"><Cloud size={26} /><strong>{isGerman ? "Keine aktive Integration" : "No active integration"}</strong><p>{isGerman ? "Richte unter Einstellungen → Integrationen zuerst GitHub, GitLab, Azure DevOps oder Gitea ein." : "Set up GitHub, GitLab, Azure DevOps, or Gitea under Settings → Integrations first."}</p></div> <div class="integration-empty"><Cloud size={26} /><strong>{isGerman ? "Keine aktive Integration" : "No active integration"}</strong><p>{isGerman ? "Richte unter Einstellungen → Integrationen zuerst GitHub, GitLab, Azure DevOps oder Gitea ein." : "Set up GitHub, GitLab, Azure DevOps, or Gitea under Settings → Integrations first."}</p></div>
{:else} {:else}
<div class="integration-provider-tabs" role="tablist" aria-label={isGerman ? "Konfigurierte Anbieter" : "Configured providers"}>
{#each configuredSources as integrationSource}<button type="button" role="tab" aria-selected={selectedSourceId === integrationSource.id} class:active={selectedSourceId === integrationSource.id} onclick={() => loadRepositories(integrationSource)}>{integrationSource.provider === "azure-devops" ? `Azure · ${integrationSource.label}` : integrationSource.label}</button>{/each}
</div>
<div class="repository-toolbar"> <div class="repository-toolbar">
<label><Search size={14} /><input bind:value={repositorySearch} placeholder={isGerman ? "Repositories filtern…" : "Filter repositories…"} aria-label={isGerman ? "Repositories filtern" : "Filter repositories"} /></label> <label><Search size={14} /><input bind:value={repositorySearch} placeholder={isGerman ? "Repositories durchsuchen…" : "Search repositories…"} aria-label={isGerman ? "Repositories durchsuchen" : "Search repositories"} /></label>
<button type="button" onclick={() => activeSource && loadRepositories(activeSource, true)} disabled={!activeSource || loadingSourceId.length > 0} title={isGerman ? "Neu laden" : "Refresh"} aria-label={isGerman ? "Repository-Liste neu laden" : "Refresh repository list"}><RefreshCw class={loadingSourceId ? "spin" : ""} size={14} /></button> <button type="button" onclick={() => activeSource && loadRepositories(activeSource, true)} disabled={!activeSource || loadingSourceId.length > 0} title={isGerman ? "Neu laden" : "Refresh"} aria-label={isGerman ? "Repository-Liste neu laden" : "Refresh repository list"}><RefreshCw class={loadingSourceId ? "spin" : ""} size={14} /></button>
</div> </div>
<div class="repository-list-shell"> <div class="repository-list-shell">
@@ -292,6 +321,19 @@
<div class="repository-state repository-state-error"><strong>{isGerman ? "Repositories konnten nicht geladen werden" : "Could not load repositories"}</strong><span>{repositoryError}</span></div> <div class="repository-state repository-state-error"><strong>{isGerman ? "Repositories konnten nicht geladen werden" : "Could not load repositories"}</strong><span>{repositoryError}</span></div>
{:else if filteredRepositories.length === 0} {:else if filteredRepositories.length === 0}
<div class="repository-state"><GitBranch size={20} /><span>{repositorySearch ? (isGerman ? "Keine passenden Repositories." : "No matching repositories.") : (isGerman ? "Keine Repositories gefunden." : "No repositories found.")}</span></div> <div class="repository-state"><GitBranch size={20} /><span>{repositorySearch ? (isGerman ? "Keine passenden Repositories." : "No matching repositories.") : (isGerman ? "Keine Repositories gefunden." : "No repositories found.")}</span></div>
{:else if activeSource?.provider === "azure-devops"}
{#each azureRepositoryGroups as group (group.project)}
<section class="repository-project-group" aria-label={group.project}>
<div class="repository-project-header"><span>{group.project}</span><em>{group.repositories.length}</em></div>
{#each group.repositories as repository (repository.id)}
<button type="button" class="repository-option" class:selected={selectedRepositoryId === repository.id} onclick={() => selectRepository(repository)}>
<span class="repository-option-icon"><GitBranch size={15} /></span>
<span class="repository-option-copy"><strong>{repository.name}</strong><small>{repository.description || repository.cloneUrl}</small></span>
<span class="repository-option-meta">{#if repository.private}<LockKeyhole size={12} aria-label={isGerman ? "Privat" : "Private"} />{/if}{formatUpdatedAt(repository.updatedAt)}</span>
</button>
{/each}
</section>
{/each}
{:else} {:else}
{#each filteredRepositories as repository (repository.id)} {#each filteredRepositories as repository (repository.id)}
<button type="button" class="repository-option" class:selected={selectedRepositoryId === repository.id} onclick={() => selectRepository(repository)}> <button type="button" class="repository-option" class:selected={selectedRepositoryId === repository.id} onclick={() => selectRepository(repository)}>
@@ -334,35 +376,43 @@
</section> </section>
{/if} {/if}
<div class="clone-target-grid">
<label class="clone-dialog-field"><span>{isGerman ? "Ziel" : "Destination"}</span><div class="clone-dialog-path-field"><input bind:value={parentPath} autocomplete="off" spellcheck="false" placeholder={isGerman ? "Übergeordneten Ordner auswählen" : "Choose parent folder"} disabled={isBusy} /><button class="btn-secondary" type="button" onclick={chooseParentFolder} disabled={isBusy}><FolderOpen size={14} />{isGerman ? "Durchsuchen" : "Browse"}</button></div></label>
<label class="clone-dialog-field"><span>{isGerman ? "Ordnername" : "Folder name"}</span><input bind:value={directoryName} oninput={handleDirectoryInput} autocomplete="off" spellcheck="false" placeholder={directorySuggestion || "Optional"} disabled={isBusy} /></label>
</div>
{#if visibleError}<div class="clone-dialog-error" role="alert">{visibleError}</div>{/if} {#if visibleError}<div class="clone-dialog-error" role="alert">{visibleError}</div>{/if}
</section>
</div>
<div class="clone-dialog-actions"><button class="btn-secondary" type="button" onclick={onClose} disabled={isBusy}>{isGerman ? "Abbrechen" : "Cancel"}</button><button class="btn-primary" type="submit" disabled={!canSubmit}>{#if isBusy}<LoaderCircle class="spin" size={16} />{:else}<Download size={16} />{/if}{isGerman ? "Klonen" : "Clone"}</button></div> <div class="clone-dialog-actions"><button class="btn-secondary" type="button" onclick={onClose} disabled={isBusy}>{isGerman ? "Abbrechen" : "Cancel"}</button><button class="btn-primary" type="submit" disabled={!canSubmit}>{#if isBusy}<LoaderCircle class="spin" size={16} />{:else}<Download size={16} />{/if}{isGerman ? "Klonen" : "Clone"}</button></div>
</form> </form>
</div> </div>
</div> </div>
<style> <style>
.clone-repository-dialog { width: min(760px, calc(100vw - 32px)); } .clone-repository-dialog { width: min(900px, calc(100vw - 32px)); height: min(660px, calc(100vh - 32px)); }
.clone-source-tabs { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px; padding: 4px; border: 1px solid var(--color-border-subtle); border-radius: 9px; background: var(--app-settings-row-bg); } .clone-dialog-header { min-height: 52px; padding: 0 16px 0 20px; }
.clone-source-tabs button { min-height: 36px; border-color: transparent; color: var(--color-ink-dim); background: transparent; font-size: 11px; font-weight: 800; } .clone-dialog-header h2 { margin: 0; color: var(--color-ink); font-size: 15px; font-weight: 650; }
.clone-source-tabs button.active { border-color: var(--color-border-input); color: var(--color-ink); background: var(--color-surface-raised); box-shadow: 0 2px 8px rgba(0,0,0,.12); } .clone-dialog-form { grid-template-rows: minmax(0, 1fr) auto; gap: 0; height: calc(100% - 53px); padding: 0; }
.clone-source-tabs button.active :global(svg) { color: var(--color-accent); } .clone-dialog-layout { display: grid; grid-template-columns: 205px minmax(0, 1fr); min-height: 0; }
.clone-source-tabs em { display: grid; place-items: center; min-width: 19px; height: 18px; padding: 0 5px; border-radius: 9px; color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 12%, transparent); font-size: 9px; font-style: normal; } .clone-source-nav { min-width: 0; padding: 12px 0; border-right: 1px solid var(--color-border-subtle); background: var(--app-dialog-chrome); }
.integration-browser { display: grid; gap: 9px; min-height: 270px; padding: 11px; border: 1px solid var(--color-border-subtle); border-radius: 10px; background: color-mix(in srgb, var(--app-settings-row-bg) 72%, transparent); } .clone-source-heading { padding: 2px 14px 8px; color: var(--color-ink-faint); font-size: 8.5px; font-weight: 850; text-transform: uppercase; letter-spacing: .08em; }
.integration-provider-tabs { display: flex; gap: 5px; overflow-x: auto; } .clone-source-list { display: grid; gap: 2px; }
.integration-provider-tabs button { flex: 0 0 auto; min-height: 29px; padding: 0 9px; border-color: transparent; color: var(--color-ink-dim); background: transparent; font-size: 10px; font-weight: 750; } .clone-source-list button { display: grid; grid-template-columns: 18px minmax(0, 1fr); align-items: center; gap: 8px; width: 100%; min-height: 38px; padding: 0 14px; border: 0; border-radius: 0; color: var(--color-ink-dim); background: transparent; box-shadow: none; font-size: 10.5px; font-weight: 650; text-align: left; }
.integration-provider-tabs button.active { border-color: color-mix(in srgb, var(--color-accent) 30%, var(--color-border)); color: var(--color-ink); background: color-mix(in srgb, var(--color-accent) 8%, var(--color-surface-raised)); } .clone-source-list button span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clone-source-list button :global(svg) { color: var(--color-ink-faint); }
.clone-source-list button:hover { color: var(--color-ink); background: var(--color-surface-hover); }
.clone-source-list button.active { color: var(--color-ink); background: color-mix(in srgb, var(--color-accent) 18%, var(--color-surface-hover)); box-shadow: inset 3px 0 0 var(--color-accent); }
.clone-source-list button.active :global(svg) { color: var(--color-accent); }
.clone-source-nav > p { margin: 12px 14px 0; color: var(--color-ink-faint); font-size: 9px; line-height: 1.45; }
.clone-dialog-content { display: grid; grid-template-rows: auto auto minmax(0, 1fr); grid-auto-rows: auto; align-content: stretch; gap: 14px; min-width: 0; min-height: 0; padding: 16px 18px; overflow: hidden; }
.clone-dialog-title { display: grid; gap: 3px; }
.clone-dialog-title > span { color: var(--color-accent); font-size: 8.5px; font-weight: 850; text-transform: uppercase; letter-spacing: .07em; }
.clone-dialog-title h3 { margin: 0; color: var(--color-ink); font-size: 16px; font-weight: 650; }
.clone-url-field { align-self: start; margin-top: 2px; }
.integration-browser { display: grid; grid-template-rows: auto minmax(0, 1fr); grid-auto-rows: auto; gap: 8px; min-height: 0; }
.repository-toolbar { display: grid; grid-template-columns: minmax(0, 1fr) 32px; gap: 6px; } .repository-toolbar { display: grid; grid-template-columns: minmax(0, 1fr) 32px; gap: 6px; }
.repository-toolbar label { position: relative; min-width: 0; } .repository-toolbar label { position: relative; min-width: 0; }
.repository-toolbar label > :global(svg) { position: absolute; z-index: 1; top: 10px; left: 10px; color: var(--color-ink-faint); } .repository-toolbar label > :global(svg) { position: absolute; z-index: 1; top: 10px; left: 10px; color: var(--color-ink-faint); }
.repository-toolbar input { height: 34px; padding-left: 31px; font-size: 11px; } .repository-toolbar input { height: 34px; padding-left: 31px; font-size: 11px; }
.repository-toolbar button { min-height: 32px; padding: 0; } .repository-toolbar button { min-height: 32px; padding: 0; }
.repository-list-shell { position: relative; min-height: 162px; max-height: 250px; overflow: hidden; border: 1px solid var(--color-border-subtle); border-radius: 8px; background: var(--color-surface-raised); } .repository-list-shell { position: relative; min-height: 0; height: 100%; overflow: hidden; border: 1px solid var(--color-border-input); border-radius: 7px; background: var(--color-surface-raised); box-shadow: 0 8px 18px rgba(0,0,0,.13); }
.repository-list { min-height: 160px; max-height: 248px; padding-right: 8px; overflow: auto; scrollbar-width: none; border-radius: inherit; background: transparent; } .repository-list { min-height: 0; height: 100%; padding-right: 8px; overflow: auto; scrollbar-width: none; border-radius: inherit; background: transparent; }
.repository-list::-webkit-scrollbar { display: none; width: 0; height: 0; } .repository-list::-webkit-scrollbar { display: none; width: 0; height: 0; }
.repository-scrollbar { position: absolute; z-index: 2; top: 3px; right: 1px; bottom: 3px; width: 7px; border-radius: 4px; opacity: 0; pointer-events: none; touch-action: none; transition: opacity 120ms ease; } .repository-scrollbar { position: absolute; z-index: 2; top: 3px; right: 1px; bottom: 3px; width: 7px; border-radius: 4px; opacity: 0; pointer-events: none; touch-action: none; transition: opacity 120ms ease; }
.repository-scrollbar.visible { opacity: 1; pointer-events: auto; } .repository-scrollbar.visible { opacity: 1; pointer-events: auto; }
@@ -371,28 +421,55 @@
.repository-scrollbar:focus-visible .repository-scrollbar-thumb, .repository-scrollbar:focus-visible .repository-scrollbar-thumb,
.repository-scrollbar.dragging .repository-scrollbar-thumb { right: 1px; width: 4px; background: var(--app-scrollbar-thumb-hover); } .repository-scrollbar.dragging .repository-scrollbar-thumb { right: 1px; width: 4px; background: var(--app-scrollbar-thumb-hover); }
.repository-scrollbar:focus-visible { outline: 1px solid color-mix(in srgb, var(--color-accent) 70%, transparent); outline-offset: 1px; } .repository-scrollbar:focus-visible { outline: 1px solid color-mix(in srgb, var(--color-accent) 70%, transparent); outline-offset: 1px; }
.repository-option { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 9px; width: 100%; min-height: 52px; padding: 7px 9px; border: 0; border-bottom: 1px solid var(--color-border-subtle); border-radius: 0; color: var(--color-ink-dim); background: transparent; text-align: left; } .repository-project-group + .repository-project-group { border-top: 1px solid var(--color-border-subtle); }
.repository-project-header { position: sticky; z-index: 1; top: 0; display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 34px; padding: 7px 10px 6px 12px; color: var(--color-accent); background: color-mix(in srgb, var(--color-surface-raised) 96%, transparent); font-size: 9.5px; font-weight: 900; text-transform: uppercase; letter-spacing: .045em; }
.repository-project-header span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.repository-project-header em { display: grid; flex: 0 0 auto; place-items: center; min-width: 19px; height: 16px; padding: 0 5px; color: var(--color-ink); background: color-mix(in srgb, var(--color-ink) 12%, transparent); font-size: 8px; font-style: normal; line-height: 1; letter-spacing: 0; }
.repository-option { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 8px; width: 100%; min-height: 44px; padding: 6px 10px 6px 12px; border: 0; border-bottom: 1px solid var(--color-border-subtle); border-radius: 0; color: var(--color-ink-dim); background: transparent; text-align: left; }
.repository-option:last-child { border-bottom: 0; } .repository-option:last-child { border-bottom: 0; }
.repository-option:hover { color: var(--color-ink); background: var(--color-surface-hover); } .repository-option:hover { color: var(--color-ink); background: var(--color-surface-hover); }
.repository-option.selected { color: var(--color-ink); background: color-mix(in srgb, var(--color-accent) 8%, var(--color-surface-hover)); box-shadow: inset 2px 0 0 var(--color-accent); } .repository-option.selected { color: var(--color-ink); background: color-mix(in srgb, var(--color-accent) 15%, var(--color-surface-hover)); box-shadow: inset 3px 0 0 var(--color-accent); }
.repository-option-icon { display: grid; place-items: center; width: 30px; height: 30px; border: 1px solid var(--color-border-subtle); border-radius: 7px; color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 7%, transparent); } .repository-option-icon { display: grid; place-items: center; width: 22px; height: 22px; color: var(--color-ink-faint); }
.repository-option.selected .repository-option-icon { color: var(--color-accent); }
.repository-option-copy { display: grid; min-width: 0; gap: 3px; } .repository-option-copy { display: grid; min-width: 0; gap: 3px; }
.repository-option-copy strong, .repository-option-copy small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .repository-option-copy strong, .repository-option-copy small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.repository-option-copy strong { color: inherit; font-size: 10.5px; } .repository-option-copy strong { color: inherit; font-size: 10.5px; }
.repository-option-copy small { color: var(--color-ink-faint); font-size: 9px; } .repository-option-copy small { color: var(--color-ink-faint); font-size: 9px; }
.repository-project-group .repository-option { min-height: 38px; padding-block: 5px; }
.repository-project-group .repository-option-copy { gap: 0; }
.repository-project-group .repository-option-copy strong { color: var(--color-ink); font-size: 11.5px; font-weight: 800; }
.repository-project-group .repository-option-copy small { display: none; }
.repository-option-meta { display: flex; align-items: center; gap: 5px; color: var(--color-ink-faint); font-size: 8.5px; } .repository-option-meta { display: flex; align-items: center; gap: 5px; color: var(--color-ink-faint); font-size: 8.5px; }
.repository-state, .integration-empty { display: grid; place-items: center; align-content: center; min-height: 160px; padding: 20px; color: var(--color-ink-faint); text-align: center; } .repository-state, .integration-empty { display: grid; place-items: center; align-content: center; min-height: 188px; padding: 20px; color: var(--color-ink-faint); text-align: center; }
.repository-state { gap: 7px; font-size: 10.5px; } .repository-state { gap: 7px; font-size: 10.5px; }
.repository-state strong, .integration-empty strong { color: var(--color-ink); font-size: 11px; } .repository-state strong, .integration-empty strong { color: var(--color-ink); font-size: 11px; }
.repository-state-error strong { color: #e86060; } .repository-state-error strong { color: #e86060; }
.repository-state-error span { max-width: 520px; line-height: 1.45; } .repository-state-error span { max-width: 520px; line-height: 1.45; }
.integration-empty { min-height: 235px; gap: 8px; } .integration-empty { min-height: 260px; gap: 8px; }
.integration-empty :global(svg) { color: var(--color-accent); } .integration-empty :global(svg) { color: var(--color-accent); }
.integration-empty p { max-width: 400px; margin: 0; color: var(--color-ink-faint); font-size: 10px; line-height: 1.5; } .integration-empty p { max-width: 400px; margin: 0; color: var(--color-ink-faint); font-size: 10px; line-height: 1.5; }
.selected-repository { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 3px 8px; min-width: 0; padding: 8px 9px; border-left: 2px solid var(--color-accent); background: color-mix(in srgb, var(--color-accent) 6%, transparent); } .selected-repository { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 3px 8px; min-width: 0; padding: 8px 9px; border-left: 2px solid var(--color-accent); background: color-mix(in srgb, var(--color-accent) 6%, transparent); }
.selected-repository span { color: var(--color-accent); font-size: 8.5px; font-weight: 850; text-transform: uppercase; letter-spacing: .04em; } .selected-repository span { color: var(--color-accent); font-size: 8.5px; font-weight: 850; text-transform: uppercase; letter-spacing: .04em; }
.selected-repository strong { overflow: hidden; color: var(--color-ink); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; } .selected-repository strong { overflow: hidden; color: var(--color-ink); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
.selected-repository code { grid-column: 2; overflow: hidden; color: var(--color-ink-faint); font: 8.5px var(--font-mono); text-overflow: ellipsis; white-space: nowrap; } .selected-repository code { grid-column: 2; overflow: hidden; color: var(--color-ink-faint); font: 8.5px var(--font-mono); text-overflow: ellipsis; white-space: nowrap; }
.clone-target-grid { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(150px, .75fr); gap: 10px; } .clone-target-grid { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(150px, .72fr); gap: 10px; }
@media (max-width: 620px) { .clone-repository-dialog { width: min(620px, calc(100vw - 20px)); } .clone-target-grid { grid-template-columns: 1fr; } .repository-option-meta { display: none; } } .clone-dialog-actions { min-height: 54px; align-items: center; padding: 9px 16px; border-top: 1px solid var(--color-border-subtle); background: var(--app-dialog-chrome); }
@media (max-width: 700px) {
.clone-repository-dialog { width: min(660px, calc(100vw - 20px)); }
.clone-dialog-layout { grid-template-columns: 155px minmax(0, 1fr); }
.clone-source-list button { padding-inline: 10px; }
.clone-target-grid { grid-template-columns: 1fr; }
.repository-option-meta { display: none; }
}
@media (max-width: 500px) {
.dialog-backdrop { padding: 10px; }
.clone-repository-dialog { width: calc(100vw - 20px); height: min(660px, calc(100vh - 20px)); }
.clone-dialog-layout { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
.clone-source-nav { padding: 6px 0; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--color-border-subtle); }
.clone-source-heading, .clone-source-nav > p { display: none; }
.clone-source-list { display: flex; width: max-content; min-width: 100%; padding: 0 6px; }
.clone-source-list button { width: auto; min-height: 34px; padding-inline: 9px; border-radius: 5px; }
.clone-source-list button.active { box-shadow: inset 0 -2px 0 var(--color-accent); }
.clone-dialog-content { padding: 13px 12px; overflow: hidden; }
}
</style> </style>
+2 -1
View File
@@ -2116,7 +2116,8 @@
.help-search-icon { position: absolute; left: 12px; display: grid; color: var(--color-ink-faint); pointer-events: none; } .help-search-icon { position: absolute; left: 12px; display: grid; color: var(--color-ink-faint); pointer-events: none; }
.help-search input { width: 100%; height: 40px; padding: 0 68px 0 39px; border-color: var(--color-border-input); border-radius: 8px; background: var(--app-input-bg); color: var(--color-ink); font-size: 12.5px; } .help-search input { width: 100%; height: 40px; padding: 0 68px 0 39px; border-color: var(--color-border-input); border-radius: 8px; background: var(--app-input-bg); color: var(--color-ink); font-size: 12.5px; }
.help-search kbd { position: absolute; right: 8px; } .help-search kbd { position: absolute; right: 8px; }
.help-close { justify-self: end; width: 36px; min-height: 36px; padding: 0; border-color: transparent; border-radius: 7px; background: transparent; color: var(--color-ink-muted); } .help-close { justify-self: end; width: 36px; min-height: 36px; padding: 0; border-color: transparent; border-radius: 7px; background: transparent; color: var(--color-ink-muted); transition: color 120ms ease, border-color 120ms ease, background 120ms ease, box-shadow 120ms ease; }
.help-close:hover:not(:disabled), .help-close:focus-visible:not(:disabled) { color: #fff; border-color: #f0646d; background: #d93641; box-shadow: inset 0 0 0 1px rgba(255,255,255,.08); }
.help-layout { display: grid; grid-template-columns: 250px minmax(0, 1fr); min-height: 0; } .help-layout { display: grid; grid-template-columns: 250px minmax(0, 1fr); min-height: 0; }
.help-nav { display: flex; flex-direction: column; min-height: 0; padding: 14px 10px 12px; border-right: 1px solid var(--color-border); background: var(--color-surface-dim); } .help-nav { display: flex; flex-direction: column; min-height: 0; padding: 14px 10px 12px; border-right: 1px solid var(--color-border); background: var(--color-surface-dim); }
+3 -3
View File
@@ -33,7 +33,7 @@
<style> <style>
.repo-loading { .repo-loading {
position: fixed; position: fixed;
top: calc(var(--app-titlebar-height, 42px) + 56px); top: calc(var(--app-titlebar-height, 40px) + var(--app-repo-tabbar-height, 36px));
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
@@ -47,8 +47,8 @@
color-mix(in srgb, var(--color-accent) 13%, transparent), color-mix(in srgb, var(--color-accent) 13%, transparent),
transparent 38% transparent 38%
), ),
var(--app-dialog-backdrop); color-mix(in srgb, var(--app-dialog-bg) 78%, #05070a 22%);
backdrop-filter: blur(5px); backdrop-filter: blur(9px);
animation: overlay-in 180ms ease; animation: overlay-in 180ms ease;
} }