Browse Source

fix(tui): pin dialog select footer to bottom (#29878)

Shoubhit Dash 3 months ago
parent
commit
7da2620078
1 changed files with 98 additions and 96 deletions
  1. 98 96
      packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx

+ 98 - 96
packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx

@@ -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}