Explorar el Código

tui: redesign tips display on home screen

Dax Raad hace 1 mes
padre
commit
547a975707

+ 0 - 51
packages/opencode/src/cli/cmd/tui/component/did-you-know.tsx

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

+ 49 - 2
packages/opencode/src/cli/cmd/tui/component/tips.ts → 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',

+ 3 - 0
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 [

+ 5 - 16
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}>