Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion staged/src/lib/features/branches/BranchCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@

interface Props {
branch: Branch;
repoLabel?: string | null;
repoLabel?: { githubRepo: string; subpath: string | null } | null;
deleting?: boolean;
worktreeError?: string;
onDelete?: () => void;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script lang="ts">
import { GitBranch } from 'lucide-svelte';
import RepoLabel from '../../shared/RepoLabel.svelte';

interface Props {
branchName: string;
repoLabel?: string | null;
repoLabel?: { githubRepo: string; subpath: string | null } | null;
secondaryLabel?: string | null;
}

Expand All @@ -12,7 +13,9 @@

<div class="header-left">
{#if repoLabel}
<span class="repo-name" title={repoLabel}>{repoLabel}</span>
<span class="repo-name"
><RepoLabel githubRepo={repoLabel.githubRepo} subpath={repoLabel.subpath} /></span
>
<div class="header-meta">
<span class="branch-name">{branchName}</span>
{#if secondaryLabel}
Expand Down
2 changes: 1 addition & 1 deletion staged/src/lib/features/branches/RemoteBranchCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

interface Props {
branch: Branch;
repoLabel?: string | null;
repoLabel?: { githubRepo: string; subpath: string | null } | null;
deleting?: boolean;
onDelete?: () => void;
onRename?: (branchName: string) => void;
Expand Down
44 changes: 37 additions & 7 deletions staged/src/lib/features/projects/ProjectHome.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
// Data
let projects = $state<Project[]>([]);
let branchesByProject = $state<Map<string, Branch[]>>(new Map());
let repoLabelsByProject = $state<Map<string, Map<string, string>>>(new Map());
let repoLabelsByProject = $state<
Map<string, Map<string, { githubRepo: string; subpath: string | null }>>
>(new Map());
let loading = $state(true);
let error = $state<string | null>(null);
let loadGeneration = 0;
Expand Down Expand Up @@ -178,7 +180,10 @@

// Seed maps so project sections can render immediately.
const branchMap = new Map<string, Branch[]>();
const repoLabelMap = new Map<string, Map<string, string>>();
const repoLabelMap = new Map<
string,
Map<string, { githubRepo: string; subpath: string | null }>
>();
for (const project of projectList) {
branchMap.set(project.id, branchesByProject.get(project.id) || []);
repoLabelMap.set(project.id, repoLabelsByProject.get(project.id) || new Map());
Expand All @@ -197,7 +202,15 @@
branchesByProject = new Map(branchesByProject).set(project.id, branches);
repoLabelsByProject = new Map(repoLabelsByProject).set(
project.id,
new Map(repos.map((repo) => [repo.id, repo.githubRepo] as const))
new Map(
repos.map(
(repo) =>
[
repo.id,
{ githubRepo: repo.githubRepo, subpath: repo.subpath ?? null },
] as const
)
)
);
} catch (e) {
console.error(`[ProjectHome] Failed to hydrate project '${project.id}':`, e);
Expand Down Expand Up @@ -319,7 +332,12 @@
branchesByProject = new Map(branchesByProject).set(project.id, branches);
repoLabelsByProject = new Map(repoLabelsByProject).set(
project.id,
new Map(repos.map((repo) => [repo.id, repo.githubRepo] as const))
new Map(
repos.map(
(repo) =>
[repo.id, { githubRepo: repo.githubRepo, subpath: repo.subpath ?? null }] as const
)
)
);
startInitialBranchSetup(project.id, branches);
showNewProjectModal = false;
Expand Down Expand Up @@ -423,7 +441,12 @@
branchesByProject = new Map(branchesByProject).set(projectId, branches);
repoLabelsByProject = new Map(repoLabelsByProject).set(
projectId,
new Map(repos.map((repo) => [repo.id, repo.githubRepo] as const))
new Map(
repos.map(
(repo) =>
[repo.id, { githubRepo: repo.githubRepo, subpath: repo.subpath ?? null }] as const
)
)
);
startInitialBranchSetup(projectId, branches);
} catch (e) {
Expand Down Expand Up @@ -626,7 +649,12 @@
branchesByProject = new Map(branchesByProject).set(branch.projectId, branches);
repoLabelsByProject = new Map(repoLabelsByProject).set(
branch.projectId,
new Map(repos.map((repo) => [repo.id, repo.githubRepo] as const))
new Map(
repos.map(
(repo) =>
[repo.id, { githubRepo: repo.githubRepo, subpath: repo.subpath ?? null }] as const
)
)
);
} else {
await commands.deleteBranch(branch.id);
Expand Down Expand Up @@ -761,7 +789,9 @@
handleRenameBranch(branchId, project.id, branchName)}
onWorkspaceStatusChange={(branchId, workspaceStatus) =>
handleWorkspaceStatusChange(project.id, branchId, workspaceStatus)}
excludeRepos={new Set(repoLabelsByProject.get(project.id)?.values())}
excludeRepos={new Set(
[...(repoLabelsByProject.get(project.id)?.values() ?? [])].map((r) => r.githubRepo)
)}
onRepoSelected={(nameWithOwner, subpath) =>
handleRepoSelected(project.id, nameWithOwner, subpath)}
onRetryWorktree={(branchId) => setupBranchWorktree(branchId, project.id)}
Expand Down
13 changes: 9 additions & 4 deletions staged/src/lib/features/projects/ProjectSection.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
interface Props {
project: Project;
branches: Branch[];
repoLabelsById?: Map<string, string>;
repoLabelsById?: Map<string, { githubRepo: string; subpath: string | null }>;
canAddRepo?: boolean;
addRepoHint?: string | null;
deleting?: boolean;
Expand Down Expand Up @@ -92,9 +92,14 @@
return () => window.removeEventListener('pointerdown', onPointerDown);
});

function repoLabelForBranch(branch: Branch): string | null {
if (!branch.projectRepoId) return project.githubRepo;
return repoLabelsById.get(branch.projectRepoId) ?? project.githubRepo;
function repoLabelForBranch(
branch: Branch
): { githubRepo: string; subpath: string | null } | null {
const fallback = project.githubRepo
? { githubRepo: project.githubRepo, subpath: project.subpath ?? null }
: null;
if (!branch.projectRepoId) return fallback;
return repoLabelsById.get(branch.projectRepoId) ?? fallback;
}
</script>

Expand Down
19 changes: 15 additions & 4 deletions staged/src/lib/features/projects/ProjectsList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import { getProjectStatus } from './projectStatus';
import SplashScreen from './SplashScreen.svelte';
import Spinner from '../../shared/Spinner.svelte';
import RepoLabel from '../../shared/RepoLabel.svelte';
import { setHasProjects } from './projectsSidebarState.svelte';

let projects = $state<Project[]>([]);
Expand Down Expand Up @@ -337,9 +338,16 @@
<div class="deleting-pill" role="status" aria-live="polite">Deleting…</div>
{/if}
<div class="repo">
{repos.length > 0
? repos.map((r) => r.githubRepo).join(', ')
: (project.githubRepo ?? 'No repo attached')}
{#if repos.length > 0}
{#each repos as r, i}
{#if i > 0}<span class="repo-separator">, </span>{/if}
<RepoLabel githubRepo={r.githubRepo} subpath={r.subpath} />
{/each}
{:else if project.githubRepo}
<RepoLabel githubRepo={project.githubRepo} subpath={project.subpath} />
{:else}
No repo attached
{/if}
</div>
</button>
<div class="card-location">
Expand Down Expand Up @@ -524,7 +532,6 @@

.repo {
margin-top: auto;
color: var(--text-primary);
font-size: var(--size-sm);
display: -webkit-box;
-webkit-box-orient: vertical;
Expand All @@ -533,6 +540,10 @@
overflow: hidden;
}

.repo-separator {
color: var(--text-faint);
}

.deleting-pill {
width: fit-content;
padding: 2px 8px;
Expand Down
12 changes: 3 additions & 9 deletions staged/src/lib/features/projects/RepoSearchInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { onMount, onDestroy } from 'svelte';
import { Search, Lock, Globe, Clock, Plus, Command } from 'lucide-svelte';
import Spinner from '../../shared/Spinner.svelte';
import RepoLabel from '../../shared/RepoLabel.svelte';
import * as commands from '../../commands';
import type { GitHubRepo, RecentRepo } from '../../types';

Expand Down Expand Up @@ -278,9 +279,7 @@
</div>
<div class="repo-info">
<span class="repo-name">
{recent.githubRepo}{#if recent.subpath}<span class="repo-subpath"
>/{recent.subpath}</span
>{/if}
<RepoLabel githubRepo={recent.githubRepo} subpath={recent.subpath} />
</span>
</div>
{#if i < 3}
Expand Down Expand Up @@ -336,7 +335,7 @@
{/if}
</div>
<div class="repo-info">
<span class="repo-name">{repo.nameWithOwner}</span>
<span class="repo-name"><RepoLabel githubRepo={repo.nameWithOwner} /></span>
{#if repo.description}
<span class="repo-description">{repo.description}</span>
{/if}
Expand Down Expand Up @@ -484,11 +483,6 @@
white-space: nowrap;
}

.repo-subpath {
font-weight: 400;
color: var(--text-muted);
}

.repo-description {
font-size: var(--size-xs);
color: var(--text-muted);
Expand Down
18 changes: 2 additions & 16 deletions staged/src/lib/features/settings/ActionsPreferencesModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
Code2,
} from 'lucide-svelte';
import Spinner from '../../shared/Spinner.svelte';
import RepoLabel from '../../shared/RepoLabel.svelte';
import type { ActionContext, ProjectAction } from '../../commands';
import * as commands from '../../commands';
import { detectRepoActions, type SuggestedAction, type ActionType } from '../actions/actions';
Expand Down Expand Up @@ -88,11 +89,6 @@
loadActions();
});

function contextLabel(context: ActionContext): string {
const repoName = context.githubRepo.split('/').pop() || context.githubRepo;
return context.subpath ? `${repoName}/${context.subpath}` : repoName;
}

async function detectActions() {
if (!selectedContext) return;

Expand Down Expand Up @@ -305,9 +301,7 @@
class:selected={context.id === selectedContextId}
onclick={() => (selectedContextId = context.id)}
>
<span class="context-repo">{context.githubRepo}</span>{#if context.subpath}<span
class="context-subpath">/{context.subpath}</span
>{/if}
<RepoLabel githubRepo={context.githubRepo} subpath={context.subpath} />
</button>
{/each}
</div>
Expand Down Expand Up @@ -522,14 +516,6 @@
border-color: var(--border-muted);
}

.context-repo {
color: var(--text-primary);
}

.context-subpath {
color: var(--text-muted);
}

.loading-side,
.empty-side,
.empty-main,
Expand Down
60 changes: 60 additions & 0 deletions staged/src/lib/shared/RepoLabel.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!--
RepoLabel – reusable repo-path display with contrast styling.

The *last* path segment gets full contrast (--text-primary) while every
preceding segment is muted (--text-muted). This makes the most
distinguishing part of the path pop out visually.

Examples:
githubRepo="block/staged" → "block/" muted + "staged" primary
githubRepo="block/staged" subpath="ui" → "block/staged/" muted + "ui" primary
-->
<script lang="ts">
interface Props {
githubRepo: string;
subpath?: string | null;
}

let { githubRepo, subpath = null }: Props = $props();

let prefix = $derived.by(() => {
if (subpath) {
return githubRepo + '/';
}
const idx = githubRepo.lastIndexOf('/');
return idx >= 0 ? githubRepo.slice(0, idx + 1) : '';
});

let emphasis = $derived.by(() => {
if (subpath) {
return subpath;
}
const idx = githubRepo.lastIndexOf('/');
return idx >= 0 ? githubRepo.slice(idx + 1) : githubRepo;
});

let fullLabel = $derived(subpath ? `${githubRepo}/${subpath}` : githubRepo);
</script>

<span class="repo-label" title={fullLabel}
>{#if prefix}<span class="repo-label-prefix">{prefix}</span>{/if}<span class="repo-label-emphasis"
>{emphasis}</span
></span
>

<style>
.repo-label {
display: inline;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.repo-label-prefix {
color: var(--text-muted);
}

.repo-label-emphasis {
color: var(--text-primary);
}
</style>