Redesign tips display on home screen (#6126)

Co-authored-by: Dax <mail@thdxr.com>
This commit is contained in:
David Hill
2026-01-12 14:31:36 +00:00
committed by GitHub
parent e6bc3b253b
commit c009cab15b
3 changed files with 126 additions and 148 deletions

View File

@@ -1,8 +1,6 @@
import { createMemo, createSignal, For } from "solid-js" import { createMemo, createSignal, For } from "solid-js"
import { useTheme } from "@tui/context/theme" import { useTheme } from "@tui/context/theme"
import { useKeybind } from "@tui/context/keybind"
import { TIPS } from "./tips" import { TIPS } from "./tips"
import { EmptyBorder } from "./border"
type TipPart = { text: string; highlight: boolean } type TipPart = { text: string; highlight: boolean }
@@ -33,53 +31,21 @@ export function randomizeTip() {
setTipIndex(Math.floor(Math.random() * TIPS.length)) setTipIndex(Math.floor(Math.random() * TIPS.length))
} }
const BOX_WIDTH = 42
const TITLE = " 🅘 Did you know? "
export function DidYouKnow() { export function DidYouKnow() {
const { theme } = useTheme() const { theme } = useTheme()
const keybind = useKeybind()
const tipParts = createMemo(() => parseTip(TIPS[tipIndex()])) const tipParts = createMemo(() => parseTip(TIPS[tipIndex()]))
const dashes = createMemo(() => {
// ╭─ + title + ─...─ + ╮ = BOX_WIDTH
// 1 + 1 + title.length + dashes + 1 = BOX_WIDTH
return Math.max(0, BOX_WIDTH - 2 - TITLE.length - 1)
})
return ( return (
<box position="absolute" bottom={3} right={2} width={BOX_WIDTH}> <box flexDirection="row" maxWidth="100%">
<text> <text flexShrink={0} style={{ fg: theme.warning }}>
<span style={{ fg: theme.border }}></span> Tip{" "}
<span style={{ fg: theme.text }}>{TITLE}</span> </text>
<span style={{ fg: theme.border }}>{"─".repeat(dashes())}</span> <text flexShrink={1}>
<For each={tipParts()}>
{(part) => <span style={{ fg: part.highlight ? theme.text : theme.textMuted }}>{part.text}</span>}
</For>
</text> </text>
<box
border={["left", "right", "bottom"]}
borderColor={theme.border}
customBorderChars={{
...EmptyBorder,
bottomLeft: "╰",
bottomRight: "╯",
horizontal: "─",
vertical: "│",
}}
>
<box paddingLeft={2} paddingRight={2} paddingTop={1} paddingBottom={1}>
<text>
<For each={tipParts()}>
{(part) => <span style={{ fg: part.highlight ? theme.text : theme.textMuted }}>{part.text}</span>}
</For>
</text>
</box>
</box>
<box flexDirection="row" justifyContent="flex-end">
<text>
<span style={{ fg: theme.text }}>{keybind.print("tips_toggle")}</span>
<span style={{ fg: theme.textMuted }}> hide tips</span>
</text>
</box>
</box> </box>
) )
} }

View File

