refactor(tui): fade long session branch details
This commit is contained in:
@@ -9,8 +9,8 @@ import {
|
||||
adaptiveSessionTabLayout,
|
||||
moveSessionTab,
|
||||
NEW_SESSION_TAB_TITLE,
|
||||
sessionTabBranch,
|
||||
sessionTabComplete,
|
||||
sessionTabDetail,
|
||||
sessionTabShortcutLabel,
|
||||
seedSessionTabMotion,
|
||||
sessionTabOverflowWidth,
|
||||
@@ -149,25 +149,15 @@ function VerticalSessionTabs(props: { controller?: SessionTabsController; animat
|
||||
const visibleTitleParts = createMemo(() => Locale.graphemes(visibleTitle()))
|
||||
const titleFades = createMemo(() => stringWidth(title()) >= titleWidth() && titleWidth() > FADE_WIDTH)
|
||||
const detail = createMemo(() => {
|
||||
if (tab === NEW_SESSION_TAB)
|
||||
return { project: Locale.takeWidth("Start a new session", titleWidth()), branch: undefined }
|
||||
if (tab === NEW_SESSION_TAB) return "Start a new session"
|
||||
const value = session()
|
||||
const projectLabel = projectName(project(), value?.location.directory) ?? ""
|
||||
const vcs = value ? data.location.vcs.info(value.location) : undefined
|
||||
const branch = sessionTabBranch(vcs?.branch.current, vcs?.branch.default)
|
||||
if (!branch) return { project: Locale.takeWidth(projectLabel, titleWidth()), branch: undefined }
|
||||
|
||||
const separatorWidth = projectLabel ? 1 : 0
|
||||
const branchWidth = Math.min(
|
||||
branch.length,
|
||||
Math.max(1, titleWidth() - Math.min(projectLabel.length, 12) - separatorWidth),
|
||||
)
|
||||
const projectWidth = Math.max(0, titleWidth() - branchWidth - separatorWidth)
|
||||
return {
|
||||
project: Locale.takeWidth(projectLabel, projectWidth),
|
||||
branch: Locale.truncateLeft(branch, branchWidth),
|
||||
}
|
||||
return sessionTabDetail(projectLabel, vcs?.branch.current, vcs?.branch.default)
|
||||
})
|
||||
const visibleDetail = createMemo(() => Locale.takeWidth(detail(), titleWidth()))
|
||||
const visibleDetailParts = createMemo(() => Locale.graphemes(visibleDetail()))
|
||||
const detailFades = createMemo(() => stringWidth(detail()) >= titleWidth() && titleWidth() > FADE_WIDTH)
|
||||
const background = createMemo(() => {
|
||||
if (selected()) return theme.background.action.primary.selected
|
||||
if (hovered() === tab.sessionID || dragging() === tab.sessionID)
|
||||
@@ -200,6 +190,11 @@ function VerticalSessionTabs(props: { controller?: SessionTabsController; animat
|
||||
const detailPulseColor = createMemo(() => tint(pulseBackground(), theme.text.default, 0.13))
|
||||
const detailGlowColor = createMemo(() => tint(pulseBackground(), glowHue(), 0.25))
|
||||
const detailColor = createMemo(() => tint(theme.text.subdued, pulseBackground(), 0.35))
|
||||
const detailTextColor = (index: number) => {
|
||||
if (!detailFades() || index < visibleDetailParts().length - FADE_WIDTH) return detailColor()
|
||||
const position = index - (visibleDetailParts().length - FADE_WIDTH)
|
||||
return tint(detailColor(), pulseBackground(), 0.2 + 0.72 * (position / Math.max(1, FADE_WIDTH - 1)))
|
||||
}
|
||||
const glows = () => status().glows
|
||||
const previous = createMemo(() => items()[index() - 1])
|
||||
const previousStatus = createMemo(() => {
|
||||
@@ -376,7 +371,11 @@ function VerticalSessionTabs(props: { controller?: SessionTabsController; animat
|
||||
/>
|
||||
<box zIndex={1} width="100%" flexDirection="row" paddingLeft={numberWidth() + 1} paddingRight={2}>
|
||||
<text fg={detailColor()} wrapMode="none" selectable={false}>
|
||||
{`${detail().project}${detail().project && detail().branch ? " " : ""}${detail().branch ?? ""}`}
|
||||
<Show when={detailFades()} fallback={visibleDetail()}>
|
||||
<For each={visibleDetailParts()}>
|
||||
{(character, index) => <span style={{ fg: detailTextColor(index()) }}>{character}</span>}
|
||||
</For>
|
||||
</Show>
|
||||
</text>
|
||||
</box>
|
||||
</box>
|
||||
|
||||
@@ -18,6 +18,11 @@ export function sessionTabBranch(current: string | undefined, defaultBranch: str
|
||||
return current
|
||||
}
|
||||
|
||||
export function sessionTabDetail(project: string, current: string | undefined, defaultBranch: string | undefined) {
|
||||
const branch = sessionTabBranch(current, defaultBranch)
|
||||
return branch && project ? `${project}:${branch}` : (branch ?? project)
|
||||
}
|
||||
|
||||
export type SessionTabHistory = {
|
||||
entries: readonly string[]
|
||||
index: number
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
seedSessionTabMotion,
|
||||
sessionTabComplete,
|
||||
sessionTabBranch,
|
||||
sessionTabDetail,
|
||||
sessionTabOverflowWidth,
|
||||
sessionTabShortcutLabel,
|
||||
} from "../../src/context/session-tabs-model"
|
||||
@@ -24,6 +25,11 @@ describe("session tabs", () => {
|
||||
expect(sessionTabBranch(undefined, "main")).toBeUndefined()
|
||||
})
|
||||
|
||||
test("separates the project and branch with a colon", () => {
|
||||
expect(sessionTabDetail("opencode", "feature/sidebar", "main")).toBe("opencode:feature/sidebar")
|
||||
expect(sessionTabDetail("opencode", "main", "main")).toBe("opencode")
|
||||
})
|
||||
|
||||
test("labels direct shortcut tabs and marks unbound tabs with a dot", () => {
|
||||
expect(Array.from({ length: 12 }, (_, index) => sessionTabShortcutLabel(index))).toEqual([
|
||||
"1",
|
||||
|
||||
Reference in New Issue
Block a user