tui: redesign tips display on home screen
This commit is contained in:
@@ -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>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -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",
|
"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})",
|
"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",
|
"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)",
|
"Set agent {highlight}temperature{/highlight} from 0.0 (focused) to 1.0 (creative)",
|
||||||
"Configure {highlight}maxSteps{/highlight} to limit agentic iterations per request",
|
"Configure {highlight}maxSteps{/highlight} to limit agentic iterations per request",
|
||||||
'Set {highlight}"tools": {"bash": false}{/highlight} to disable specific tools',
|
'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",
|
"Override global tool settings per agent configuration",
|
||||||
'Set {highlight}"share": "auto"{/highlight} to automatically share all sessions',
|
'Set {highlight}"share": "auto"{/highlight} to automatically share all sessions',
|
||||||
'Set {highlight}"share": "disabled"{/highlight} to prevent any session sharing',
|
'Set {highlight}"share": "disabled"{/highlight} to prevent any session sharing',
|
||||||
@@ -25,6 +25,9 @@ export const { use: useKV, provider: KVProvider } = createSimpleContext({
|
|||||||
get ready() {
|
get ready() {
|
||||||
return ready()
|
return ready()
|
||||||
},
|
},
|
||||||
|
get store() {
|
||||||
|
return kvStore
|
||||||
|
},
|
||||||
signal<T>(name: string, defaultValue: T) {
|
signal<T>(name: string, defaultValue: T) {
|
||||||
if (kvStore[name] === undefined) setKvStore(name, defaultValue)
|
if (kvStore[name] === undefined) setKvStore(name, defaultValue)
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { createMemo, Match, onMount, Show, Switch } from "solid-js"
|
|||||||
import { useTheme } from "@tui/context/theme"
|
import { useTheme } from "@tui/context/theme"
|
||||||
import { useKeybind } from "@tui/context/keybind"
|
import { useKeybind } from "@tui/context/keybind"
|
||||||
import { Logo } from "../component/logo"
|
import { Logo } from "../component/logo"
|
||||||
import { DidYouKnow, randomizeTip } from "../component/did-you-know"
|
import { Tips } from "../component/tips"
|
||||||
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"
|
||||||
@@ -77,7 +77,6 @@ export function Home() {
|
|||||||
let prompt: PromptRef
|
let prompt: PromptRef
|
||||||
const args = useArgs()
|
const args = useArgs()
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
randomizeTip()
|
|
||||||
if (once) return
|
if (once) return
|
||||||
if (route.initialPrompt) {
|
if (route.initialPrompt) {
|
||||||
prompt.set(route.initialPrompt)
|
prompt.set(route.initialPrompt)
|
||||||
@@ -105,23 +104,13 @@ export function Home() {
|
|||||||
hint={Hint}
|
hint={Hint}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
<Show when={!isFirstTimeUser()}>
|
<Show when={showTips()}>
|
||||||
<Show when={showTips()}>
|
<box width="100%" maxWidth={75} paddingTop={2} alignItems="center">
|
||||||
<box width="100%" maxWidth={75} paddingTop={3} alignItems="center">
|
<Tips />
|
||||||
<DidYouKnow />
|
</box>
|
||||||
</box>
|
|
||||||
</Show>
|
|
||||||
</Show>
|
</Show>
|
||||||
<Toast />
|
<Toast />
|
||||||
</box>
|
</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}>
|
<box paddingTop={1} paddingBottom={1} paddingLeft={2} paddingRight={2} flexDirection="row" flexShrink={0} gap={2}>
|
||||||
<text fg={theme.textMuted}>{directory()}</text>
|
<text fg={theme.textMuted}>{directory()}</text>
|
||||||
<box gap={1} flexDirection="row" flexShrink={0}>
|
<box gap={1} flexDirection="row" flexShrink={0}>
|
||||||
|
|||||||
Reference in New Issue
Block a user