feat(ui): show worktree badge in session list
Render a worktree pill on parent sessions using the session status chip styling, with a distinct icon and selection-aware colors.
This commit is contained in:
@@ -2,7 +2,7 @@ import { Component, For, Show, createSignal, createMemo, createEffect, JSX, onCl
|
|||||||
import type { SessionStatus } from "../types/session"
|
import type { SessionStatus } from "../types/session"
|
||||||
import type { SessionThread } from "../stores/session-state"
|
import type { SessionThread } from "../stores/session-state"
|
||||||
import { getSessionStatus } from "../stores/session-status"
|
import { getSessionStatus } from "../stores/session-status"
|
||||||
import { Bot, User, Copy, Trash2, Pencil, ShieldAlert, ChevronDown, Search, Square, CheckSquare, MinusSquare } from "lucide-solid"
|
import { Bot, User, Copy, Trash2, Pencil, ShieldAlert, ChevronDown, Search, Square, CheckSquare, MinusSquare, Split } from "lucide-solid"
|
||||||
import KeyboardHint from "./keyboard-hint"
|
import KeyboardHint from "./keyboard-hint"
|
||||||
import SessionRenameDialog from "./session-rename-dialog"
|
import SessionRenameDialog from "./session-rename-dialog"
|
||||||
import { keyboardRegistry } from "../lib/keyboard-registry"
|
import { keyboardRegistry } from "../lib/keyboard-registry"
|
||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
setActiveSessionFromList,
|
setActiveSessionFromList,
|
||||||
toggleSessionParentExpanded,
|
toggleSessionParentExpanded,
|
||||||
} from "../stores/sessions"
|
} from "../stores/sessions"
|
||||||
|
import { getGitRepoStatus, getWorktreeSlugForParentSession } from "../stores/worktrees"
|
||||||
import { getLogger } from "../lib/logger"
|
import { getLogger } from "../lib/logger"
|
||||||
import { copyToClipboard } from "../lib/clipboard"
|
import { copyToClipboard } from "../lib/clipboard"
|
||||||
const log = getLogger("session")
|
const log = getLogger("session")
|
||||||
@@ -353,6 +354,19 @@ const SessionList: Component<SessionListProps> = (props) => {
|
|||||||
if (!session()) {
|
if (!session()) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const worktreeSlug = createMemo(() => {
|
||||||
|
if (rowProps.isChild) return "root"
|
||||||
|
return getWorktreeSlugForParentSession(props.instanceId, rowProps.sessionId)
|
||||||
|
})
|
||||||
|
|
||||||
|
const showWorktreeBadge = createMemo(() => {
|
||||||
|
if (rowProps.isChild) return false
|
||||||
|
if (getGitRepoStatus(props.instanceId) === false) return false
|
||||||
|
const slug = worktreeSlug()
|
||||||
|
return Boolean(slug) && slug !== "root"
|
||||||
|
})
|
||||||
|
|
||||||
const isActive = () => props.activeSessionId === rowProps.sessionId
|
const isActive = () => props.activeSessionId === rowProps.sessionId
|
||||||
const title = () => session()?.title || t("sessionList.session.untitled")
|
const title = () => session()?.title || t("sessionList.session.untitled")
|
||||||
const status = () => getSessionStatus(props.instanceId, rowProps.sessionId)
|
const status = () => getSessionStatus(props.instanceId, rowProps.sessionId)
|
||||||
@@ -459,6 +473,12 @@ const SessionList: Component<SessionListProps> = (props) => {
|
|||||||
{needsInput() ? <ShieldAlert class="w-3.5 h-3.5" aria-hidden="true" /> : <span class="status-dot" />}
|
{needsInput() ? <ShieldAlert class="w-3.5 h-3.5" aria-hidden="true" /> : <span class="status-dot" />}
|
||||||
{statusText()}
|
{statusText()}
|
||||||
</span>
|
</span>
|
||||||
|
<Show when={showWorktreeBadge()}>
|
||||||
|
<span class="status-indicator session-status-list worktree-indicator" title={`Worktree: ${worktreeSlug()}`}>
|
||||||
|
<Split class="w-3.5 h-3.5" aria-hidden="true" />
|
||||||
|
<span class="worktree-indicator-label">{worktreeSlug()}</span>
|
||||||
|
</span>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<div class="session-item-actions">
|
<div class="session-item-actions">
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -245,6 +245,29 @@
|
|||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Session list worktree pill */
|
||||||
|
.status-indicator.worktree-indicator {
|
||||||
|
/* Match session title in selected state. */
|
||||||
|
color: var(--text-primary);
|
||||||
|
/* Use inactive session title color as the tint source. */
|
||||||
|
background-color: color-mix(in oklab, var(--text-secondary) 18%, transparent);
|
||||||
|
border-color: color-mix(in oklab, var(--text-secondary) 28%, transparent);
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.session-item-active .status-indicator.worktree-indicator {
|
||||||
|
background-color: color-mix(in oklab, var(--text-primary) 14%, transparent);
|
||||||
|
border-color: color-mix(in oklab, var(--text-primary) 22%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator.worktree-indicator .worktree-indicator-label {
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 10rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
/* Empty state */
|
/* Empty state */
|
||||||
.empty-state {
|
.empty-state {
|
||||||
@apply flex-1 flex items-center justify-center p-12;
|
@apply flex-1 flex items-center justify-center p-12;
|
||||||
|
|||||||
Reference in New Issue
Block a user