feat(tui): add adaptive session tabs (#39396)

This commit is contained in:
Kit Langton 2026-07-28 17:12:07 -04:00 committed by GitHub
commit 37a1b80d5a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 1485 additions and 147 deletions

View file

@ -67,20 +67,30 @@ export function truncate(str: string, len: number): string {
const graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" })
export function graphemes(str: string) {
return Array.from(graphemeSegmenter.segment(str), (item) => item.segment)
}
export function takeWidth(str: string, width: number) {
if (width <= 0) return ""
if (stringWidth(str) <= width) return str
const result: string[] = []
let used = 0
for (const segment of graphemes(str)) {
const next = stringWidth(segment)
if (used + next > width) break
result.push(segment)
used += next
}
return result.join("")
}
export function truncateWidth(str: string, width: number): string {
if (width <= 0) return ""
if (stringWidth(str) <= width) return str
if (width === 1) return "…"
const result: string[] = []
let used = 0
for (const item of graphemeSegmenter.segment(str)) {
const next = stringWidth(item.segment)
if (used + next > width - 1) break
result.push(item.segment)
used += next
}
return result.join("") + "…"
return takeWidth(str, width - 1) + "…"
}
export function truncateLeft(str: string, len: number): string {

View file

@ -1,4 +1,5 @@
import { createEffect, createSignal, on, onCleanup, type Accessor } from "solid-js"
import { createAnimatable, tween } from "../ui/animation"
export function createDebouncedSignal<T>(value: T, ms: number): [Accessor<T>, (value: T) => void] {
const [get, set] = createSignal(value)
@ -17,35 +18,32 @@ export function createDebouncedSignal<T>(value: T, ms: number): [Accessor<T>, (v
}
export function createFadeIn(show: Accessor<boolean>, enabled: Accessor<boolean>) {
const [alpha, setAlpha] = createSignal(show() ? 1 : 0)
const alpha = createAnimatable(
{ value: show() ? 1 : 0 },
{
enabled,
transition: tween({ duration: 0.16 }),
},
)
let revealed = show()
createEffect(
on([show, enabled], ([visible, animate]) => {
if (!visible) {
setAlpha(0)
alpha.jump({ value: 0 })
return
}
if (!animate || revealed) {
revealed = true
setAlpha(1)
alpha.jump({ value: 1 })
return
}
const start = performance.now()
revealed = true
setAlpha(0)
const timer = setInterval(() => {
const progress = Math.min((performance.now() - start) / 160, 1)
setAlpha(progress * progress * (3 - 2 * progress))
if (progress >= 1) clearInterval(timer)
}, 16)
onCleanup(() => clearInterval(timer))
alpha.animate({ value: 1 })
}),
)
return alpha
return () => alpha.value().value
}