mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-20 01:04:22 +01:00
tui: fix focus management and dialog interactions
This commit is contained in:
@@ -125,10 +125,8 @@ if (!Script.preview) {
|
|||||||
"build() {",
|
"build() {",
|
||||||
` cd "opencode-\${pkgver}"`,
|
` cd "opencode-\${pkgver}"`,
|
||||||
` bun install`,
|
` bun install`,
|
||||||
" cd packages/tui",
|
" cd ./packages/opencode",
|
||||||
` CGO_ENABLED=0 go build -ldflags="-s -w -X main.Version=\${pkgver}" -o tui cmd/opencode/main.go`,
|
` OPENCODE_CHANNEL=latest OPENCODE_VERSION=${pkgver} bun run ./script/build.ts --single`,
|
||||||
" cd ../opencode",
|
|
||||||
` bun build --define OPENCODE_TUI_PATH="'$(realpath ../tui/tui)'" --define OPENCODE_VERSION="'\${pkgver}'" --compile --target=bun-linux-x64 --outfile=opencode ./src/index.ts`,
|
|
||||||
"}",
|
"}",
|
||||||
"",
|
"",
|
||||||
"package() {",
|
"package() {",
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ export function Prompt(props: PromptProps) {
|
|||||||
keybind: "input_submit",
|
keybind: "input_submit",
|
||||||
category: "Prompt",
|
category: "Prompt",
|
||||||
onSelect: (dialog) => {
|
onSelect: (dialog) => {
|
||||||
|
if (!input.focused) return
|
||||||
submit()
|
submit()
|
||||||
dialog.clear()
|
dialog.clear()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Prompt, type PromptRef } from "@tui/component/prompt"
|
import { Prompt } from "@tui/component/prompt"
|
||||||
import { createEffect, createMemo, Match, Show, Switch, type ParentProps } from "solid-js"
|
import { createMemo, Match, Show, Switch, type ParentProps } from "solid-js"
|
||||||
import { useTheme } from "@tui/context/theme"
|
import { useTheme } from "@tui/context/theme"
|
||||||
import { useKeybind } from "../context/keybind"
|
import { useKeybind } from "../context/keybind"
|
||||||
import type { KeybindsConfig } from "@opencode-ai/sdk"
|
import type { KeybindsConfig } from "@opencode-ai/sdk"
|
||||||
@@ -7,22 +7,13 @@ import { Logo } from "../component/logo"
|
|||||||
import { Locale } from "@/util/locale"
|
import { Locale } from "@/util/locale"
|
||||||
import { useSync } from "../context/sync"
|
import { useSync } from "../context/sync"
|
||||||
import { Toast } from "../ui/toast"
|
import { Toast } from "../ui/toast"
|
||||||
import { useDialog } from "../ui/dialog"
|
|
||||||
|
|
||||||
export function Home() {
|
export function Home() {
|
||||||
const sync = useSync()
|
const sync = useSync()
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const dialog = useDialog()
|
|
||||||
const mcpError = createMemo(() => {
|
const mcpError = createMemo(() => {
|
||||||
return Object.values(sync.data.mcp).some((x) => x.status === "failed")
|
return Object.values(sync.data.mcp).some((x) => x.status === "failed")
|
||||||
})
|
})
|
||||||
let promptRef: PromptRef | undefined = undefined
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
dialog.allClosedEvent.listen(() => {
|
|
||||||
promptRef?.focus()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const Hint = (
|
const Hint = (
|
||||||
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
||||||
@@ -64,7 +55,7 @@ export function Home() {
|
|||||||
<HelpRow keybind="agent_cycle">Switch agent</HelpRow>
|
<HelpRow keybind="agent_cycle">Switch agent</HelpRow>
|
||||||
</box>
|
</box>
|
||||||
<box width="100%" maxWidth={75} zIndex={1000} paddingTop={1}>
|
<box width="100%" maxWidth={75} zIndex={1000} paddingTop={1}>
|
||||||
<Prompt hint={Hint} ref={(r) => (promptRef = r)} />
|
<Prompt hint={Hint} />
|
||||||
</box>
|
</box>
|
||||||
<Toast />
|
<Toast />
|
||||||
</box>
|
</box>
|
||||||
|
|||||||
@@ -112,12 +112,6 @@ export function Session() {
|
|||||||
let prompt: PromptRef
|
let prompt: PromptRef
|
||||||
const keybind = useKeybind()
|
const keybind = useKeybind()
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
dialog.allClosedEvent.listen(() => {
|
|
||||||
prompt.focus()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
useKeyboard((evt) => {
|
useKeyboard((evt) => {
|
||||||
if (dialog.stack.length > 0) return
|
if (dialog.stack.length > 0) return
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|||||||
if (evt.name === "return") {
|
if (evt.name === "return") {
|
||||||
const option = selected()
|
const option = selected()
|
||||||
if (option) {
|
if (option) {
|
||||||
evt.preventDefault()
|
// evt.preventDefault()
|
||||||
if (option.onSelect) option.onSelect(dialog)
|
if (option.onSelect) option.onSelect(dialog)
|
||||||
props.onSelect?.(option)
|
props.onSelect?.(option)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
import { useKeyboard, useRenderer, useTerminalDimensions } from "@opentui/solid"
|
import { useKeyboard, useRenderer, useTerminalDimensions } from "@opentui/solid"
|
||||||
import {
|
import { batch, createContext, Show, useContext, type JSX, type ParentProps } from "solid-js"
|
||||||
batch,
|
|
||||||
createContext,
|
|
||||||
createEffect,
|
|
||||||
Show,
|
|
||||||
useContext,
|
|
||||||
type JSX,
|
|
||||||
type ParentProps,
|
|
||||||
} from "solid-js"
|
|
||||||
import { useTheme } from "@tui/context/theme"
|
import { useTheme } from "@tui/context/theme"
|
||||||
import { Renderable, RGBA } from "@opentui/core"
|
import { Renderable, RGBA } from "@opentui/core"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { createEventBus } from "@solid-primitives/event-bus"
|
|
||||||
|
|
||||||
export function Dialog(
|
export function Dialog(
|
||||||
props: ParentProps<{
|
props: ParentProps<{
|
||||||
@@ -59,7 +50,6 @@ function init() {
|
|||||||
}[],
|
}[],
|
||||||
size: "medium" as "medium" | "large",
|
size: "medium" as "medium" | "large",
|
||||||
})
|
})
|
||||||
const allClosedEvent = createEventBus<void>()
|
|
||||||
|
|
||||||
useKeyboard((evt) => {
|
useKeyboard((evt) => {
|
||||||
if (evt.name === "escape" && store.stack.length > 0) {
|
if (evt.name === "escape" && store.stack.length > 0) {
|
||||||
@@ -90,12 +80,6 @@ function init() {
|
|||||||
}, 1)
|
}, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
if (store.stack.length === 0) {
|
|
||||||
allClosedEvent.emit()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
clear() {
|
clear() {
|
||||||
for (const item of store.stack) {
|
for (const item of store.stack) {
|
||||||
@@ -108,7 +92,9 @@ function init() {
|
|||||||
refocus()
|
refocus()
|
||||||
},
|
},
|
||||||
replace(input: any, onClose?: () => void) {
|
replace(input: any, onClose?: () => void) {
|
||||||
if (store.stack.length === 0) focus = renderer.currentFocusedRenderable
|
if (store.stack.length === 0) {
|
||||||
|
focus = renderer.currentFocusedRenderable
|
||||||
|
}
|
||||||
for (const item of store.stack) {
|
for (const item of store.stack) {
|
||||||
if (item.onClose) item.onClose()
|
if (item.onClose) item.onClose()
|
||||||
}
|
}
|
||||||
@@ -129,9 +115,6 @@ function init() {
|
|||||||
setSize(size: "medium" | "large") {
|
setSize(size: "medium" | "large") {
|
||||||
setStore("size", size)
|
setStore("size", size)
|
||||||
},
|
},
|
||||||
get allClosedEvent() {
|
|
||||||
return allClosedEvent
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const CHANNEL =
|
|||||||
(await $`git branch --show-current`.text().then((x) => x.trim()))
|
(await $`git branch --show-current`.text().then((x) => x.trim()))
|
||||||
const IS_PREVIEW = CHANNEL !== "latest"
|
const IS_PREVIEW = CHANNEL !== "latest"
|
||||||
const VERSION = await (async () => {
|
const VERSION = await (async () => {
|
||||||
|
if (process.env["OPENCODE_VERSION"]) return process.env["OPENCODE_VERSION"]
|
||||||
if (IS_PREVIEW)
|
if (IS_PREVIEW)
|
||||||
return `0.0.0-${CHANNEL}-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}`
|
return `0.0.0-${CHANNEL}-${new Date().toISOString().slice(0, 16).replace(/[-:T]/g, "")}`
|
||||||
const version = await fetch("https://registry.npmjs.org/opencode-ai/latest")
|
const version = await fetch("https://registry.npmjs.org/opencode-ai/latest")
|
||||||
|
|||||||
Reference in New Issue
Block a user