diff --git a/packages/tui/src/component/dialog-config.tsx b/packages/tui/src/component/dialog-config.tsx index 751485b1ae..c66d5764cd 100644 --- a/packages/tui/src/component/dialog-config.tsx +++ b/packages/tui/src/component/dialog-config.tsx @@ -1,10 +1,10 @@ -import { TextAttributes, type ScrollBoxRenderable } from "@opentui/core" +import { TextAttributes } from "@opentui/core" import { useTerminalDimensions } from "@opentui/solid" -import { createMemo, createSignal, For, onMount, Show } from "solid-js" +import { createMemo, createSignal, onMount, Show } from "solid-js" import { useConfig } from "../config" import { useTheme } from "../context/theme" -import { useBindings } from "../keymap" import { useDialog } from "../ui/dialog" +import { DialogSelect } from "../ui/dialog-select" import { useToast } from "../ui/toast" type Setting = { @@ -249,9 +249,8 @@ export function DialogConfig() { const themeState = useTheme() const { theme } = themeState const dimensions = useTerminalDimensions() - const [selected, setSelected] = createSignal(0) + const [selected, setSelected] = createSignal(settings[0]) const [saving, setSaving] = createSignal(false) - let scroll: ScrollBoxRenderable | undefined onMount(() => { dialog.setSize("xlarge") dialog.setCentered(true) @@ -275,34 +274,19 @@ export function DialogConfig() { const index = setting.values?.indexOf(current) return index === undefined || index < 0 ? String(current) : (setting.labels?.[index] ?? String(current)) } - const rows = createMemo(() => - settings.map((setting, index) => ({ - setting, - index, - heading: index === 0 || settings[index - 1].category !== setting.category, + const options = createMemo(() => + settings.map((setting) => ({ + title: setting.title, + category: setting.category, + value: setting, + footer: selected() === setting ? `‹ ${display(setting)} ›` : ` ${display(setting)} `, })), ) const split = createMemo(() => dimensions().width >= 110) const height = createMemo(() => Math.max(8, Math.min(36, dimensions().height - 12))) - function move(direction: number) { - const next = (selected() + direction + settings.length) % settings.length - setSelected(next) - queueMicrotask(() => { - if (!scroll) return - const row = - next + - settings.slice(0, next + 1).filter((setting, index) => { - return index === 0 || settings[index - 1].category !== setting.category - }).length - if (row < scroll.scrollTop) scroll.scrollTo(row) - if (row >= scroll.scrollTop + scroll.viewport.height) scroll.scrollTo(row - scroll.viewport.height + 1) - }) - } - - async function change(direction: number) { + async function change(setting: Setting, direction: number) { if (saving()) return - const setting = settings[selected()] const current = value(setting) const choices = values(setting) const next = choices @@ -322,72 +306,22 @@ export function DialogConfig() { .finally(() => setSaving(false)) } - useBindings(() => ({ - bindings: [ - { - key: "up", - desc: "Previous setting", - group: "Settings", - cmd: () => move(-1), - }, - { - key: "down", - desc: "Next setting", - group: "Settings", - cmd: () => move(1), - }, - { key: "left", desc: "Previous value", group: "Settings", cmd: () => void change(-1) }, - { key: "right", desc: "Next value", group: "Settings", cmd: () => void change(1) }, - { key: "return", desc: "Next value", group: "Settings", cmd: () => void change(1) }, - ], - })) - return ( - - - Settings - - (scroll = element)} - flexGrow={1} - scrollbarOptions={{ visible: false }} - > - - {(row) => ( - <> - - - - {row.setting.category} - - - - - - {row.setting.title} - - - - {row.index === selected() ? "‹ " : " "} - - {display(row.setting)} - - {row.index === selected() ? " ›" : " "} - - - - - )} - - + + setSelected(option.value)} + onSelect={(option) => void change(option.value, 1)} + bindings={[ + { key: "left", desc: "Previous value", group: "Settings", cmd: () => void change(selected(), -1) }, + { key: "right", desc: "Next value", group: "Settings", cmd: () => void change(selected(), 1) }, + ]} + /> - {settings[selected()].title} + {selected().title} dialog.clear()}> esc @@ -410,7 +344,7 @@ export function DialogConfig() { - {settings[selected()].detail ?? settings[selected()].description} + {selected().detail ?? selected().description} diff --git a/packages/tui/src/ui/dialog-select.tsx b/packages/tui/src/ui/dialog-select.tsx index 78563bcb86..3b08f013ff 100644 --- a/packages/tui/src/ui/dialog-select.tsx +++ b/packages/tui/src/ui/dialog-select.tsx @@ -51,6 +51,8 @@ export interface DialogSelectProps { }[] bindings?: readonly Binding[] current?: T + hideClose?: boolean + maxHeight?: number } export interface DialogSelectOption { @@ -212,7 +214,7 @@ export function DialogSelect(props: DialogSelectProps) { }) const dimensions = useTerminalDimensions() - const height = createMemo(() => Math.min(rows(), Math.floor(dimensions().height / 2) - 6)) + const height = createMemo(() => Math.min(rows(), props.maxHeight ?? Math.floor(dimensions().height / 2) - 6)) const selected = createMemo(() => flat()[store.selected]) @@ -565,9 +567,11 @@ export function DialogSelect(props: DialogSelectProps) { {props.title} )} - dialog.clear()}> - esc - + + dialog.clear()}> + esc + + @@ -789,7 +793,11 @@ function Option(props: { - {props.footer} + {typeof props.footer === "string" ? ( + {props.footer} + ) : ( + props.footer + )}