@@ -1,103 +1,103 @@
export const TIPS = [ export const TIPS = [
"Type {highlight}@{/highlight} followed by a filename to fuzzy search and attach files to your prompt.", "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 (full access) and Plan (read-only) agents.", "Press {highlight}Tab{/highlight} to cycle between Build and Plan agents",
"Use {highlight}/undo{/highlight} to revert the last message and any file changes made by OpenCode.", "Use {highlight}/undo{/highlight} to revert the last message and file changes",
"Use {highlight}/redo{/highlight} to restore previously undone messages and file changes.", "Use {highlight}/redo{/highlight} to restore previously undone messages and file changes",
"Run {highlight}/share{/highlight} to create a public link to your conversation at opencode.ai.", "Run {highlight}/share{/highlight} to create a public link to your conversation at opencode.ai",
"Drag and drop images into the terminal to add them as context for your prompts.", "Drag and drop images into the terminal to add them as context",
"Press {highlight}Ctrl+V{/highlight} to paste images from your clipboard directly into the prompt.", "Press {highlight}Ctrl+V{/highlight} to paste images from your clipboard into the prompt",
"Press {highlight}Ctrl+X E{/highlight} or {highlight}/editor{/highlight} to compose messages in your external editor.", "Press {highlight}Ctrl+X E{/highlight} or {highlight}/editor{/highlight} to compose messages in your external editor",
"Run {highlight}/init{/highlight} to auto-generate project rules based on your codebase structure.", "Run {highlight}/init{/highlight} to auto-generate project rules based on your codebase",
"Run {highlight}/models{/highlight} or {highlight}Ctrl+X M{/highlight} to see and switch between available AI models.", "Run {highlight}/models{/highlight} or {highlight}Ctrl+X M{/highlight} to see and switch between available AI models",
"Use {highlight}/theme{/highlight} or {highlight}Ctrl+X T{/highlight} to preview and switch between 50+ built-in themes.", "Use {highlight}/theme{/highlight} or {highlight}Ctrl+X T{/highlight} to switch between 50+ built-in themes",
"Press {highlight}Ctrl+X N{/highlight} or {highlight}/new{/highlight} to start a fresh conversation session.", "Press {highlight}Ctrl+X N{/highlight} or {highlight}/new{/highlight} to start a fresh conversation session",
"Use {highlight}/sessions{/highlight} or {highlight}Ctrl+X L{/highlight} to list and continue previous conversations.", "Use {highlight}/sessions{/highlight} or {highlight}Ctrl+X L{/highlight} to list and continue previous conversations",
"Run {highlight}/compact{/highlight} to summarize long sessions when approaching context limits.", "Run {highlight}/compact{/highlight} to summarize long sessions near context limits",
"Press {highlight}Ctrl+X X{/highlight} or {highlight}/export{/highlight} to save the conversation as Markdown.", "Press {highlight}Ctrl+X X{/highlight} or {highlight}/export{/highlight} to save the conversation as Markdown",
"Press {highlight}Ctrl+X Y{/highlight} to copy the assistant's last message to clipboard.", "Press {highlight}Ctrl+X Y{/highlight} to copy the assistant's last message to clipboard",
"Press {highlight}Ctrl+P{/highlight} to see all available actions and commands.", "Press {highlight}Ctrl+P{/highlight} to see all available actions and commands",
"Run {highlight}/connect{/highlight} to add API keys for 75+ supported LLM providers.", "Run {highlight}/connect{/highlight} to add API keys for 75+ supported LLM providers",
"The default leader key is {highlight}Ctrl+X{/highlight}; combine with other keys for quick actions.", "The leader key is {highlight}Ctrl+X{/highlight}; combine with other keys for quick actions",
"Press {highlight}F2{/highlight} to quickly switch between recently used models.", "Press {highlight}F2{/highlight} to quickly switch between recently used models",
"Press {highlight}Ctrl+X B{/highlight} to show/hide the sidebar panel.", "Press {highlight}Ctrl+X B{/highlight} to show/hide the sidebar panel",
"Use {highlight}PageUp{/highlight}/{highlight}PageDown{/highlight} to navigate through conversation history.", "Use {highlight}PageUp{/highlight}/{highlight}PageDown{/highlight} to navigate through conversation history",
"Press {highlight}Ctrl+G{/highlight} or {highlight}Home{/highlight} to jump to the beginning of the conversation.", "Press {highlight}Ctrl+G{/highlight} or {highlight}Home{/highlight} to jump to the beginning of the conversation",
"Press {highlight}Ctrl+Alt+G{/highlight} or {highlight}End{/highlight} to jump to the most recent message.", "Press {highlight}Ctrl+Alt+G{/highlight} or {highlight}End{/highlight} to jump to the most recent message",
"Press {highlight}Shift+Enter{/highlight} or {highlight}Ctrl+J{/highlight} to add newlines in your prompt.", "Press {highlight}Shift+Enter{/highlight} or {highlight}Ctrl+J{/highlight} to add newlines in your prompt",
"Press {highlight}Ctrl+C{/highlight} when typing to clear the input field.", "Press {highlight}Ctrl+C{/highlight} when typing to clear the input field",
"Press {highlight}Escape{/highlight} to stop the AI mid-response.", "Press {highlight}Escape{/highlight} to stop the AI mid-response",
"Switch to {highlight}Plan{/highlight} agent to get suggestions without making actual changes.", "Switch to {highlight}Plan{/highlight} agent to get suggestions without making actual changes",
"Use {highlight}@<agent-name>{/highlight} in prompts to invoke specialized subagents.", "Use {highlight}@agent-name{/highlight} in prompts to invoke specialized subagents",
"Press {highlight}Ctrl+X Right/Left{/highlight} to cycle through parent and child sessions.", "Press {highlight}Ctrl+X Right/Left{/highlight} to cycle through parent and child sessions",
"Create {highlight}opencode.json{/highlight} in project root for project-specific settings.", "Create {highlight}opencode.json{/highlight} in project root for project-specific settings",
"Place settings in {highlight}~/.config/opencode/opencode.json{/highlight} for global config.", "Place settings in {highlight}~/.config/opencode/opencode.json{/highlight} for global config",
"Add {highlight}$schema{/highlight} to your config for autocomplete in your editor.", "Add {highlight}$schema{/highlight} to your config for autocomplete in your editor",
"Configure {highlight}model{/highlight} in config to set your default model.", "Configure {highlight}model{/highlight} in config to set your default model",
"Override any keybind in config via the {highlight}keybinds{/highlight} section.", "Override any keybind in config via the {highlight}keybinds{/highlight} section",
"Set any keybind to {highlight}none{/highlight} to disable it completely.", "Set any keybind to {highlight}none{/highlight} to disable it completely",
"Configure local or remote MCP servers in the {highlight}mcp{/highlight} config section.", "Configure local or remote MCP servers in the {highlight}mcp{/highlight} config section",
"OpenCode auto-handles OAuth for remote MCP servers requiring auth.", "OpenCode auto-handles OAuth for remote MCP servers requiring auth",
"Add {highlight}.md{/highlight} files to {highlight}.opencode/command/{/highlight} to define reusable custom prompts.", "Add {highlight}.md{/highlight} files to {highlight}.opencode/command/{/highlight} to define reusable custom prompts",
"Use {highlight}$ARGUMENTS{/highlight}, {highlight}$1{/highlight}, {highlight}$2{/highlight} in custom commands for dynamic input.", "Use {highlight}$ARGUMENTS{/highlight}, {highlight}$1{/highlight}, {highlight}$2{/highlight} in custom commands for dynamic input",
"Use backticks in commands to inject shell output (e.g., {highlight}`git status`{/highlight}).", "Use backticks in commands to inject shell output (e.g., {highlight}`git status`{/highlight})",
"Add {highlight}.md{/highlight} files to {highlight}.opencode/agent/{/highlight} for specialized AI personas.", "Add {highlight}.md{/highlight} files to {highlight}.opencode/agent/{/highlight} for specialized AI personas",
"Configure per-agent permissions for {highlight}edit{/highlight}, {highlight}bash{/highlight}, and {highlight}webfetch{/highlight} tools.", "Configure per-agent permissions for {highlight}edit{/highlight}, {highlight}bash{/highlight}, and {highlight}webfetch{/highlight} tools",
'Use patterns like {highlight}"git *": "allow"{/highlight} for granular bash permissions.', 'Use patterns like {highlight}"git *": "allow"{/highlight} for granular bash permissions',
'Set {highlight}"rm -rf *": "deny"{/highlight} to block destructive commands.', 'Set {highlight}"rm -rf *": "deny"{/highlight} to block destructive commands',
'Configure {highlight}"git push": "ask"{/highlight} to require approval before pushing.', 'Configure {highlight}"git push": "ask"{/highlight} to require approval before pushing',
"OpenCode auto-formats files using prettier, gofmt, ruff, and more.", "OpenCode auto-formats files using prettier, gofmt, ruff, and more",
'Set {highlight}"formatter": false{/highlight} in config to disable all auto-formatting.', 'Set {highlight}"formatter": false{/highlight} in config to disable all auto-formatting',
"Define custom formatter commands with file extensions in config.", "Define custom formatter commands with file extensions in config",
"OpenCode uses LSP servers for intelligent code analysis.", "OpenCode uses LSP servers for intelligent code analysis",
"Create {highlight}.ts{/highlight} files in {highlight}.opencode/tool/{/highlight} to define new LLM tools.", "Create {highlight}.ts{/highlight} files in {highlight}.opencode/tool/{/highlight} to define new LLM tools",
"Tool definitions can invoke scripts written in Python, Go, etc.", "Tool definitions can invoke scripts written in Python, Go, etc",
"Add {highlight}.ts{/highlight} files to {highlight}.opencode/plugin/{/highlight} for event hooks.", "Add {highlight}.ts{/highlight} files to {highlight}.opencode/plugin/{/highlight} for event hooks",
"Use plugins to send OS notifications when sessions complete.", "Use plugins to send OS notifications when sessions complete",
"Create a plugin to prevent OpenCode from reading sensitive files.", "Create a plugin to prevent OpenCode from reading sensitive files",
"Use {highlight}opencode run{/highlight} for non-interactive scripting.", "Use {highlight}opencode run{/highlight} for non-interactive scripting",
"Use {highlight}opencode run --continue{/highlight} to resume the last session.", "Use {highlight}opencode run --continue{/highlight} to resume the last session",
"Use {highlight}opencode run -f file.ts{/highlight} to attach files via CLI.", "Use {highlight}opencode run -f file.ts{/highlight} to attach files via CLI",
"Use {highlight}--format json{/highlight} for machine-readable output in scripts.", "Use {highlight}--format json{/highlight} for machine-readable output in scripts",
"Run {highlight}opencode serve{/highlight} for headless API access to OpenCode.", "Run {highlight}opencode serve{/highlight} for headless API access to OpenCode",
"Use {highlight}opencode run --attach{/highlight} to connect to a running server for faster runs.", "Use {highlight}opencode run --attach{/highlight} to connect to a running server",
"Run {highlight}opencode upgrade{/highlight} to update to the latest version.", "Run {highlight}opencode upgrade{/highlight} to update to the latest version",
"Run {highlight}opencode auth list{/highlight} to see all configured providers.", "Run {highlight}opencode auth list{/highlight} to see all configured providers",
"Run {highlight}opencode agent create{/highlight} for guided agent creation.", "Run {highlight}opencode agent create{/highlight} for guided agent creation",
"Use {highlight}/opencode{/highlight} in GitHub issues/PRs to trigger AI actions.", "Use {highlight}/opencode{/highlight} in GitHub issues/PRs to trigger AI actions",
"Run {highlight}opencode github install{/highlight} to set up the GitHub workflow.", "Run {highlight}opencode github install{/highlight} to set up the GitHub workflow",
"Comment {highlight}/opencode fix this{/highlight} on issues to auto-create PRs.", "Comment {highlight}/opencode fix this{/highlight} on issues to auto-create PRs",
"Comment {highlight}/oc{/highlight} on PR code lines for targeted code reviews.", "Comment {highlight}/oc{/highlight} on PR code lines for targeted code reviews",
'Use {highlight}"theme": "system"{/highlight} to match your terminal\'s colors.', 'Use {highlight}"theme": "system"{/highlight} to match your terminal\'s colors',
"Create JSON theme files in {highlight}.opencode/themes/{/highlight} directory.", "Create JSON theme files in {highlight}.opencode/themes/{/highlight} directory",
"Themes support dark/light variants for both modes.", "Themes support dark/light variants for both modes",
"Reference ANSI colors 0-255 in custom themes.", "Reference ANSI colors 0-255 in custom themes",
"Use {highlight}{env:VAR_NAME}{/highlight} syntax to reference environment variables in config.", "Use {highlight}{env:VAR_NAME}{/highlight} syntax to reference environment variables in config",
"Use {highlight}{file:path}{/highlight} to include file contents in config values.", "Use {highlight}{file:path}{/highlight} to include file contents in config values",
"Use {highlight}instructions{/highlight} in config to load additional rules files.", "Use {highlight}instructions{/highlight} in config to load additional rules files",
"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.', 'Use {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',
"Run {highlight}/unshare{/highlight} to remove a session from public access.", "Run {highlight}/unshare{/highlight} to remove a session from public access",
"Permission {highlight}doom_loop{/highlight} prevents infinite tool call loops.", "Permission {highlight}doom_loop{/highlight} prevents infinite tool call loops",
"Permission {highlight}external_directory{/highlight} protects files outside project.", "Permission {highlight}external_directory{/highlight} protects files outside project",
"Run {highlight}opencode debug config{/highlight} to troubleshoot configuration.", "Run {highlight}opencode debug config{/highlight} to troubleshoot configuration",
"Use {highlight}--print-logs{/highlight} flag to see detailed logs in stderr.", "Use {highlight}--print-logs{/highlight} flag to see detailed logs in stderr",
"Press {highlight}Ctrl+X G{/highlight} or {highlight}/timeline{/highlight} to jump to specific messages.", "Press {highlight}Ctrl+X G{/highlight} or {highlight}/timeline{/highlight} to jump to specific messages",
"Press {highlight}Ctrl+X H{/highlight} to toggle code block visibility in messages.", "Press {highlight}Ctrl+X H{/highlight} to toggle code block visibility in messages",
"Press {highlight}Ctrl+X S{/highlight} or {highlight}/status{/highlight} to see system status info.", "Press {highlight}Ctrl+X S{/highlight} or {highlight}/status{/highlight} to see system status info",
"Enable {highlight}tui.scroll_acceleration{/highlight} for smooth macOS-style scrolling.", "Enable {highlight}tui.scroll_acceleration{/highlight} for smooth macOS-style scrolling",
"Toggle username display in chat via command palette ({highlight}Ctrl+P{/highlight}).", "Toggle username display in chat via command palette ({highlight}Ctrl+P{/highlight})",
"Run {highlight}docker run -it --rm ghcr.io/anomalyco/opencode{/highlight} for containerized use.", "Run {highlight}docker run -it --rm ghcr.io/sst/opencode{/highlight} for containerized use",
"Use {highlight}/connect{/highlight} with OpenCode Zen for curated, tested models.", "Use {highlight}/connect{/highlight} with OpenCode Zen for curated, tested models",
"Commit your project's {highlight}AGENTS.md{/highlight} file to Git for team sharing.", "Commit your project's {highlight}AGENTS.md{/highlight} file to Git for team sharing",
"Use {highlight}/review{/highlight} to review uncommitted changes, branches, or PRs.", "Use {highlight}/review{/highlight} to review uncommitted changes, branches, or PRs",
"Run {highlight}/help{/highlight} or {highlight}Ctrl+X H{/highlight} to show the help dialog.", "Run {highlight}/help{/highlight} or {highlight}Ctrl+X H{/highlight} to show the help dialog",
"Use {highlight}/details{/highlight} to toggle tool execution details visibility.", "Use {highlight}/details{/highlight} to toggle tool execution details visibility",
"Use {highlight}/rename{/highlight} to rename the current session.", "Use {highlight}/rename{/highlight} to rename the current session",
"Press {highlight}Ctrl+Z{/highlight} to suspend the terminal and return to your shell.", "Press {highlight}Ctrl+Z{/highlight} to suspend the terminal and return to your shell",
] ]

