summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2026-01-12 09:42:28 -0500
committerDax Raad <[email protected]>2026-01-12 09:42:28 -0500
commit547a975707c16253edf03c2d6ec30f8e499c83ad (patch)
tree85f5d167ebdab6759ffd2c498b6ac8f2a10f3c33
parentc009cab15b0590aeadb5030661af348bae75b1ea (diff)
downloadopencode-547a975707c16253edf03c2d6ec30f8e499c83ad.tar.gz
opencode-547a975707c16253edf03c2d6ec30f8e499c83ad.zip
tui: redesign tips display on home screen
-rw-r--r--packages/opencode/src/cli/cmd/tui/component/did-you-know.tsx51
-rw-r--r--packages/opencode/src/cli/cmd/tui/component/tips.tsx (renamed from packages/opencode/src/cli/cmd/tui/component/tips.ts)51
-rw-r--r--packages/opencode/src/cli/cmd/tui/context/kv.tsx3
-rw-r--r--packages/opencode/src/cli/cmd/tui/routes/home.tsx21
4 files changed, 57 insertions, 69 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/component/did-you-know.tsx b/packages/opencode/src/cli/cmd/tui/component/did-you-know.tsx
deleted file mode 100644
index 10042d938..000000000
--- a/packages/opencode/src/cli/cmd/tui/component/did-you-know.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { createMemo, createSignal, For } from "solid-js"
-import { useTheme } from "@tui/context/theme"
-import { TIPS } from "./tips"
-
-type TipPart = { text: string; highlight: boolean }
-
-function parseTip(tip: string): TipPart[] {
- const parts: TipPart[] = []
- const regex = /\{highlight\}(.*?)\{\/highlight\}/g
- let lastIndex = 0
- let match
-
- while ((match = regex.exec(tip)) !== null) {
- if (match.index > lastIndex) {
- parts.push({ text: tip.slice(lastIndex, match.index), highlight: false })
- }
- parts.push({ text: match[1], highlight: true })
- lastIndex = regex.lastIndex
- }
-
- if (lastIndex < tip.length) {
- parts.push({ text: tip.slice(lastIndex), highlight: false })
- }
-
- return parts
-}
-
-const [tipIndex, setTipIndex] = createSignal(Math.floor(Math.random() * TIPS.length))
-
-export function randomizeTip() {
- setTipIndex(Math.floor(Math.random() * TIPS.length))
-}
-
-export function DidYouKnow() {
- const { theme } = useTheme()
-
- const tipParts = createMemo(() => parseTip(TIPS[tipIndex()]))
-
- return (
- <box flexDirection="row" maxWidth="100%">
- <text flexShrink={0} style={{ fg: theme.warning }}>
- ● Tip{" "}
- </text>
- <text flexShrink={1}>
- <For each={tipParts()}>
- {(part) => <span style={{ fg: part.highlight ? theme.text : theme.textMuted }}>{part.text}</span>}
- </For>
- </text>
- </box>
- )
-}
diff --git a/packages/opencode/src/cli/cmd/tui/component/tips.ts b/packages/opencode/src/cli/cmd/tui/component/tips.tsx
index 24e0913e9..18d3c2df1 100644
--- a/packages/opencode/src/cli/cmd/tui/component/tips.ts
+++ b/packages/opencode/src/cli/cmd/tui/component/tips.tsx
@@ -1,4 +1,51 @@
-export const TIPS = [
+import { createMemo, createSignal, For } from "solid-js"
+import { useTheme } from "@tui/context/theme"
+
+type TipPart = { text: string; highlight: boolean }
+
+function parse(tip: string): TipPart[] {
+ const parts: TipPart[] = []
+ const regex = /\{highlight\}(.*?)\{\/highlight\}/g
+ const found = Array.from(tip.matchAll(regex))
+ const state = found.reduce(
+ (acc, match) => {
+ const start = match.index ?? 0
+ if (start > acc.index) {
+ acc.parts.push({ text: tip.slice(acc.index, start), highlight: false })
+ }
+ acc.parts.push({ text: match[1], highlight: true })
+ acc.index = start + match[0].length
+ return acc
+ },
+ { parts, index: 0 },
+ )
+
+ if (state.index < tip.length) {
+ parts.push({ text: tip.slice(state.index), highlight: false })
+ }
+
+ return parts
+}
+
+export function Tips() {
+ const theme = useTheme().theme
+ const parts = parse(TIPS[Math.floor(Math.random() * TIPS.length)])
+
+ return (
+ <box flexDirection="row" maxWidth="100%">
+ <text flexShrink={0} style={{ fg: theme.warning }}>
+ ● Tip{" "}
+ </text>
+ <text flexShrink={1}>
+ <For each={parts}>
+ {(part) => <span style={{ fg: part.highlight ? theme.text : theme.textMuted }}>{part.text}</span>}
+ </For>
+ </text>
+ </box>
+ )
+}
+
+const TIPS = [
"Type {highlight}@{/highlight} followed by a filename to fuzzy search and attach files",
"Start a message with {highlight}!{/highlight} to run shell commands directly (e.g., {highlight}!ls -la{/highlight})",
"Press {highlight}Tab{/highlight} to cycle between Build and Plan agents",
@@ -78,7 +125,7 @@ export const TIPS = [
"Set agent {highlight}temperature{/highlight} from 0.0 (focused) to 1.0 (creative)",
"Configure {highlight}maxSteps{/highlight} to limit agentic iterations per request",
'Set {highlight}"tools": {"bash": false}{/highlight} to disable specific tools',
- 'Use {highlight}"mcp_*": false{/highlight} to disable all tools from an MCP server',
+ 'Set {highlight}"mcp_*": false{/highlight} to disable all tools from an MCP server',
"Override global tool settings per agent configuration",
'Set {highlight}"share": "auto"{/highlight} to automatically share all sessions',
'Set {highlight}"share": "disabled"{/highlight} to prevent any session sharing',
diff --git a/packages/opencode/src/cli/cmd/tui/context/kv.tsx b/packages/opencode/src/cli/cmd/tui/context/kv.tsx
index e0844ba5a..93f469afa 100644
--- a/packages/opencode/src/cli/cmd/tui/context/kv.tsx
+++ b/packages/opencode/src/cli/cmd/tui/context/kv.tsx
@@ -25,6 +25,9 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({
get ready() {
return ready()
},
+ get store() {
+ return kvStore
+ },
signal<T>(name: string, defaultValue: T) {
if (kvStore[name] === undefined) setKvStore(name, defaultValue)
return [
diff --git a/packages/opencode/src/cli/cmd/tui/routes/home.tsx b/packages/opencode/src/cli/cmd/tui/routes/home.tsx
index e5ce80efc..6b4ab3354 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/home.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/home.tsx
@@ -3,7 +3,7 @@ import { createMemo, Match, onMount, Show, Switch } from "solid-js"
import { useTheme } from "@tui/context/theme"
import { useKeybind } from "@tui/context/keybind"
import { Logo } from "../component/logo"
-import { DidYouKnow, randomizeTip } from "../component/did-you-know"
+import { Tips } from "../component/tips"
import { Locale } from "@/util/locale"
import { useSync } from "../context/sync"
import { Toast } from "../ui/toast"
@@ -77,7 +77,6 @@ export function Home() {
let prompt: PromptRef
const args = useArgs()
onMount(() => {
- randomizeTip()
if (once) return
if (route.initialPrompt) {
prompt.set(route.initialPrompt)
@@ -105,23 +104,13 @@ export function Home() {
hint={Hint}
/>
</box>
- <Show when={!isFirstTimeUser()}>
- <Show when={showTips()}>
- <box width="100%" maxWidth={75} paddingTop={3} alignItems="center">
- <DidYouKnow />
- </box>
- </Show>
+ <Show when={showTips()}>
+ <box width="100%" maxWidth={75} paddingTop={2} alignItems="center">
+ <Tips />
+ </box>
</Show>
<Toast />
</box>
- <Show when={showTips()}>
- <box position="absolute" bottom={2} right={2}>
- <text>
- <span style={{ fg: theme.text }}>{keybind.print("tips_toggle")}</span>
- <span style={{ fg: theme.textMuted }}> Hide tips</span>
- </text>
- </box>
- </Show>
<box paddingTop={1} paddingBottom={1} paddingLeft={2} paddingRight={2} flexDirection="row" flexShrink={0} gap={2}>
<text fg={theme.textMuted}>{directory()}</text>
<box gap={1} flexDirection="row" flexShrink={0}>