fix(tui): pin dialog select footer to bottom (#29878)
Some checks are pending
deploy / deploy (push) Waiting to run
generate / generate (push) Waiting to run
nix-eval / nix-eval (push) Waiting to run
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404 platform_flag:--linux target:x86_64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-ubuntu-2404-arm platform_flag:--linux --arm64 target:aarch64-unknown-linux-gnu]) (push) Blocked by required conditions
publish / build-electron (map[host:blacksmith-4vcpu-windows-2025 platform_flag:--win target:x86_64-pc-windows-msvc]) (push) Blocked by required conditions
publish / build-electron (map[host:windows-2025 platform_flag:--win --arm64 target:aarch64-pc-windows-msvc]) (push) Blocked by required conditions
publish / publish (push) Blocked by required conditions
publish / sign-cli-windows (push) Blocked by required conditions
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=arm64 host:macos-26 platform_flag:--mac --arm64 target:aarch64-apple-darwin]) (push) Blocked by required conditions
publish / build-electron (map[bun_install_flags:--os=darwin --cpu=x64 host:macos-26-intel platform_flag:--mac --x64 target:x86_64-apple-darwin]) (push) Blocked by required conditions
publish / version (push) Waiting to run
publish / build-cli (push) Blocked by required conditions
test / unit (linux) (push) Waiting to run
test / unit (windows) (push) Waiting to run
test / e2e (linux) (push) Waiting to run
test / e2e (windows) (push) Waiting to run
typecheck / typecheck (push) Waiting to run

This commit is contained in:
Shoubhit Dash 2026-05-29 16:43:50 +05:30 committed by GitHub
parent 5764f19937
commit 7da2620078
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -354,7 +354,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
const right = createMemo(() => visibleActions().filter((item) => item.side === "right"))
return (
<box gap={1} paddingBottom={1}>
<box gap={1} paddingBottom={1} flexGrow={1}>
<box paddingLeft={4} paddingRight={4}>
<box flexDirection="row" justifyContent="space-between">
<text fg={theme.text} attributes={TextAttributes.BOLD}>
@ -391,106 +391,108 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
</box>
</Show>
</box>
<Show
when={grouped().length > 0}
fallback={
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
<text fg={theme.textMuted}>No results found</text>
</box>
}
>
<scrollbox
paddingLeft={1}
paddingRight={1}
scrollbarOptions={{ visible: false }}
scrollAcceleration={scrollAcceleration()}
ref={(r: ScrollBoxRenderable) => (scroll = r)}
maxHeight={height()}
<box flexGrow={1} flexShrink={1}>
<Show
when={grouped().length > 0}
fallback={
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
<text fg={theme.textMuted}>No results found</text>
</box>
}
>
<For each={grouped()}>
{([category, options], index) => (
<>
<Show when={category}>
<box paddingTop={index() > 0 ? 1 : 0} paddingLeft={3}>
<Show
when={options[0]?.categoryView}
fallback={
<text fg={theme.accent} attributes={TextAttributes.BOLD}>
{category}
</text>
}
>
{options[0]?.categoryView}
</Show>
</box>
</Show>
<For each={options}>
{(option) => {
const active = createMemo(() => isDeepEqual(option.value, selected()?.value))
const current = createMemo(() => isDeepEqual(option.value, props.current))
return (
<box
id={JSON.stringify(option.value)}
flexDirection="column"
position="relative"
onMouseMove={() => {
setStore("input", "mouse")
}}
onMouseUp={() => {
option.onSelect?.(dialog)
props.onSelect?.(option)
}}
onMouseOver={() => {
if (store.input !== "mouse") return
const index = flat().findIndex((x) => isDeepEqual(x.value, option.value))
if (index === -1) return
moveTo(index)
}}
onMouseDown={() => {
const index = flat().findIndex((x) => isDeepEqual(x.value, option.value))
if (index === -1) return
moveTo(index)
}}
<scrollbox
paddingLeft={1}
paddingRight={1}
scrollbarOptions={{ visible: false }}
scrollAcceleration={scrollAcceleration()}
ref={(r: ScrollBoxRenderable) => (scroll = r)}
maxHeight={height()}
>
<For each={grouped()}>
{([category, options], index) => (
<>
<Show when={category}>
<box paddingTop={index() > 0 ? 1 : 0} paddingLeft={3}>
<Show
when={options[0]?.categoryView}
fallback={
<text fg={theme.accent} attributes={TextAttributes.BOLD}>
{category}
</text>
}
>
{options[0]?.categoryView}
</Show>
</box>
</Show>
<For each={options}>
{(option) => {
const active = createMemo(() => isDeepEqual(option.value, selected()?.value))
const current = createMemo(() => isDeepEqual(option.value, props.current))
return (
<box
flexDirection="row"
paddingLeft={current() || option.gutter ? 1 : 3}
paddingRight={3}
gap={1}
backgroundColor={active() ? (option.bg ?? theme.primary) : RGBA.fromInts(0, 0, 0, 0)}
id={JSON.stringify(option.value)}
flexDirection="column"
position="relative"
onMouseMove={() => {
setStore("input", "mouse")
}}
onMouseUp={() => {
option.onSelect?.(dialog)
props.onSelect?.(option)
}}
onMouseOver={() => {
if (store.input !== "mouse") return
const index = flat().findIndex((x) => isDeepEqual(x.value, option.value))
if (index === -1) return
moveTo(index)
}}
onMouseDown={() => {
const index = flat().findIndex((x) => isDeepEqual(x.value, option.value))
if (index === -1) return
moveTo(index)
}}
>
<Show when={!current() && option.margin}>
<box position="absolute" left={1} flexShrink={0}>
{option.margin}
</box>
</Show>
<Option
title={option.title}
footer={flatten() ? (option.category ?? option.footer) : option.footer}
description={option.description !== category ? option.description : undefined}
active={active()}
current={current()}
gutter={option.gutter}
/>
<box
flexDirection="row"
paddingLeft={current() || option.gutter ? 1 : 3}
paddingRight={3}
gap={1}
backgroundColor={active() ? (option.bg ?? theme.primary) : RGBA.fromInts(0, 0, 0, 0)}
>
<Show when={!current() && option.margin}>
<box position="absolute" left={1} flexShrink={0}>
{option.margin}
</box>
</Show>
<Option
title={option.title}
footer={flatten() ? (option.category ?? option.footer) : option.footer}
description={option.description !== category ? option.description : undefined}
active={active()}
current={current()}
gutter={option.gutter}
/>
</box>
<For each={option.details}>
{(detail) => (
<box paddingLeft={3} paddingRight={3}>
<text fg={theme.textMuted} wrapMode="none">
{Locale.truncateMiddle(detail, Math.max(1, Math.min(76, dimensions().width - 12)))}
</text>
</box>
)}
</For>
</box>
<For each={option.details}>
{(detail) => (
<box paddingLeft={3} paddingRight={3}>
<text fg={theme.textMuted} wrapMode="none">
{Locale.truncateMiddle(detail, Math.max(1, Math.min(76, dimensions().width - 12)))}
</text>
</box>
)}
</For>
</box>
)
}}
</For>
</>
)}
</For>
</scrollbox>
</Show>
)
}}
</For>
</>
)}
</For>
</scrollbox>
</Show>
</box>
<Show when={visibleActions().length} fallback={<box flexShrink={0} />}>
<box
paddingRight={2}