View File

@@ -1,6 +1,7 @@
import { Prompt, type PromptRef } from "@tui/component/prompt" import { Prompt, type PromptRef } from "@tui/component/prompt"
import { createMemo, Match, onMount, Show, Switch } from "solid-js" 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 { Logo } from "../component/logo" import { Logo } from "../component/logo"
import { DidYouKnow, randomizeTip } from "../component/did-you-know" import { DidYouKnow, randomizeTip } from "../component/did-you-know"
import { Locale } from "@/util/locale" import { Locale } from "@/util/locale"
@@ -36,7 +37,6 @@ export function Home() {
const isFirstTimeUser = createMemo(() => sync.data.session.length === 0) const isFirstTimeUser = createMemo(() => sync.data.session.length === 0)
const tipsHidden = createMemo(() => kv.get("tips_hidden", false)) const tipsHidden = createMemo(() => kv.get("tips_hidden", false))
const showTips = createMemo(() => { const showTips = createMemo(() => {
return false
// Don't show tips for first-time users // Don't show tips for first-time users
if (isFirstTimeUser()) return false if (isFirstTimeUser()) return false
return !tipsHidden() return !tipsHidden()
@@ -90,6 +90,8 @@ export function Home() {
}) })
const directory = useDirectory() const directory = useDirectory()
const keybind = useKeybind()
return ( return (
<> <>
<box flexGrow={1} justifyContent="center" alignItems="center" paddingLeft={2} paddingRight={2} gap={1}> <box flexGrow={1} justifyContent="center" alignItems="center" paddingLeft={2} paddingRight={2} gap={1}>
@@ -103,12 +105,22 @@ export function Home() {
hint={Hint} hint={Hint}
/> />
</box> </box>
<Show when={!isFirstTimeUser()}>
<Show when={showTips()}>
<box width="100%" maxWidth={75} paddingTop={3} alignItems="center">
<DidYouKnow />
</box>
</Show>
</Show>
<Toast /> <Toast />
</box> </box>
<Show when={!isFirstTimeUser()}> <Show when={showTips()}>
<Show when={showTips()}> <box position="absolute" bottom={2} right={2}>
<DidYouKnow /> <text>
</Show> <span style={{ fg: theme.text }}>{keybind.print("tips_toggle")}</span>
<span style={{ fg: theme.textMuted }}> Hide tips</span>
</text>
</box>
</Show> </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>