fix(app): sidebar truncation

This commit is contained in:
Adam
2026-03-24 13:04:32 -05:00
parent 539b01f20f
commit 42a773481e
+92 -87
View File
@@ -104,7 +104,7 @@ const SessionRow = (props: {
}): JSX.Element => ( }): JSX.Element => (
<A <A
href={`/${props.slug}/session/${props.session.id}`} href={`/${props.slug}/session/${props.session.id}`}
class={`flex items-center justify-between gap-3 min-w-0 text-left w-full focus:outline-none transition-[padding] ${props.mobile ? "pr-7" : ""} group-hover/session:pr-7 group-focus-within/session:pr-7 group-active/session:pr-7 ${props.dense ? "py-0.5" : "py-1"}`} class={`flex items-center gap-1 min-w-0 w-full text-left focus:outline-none ${props.dense ? "py-0.5" : "py-1"}`}
onPointerDown={props.warmPress} onPointerDown={props.warmPress}
onPointerEnter={props.warmHover} onPointerEnter={props.warmHover}
onPointerLeave={props.cancelHoverPrefetch} onPointerLeave={props.cancelHoverPrefetch}
@@ -115,30 +115,26 @@ const SessionRow = (props: {
props.clearHoverProjectSoon() props.clearHoverProjectSoon()
}} }}
> >
<div class="flex items-center gap-1 w-full"> <div
<div class="shrink-0 size-6 flex items-center justify-center"
class="shrink-0 size-6 flex items-center justify-center" style={{ color: props.tint() ?? "var(--icon-interactive-base)" }}
style={{ color: props.tint() ?? "var(--icon-interactive-base)" }} >
> <Switch fallback={<Icon name="dash" size="small" class="text-icon-weak" />}>
<Switch fallback={<Icon name="dash" size="small" class="text-icon-weak" />}> <Match when={props.isWorking()}>
<Match when={props.isWorking()}> <Spinner class="size-[15px]" />
<Spinner class="size-[15px]" /> </Match>
</Match> <Match when={props.hasPermissions()}>
<Match when={props.hasPermissions()}> <div class="size-1.5 rounded-full bg-surface-warning-strong" />
<div class="size-1.5 rounded-full bg-surface-warning-strong" /> </Match>
</Match> <Match when={props.hasError()}>
<Match when={props.hasError()}> <div class="size-1.5 rounded-full bg-text-diff-delete-base" />
<div class="size-1.5 rounded-full bg-text-diff-delete-base" /> </Match>
</Match> <Match when={props.unseenCount() > 0}>
<Match when={props.unseenCount() > 0}> <div class="size-1.5 rounded-full bg-text-interactive-base" />
<div class="size-1.5 rounded-full bg-text-interactive-base" /> </Match>
</Match> </Switch>
</Switch>
</div>
<span class="text-14-regular text-text-strong grow-1 min-w-0 overflow-hidden text-ellipsis truncate">
{props.session.title}
</span>
</div> </div>
<span class="text-14-regular text-text-strong min-w-0 flex-1 truncate">{props.session.title}</span>
</A> </A>
) )
@@ -167,7 +163,11 @@ const SessionHoverPreview = (props: {
placement="right-start" placement="right-start"
gutter={16} gutter={16}
shift={-2} shift={-2}
trigger={<div ref={ref}>{props.trigger}</div>} trigger={
<div ref={ref} class="min-w-0 w-full">
{props.trigger}
</div>
}
open={props.hoverSession() === props.session.id} open={props.hoverSession() === props.session.id}
onOpenChange={(open) => { onOpenChange={(open) => {
if (!open) { if (!open) {
@@ -309,62 +309,71 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => {
return ( return (
<div <div
data-session-id={props.session.id} data-session-id={props.session.id}
class="group/session relative w-full rounded-md cursor-default pl-2 pr-3 transition-colors class="group/session relative w-full min-w-0 rounded-md cursor-default pl-2 pr-3 transition-colors
hover:bg-surface-raised-base-hover [&:has(:focus-visible)]:bg-surface-raised-base-hover has-[[data-expanded]]:bg-surface-raised-base-hover has-[.active]:bg-surface-base-active" hover:bg-surface-raised-base-hover [&:has(:focus-visible)]:bg-surface-raised-base-hover has-[[data-expanded]]:bg-surface-raised-base-hover has-[.active]:bg-surface-base-active"
> >
<Show <div class="flex min-w-0 items-center gap-1">
when={hoverEnabled()} <div class="min-w-0 flex-1">
fallback={ <Show
<Tooltip placement={props.mobile ? "bottom" : "right"} value={props.session.title} gutter={10}> when={hoverEnabled()}
{item} fallback={
</Tooltip> <Tooltip
} placement={props.mobile ? "bottom" : "right"}
> value={props.session.title}
<SessionHoverPreview gutter={10}
mobile={props.mobile} class="min-w-0 w-full"
nav={props.nav} >
hoverSession={props.hoverSession} {item}
session={props.session} </Tooltip>
sidebarHovering={props.sidebarHovering} }
hoverReady={hoverReady} >
hoverMessages={hoverMessages} <SessionHoverPreview
language={language} mobile={props.mobile}
isActive={isActive} nav={props.nav}
slug={props.slug} hoverSession={props.hoverSession}
setHoverSession={props.setHoverSession} session={props.session}
messageLabel={messageLabel} sidebarHovering={props.sidebarHovering}
onMessageSelect={(message) => { hoverReady={hoverReady}
if (!isActive()) hoverMessages={hoverMessages}
layout.pendingMessage.set(`${base64Encode(props.session.directory)}/${props.session.id}`, message.id) language={language}
isActive={isActive}
slug={props.slug}
setHoverSession={props.setHoverSession}
messageLabel={messageLabel}
onMessageSelect={(message) => {
if (!isActive())
layout.pendingMessage.set(`${base64Encode(props.session.directory)}/${props.session.id}`, message.id)
navigate(`${props.slug}/session/${props.session.id}#message-${message.id}`) navigate(`${props.slug}/session/${props.session.id}#message-${message.id}`)
}}
trigger={item}
/>
</Show>
</div>
<div
class="shrink-0 overflow-hidden transition-[width,opacity]"
classList={{
"w-6 opacity-100 pointer-events-auto": !!props.mobile,
"w-0 opacity-0 pointer-events-none": !props.mobile,
"group-hover/session:w-6 group-hover/session:opacity-100 group-hover/session:pointer-events-auto": true,
"group-focus-within/session:w-6 group-focus-within/session:opacity-100 group-focus-within/session:pointer-events-auto": true,
}} }}
trigger={item} >
/> <Tooltip value={language.t("common.archive")} placement="top">
</Show> <IconButton
icon="archive"
<div variant="ghost"
class={`absolute ${props.dense ? "top-0.5 right-0.5" : "top-1 right-1"} flex items-center gap-0.5 transition-opacity`} class="size-6 rounded-md"
classList={{ aria-label={language.t("common.archive")}
"opacity-100 pointer-events-auto": !!props.mobile, onClick={(event) => {
"opacity-0 pointer-events-none": !props.mobile, event.preventDefault()
"group-hover/session:opacity-100 group-hover/session:pointer-events-auto": true, event.stopPropagation()
"group-focus-within/session:opacity-100 group-focus-within/session:pointer-events-auto": true, void props.archiveSession(props.session)
}} }}
> />
<Tooltip value={language.t("common.archive")} placement="top"> </Tooltip>
<IconButton </div>
icon="archive"
variant="ghost"
class="size-6 rounded-md"
aria-label={language.t("common.archive")}
onClick={(event) => {
event.preventDefault()
event.stopPropagation()
void props.archiveSession(props.session)
}}
/>
</Tooltip>
</div> </div>
</div> </div>
) )
@@ -386,30 +395,26 @@ export const NewSessionItem = (props: {
<A <A
href={`/${props.slug}/session`} href={`/${props.slug}/session`}
end end
class={`flex items-center justify-between gap-3 min-w-0 text-left w-full focus:outline-none ${props.dense ? "py-0.5" : "py-1"}`} class={`flex items-center gap-1 min-w-0 w-full text-left focus:outline-none ${props.dense ? "py-0.5" : "py-1"}`}
onClick={() => { onClick={() => {
props.setHoverSession(undefined) props.setHoverSession(undefined)
if (layout.sidebar.opened()) return if (layout.sidebar.opened()) return
props.clearHoverProjectSoon() props.clearHoverProjectSoon()
}} }}
> >
<div class="flex items-center gap-1 w-full"> <div class="shrink-0 size-6 flex items-center justify-center">
<div class="shrink-0 size-6 flex items-center justify-center"> <Icon name="new-session" size="small" class="text-icon-weak" />
<Icon name="new-session" size="small" class="text-icon-weak" />
</div>
<span class="text-14-regular text-text-strong grow-1 min-w-0 overflow-hidden text-ellipsis truncate">
{label}
</span>
</div> </div>
<span class="text-14-regular text-text-strong min-w-0 flex-1 truncate">{label}</span>
</A> </A>
) )
return ( return (
<div class="group/session relative w-full rounded-md cursor-default transition-colors pl-2 pr-3 hover:bg-surface-raised-base-hover [&:has(:focus-visible)]:bg-surface-raised-base-hover has-[.active]:bg-surface-base-active"> <div class="group/session relative w-full min-w-0 rounded-md cursor-default transition-colors pl-2 pr-3 hover:bg-surface-raised-base-hover [&:has(:focus-visible)]:bg-surface-raised-base-hover has-[.active]:bg-surface-base-active">
<Show <Show
when={!tooltip()} when={!tooltip()}
fallback={ fallback={
<Tooltip placement={props.mobile ? "bottom" : "right"} value={label} gutter={10}> <Tooltip placement={props.mobile ? "bottom" : "right"} value={label} gutter={10} class="min-w-0 w-full">
{item} {item}
</Tooltip> </Tooltip>
} }