mirror of
https://github.com/aljazceru/opencode.git
synced 2026-01-07 09:54:56 +01:00
Light mode (#3709)
This commit is contained in:
@@ -29,6 +29,63 @@ import { Session as SessionApi } from "@/session"
|
|||||||
import { TuiEvent } from "./event"
|
import { TuiEvent } from "./event"
|
||||||
import { KVProvider, useKV } from "./context/kv"
|
import { KVProvider, useKV } from "./context/kv"
|
||||||
|
|
||||||
|
async function getTerminalBackgroundColor(): Promise<"dark" | "light"> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
let timeout: NodeJS.Timeout
|
||||||
|
|
||||||
|
const cleanup = () => {
|
||||||
|
process.stdin.setRawMode(false)
|
||||||
|
process.stdin.removeListener("data", handler)
|
||||||
|
clearTimeout(timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handler = (data: Buffer) => {
|
||||||
|
const str = data.toString()
|
||||||
|
const match = str.match(/\x1b]11;([^\x07\x1b]+)/)
|
||||||
|
if (match) {
|
||||||
|
cleanup()
|
||||||
|
const color = match[1]
|
||||||
|
// Parse RGB values from color string
|
||||||
|
// Formats: rgb:RR/GG/BB or #RRGGBB or rgb(R,G,B)
|
||||||
|
let r = 0,
|
||||||
|
g = 0,
|
||||||
|
b = 0
|
||||||
|
|
||||||
|
if (color.startsWith("rgb:")) {
|
||||||
|
const parts = color.substring(4).split("/")
|
||||||
|
r = parseInt(parts[0], 16) >> 8 // Convert 16-bit to 8-bit
|
||||||
|
g = parseInt(parts[1], 16) >> 8 // Convert 16-bit to 8-bit
|
||||||
|
b = parseInt(parts[2], 16) >> 8 // Convert 16-bit to 8-bit
|
||||||
|
} else if (color.startsWith("#")) {
|
||||||
|
r = parseInt(color.substring(1, 3), 16)
|
||||||
|
g = parseInt(color.substring(3, 5), 16)
|
||||||
|
b = parseInt(color.substring(5, 7), 16)
|
||||||
|
} else if (color.startsWith("rgb(")) {
|
||||||
|
const parts = color.substring(4, color.length - 1).split(",")
|
||||||
|
r = parseInt(parts[0])
|
||||||
|
g = parseInt(parts[1])
|
||||||
|
b = parseInt(parts[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate luminance using relative luminance formula
|
||||||
|
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
|
||||||
|
|
||||||
|
// Determine if dark or light based on luminance threshold
|
||||||
|
resolve(luminance > 0.5 ? "light" : "dark")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stdin.setRawMode(true)
|
||||||
|
process.stdin.on("data", handler)
|
||||||
|
process.stdout.write("\x1b]11;?\x07")
|
||||||
|
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
cleanup()
|
||||||
|
resolve("dark")
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function tui(input: {
|
export function tui(input: {
|
||||||
url: string
|
url: string
|
||||||
sessionID?: string
|
sessionID?: string
|
||||||
@@ -38,7 +95,9 @@ export function tui(input: {
|
|||||||
onExit?: () => Promise<void>
|
onExit?: () => Promise<void>
|
||||||
}) {
|
}) {
|
||||||
// promise to prevent immediate exit
|
// promise to prevent immediate exit
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>(async (resolve) => {
|
||||||
|
const mode = await getTerminalBackgroundColor()
|
||||||
|
|
||||||
const routeData: Route | undefined = input.sessionID
|
const routeData: Route | undefined = input.sessionID
|
||||||
? {
|
? {
|
||||||
type: "session",
|
type: "session",
|
||||||
@@ -65,8 +124,12 @@ export function tui(input: {
|
|||||||
<RouteProvider data={routeData}>
|
<RouteProvider data={routeData}>
|
||||||
<SDKProvider url={input.url}>
|
<SDKProvider url={input.url}>
|
||||||
<SyncProvider>
|
<SyncProvider>
|
||||||
<ThemeProvider>
|
<ThemeProvider mode={mode}>
|
||||||
<LocalProvider initialModel={input.model} initialAgent={input.agent} initialPrompt={input.prompt}>
|
<LocalProvider
|
||||||
|
initialModel={input.model}
|
||||||
|
initialAgent={input.agent}
|
||||||
|
initialPrompt={input.prompt}
|
||||||
|
>
|
||||||
<KeybindProvider>
|
<KeybindProvider>
|
||||||
<DialogProvider>
|
<DialogProvider>
|
||||||
<CommandProvider>
|
<CommandProvider>
|
||||||
@@ -109,7 +172,7 @@ function App() {
|
|||||||
const sync = useSync()
|
const sync = useSync()
|
||||||
const toast = useToast()
|
const toast = useToast()
|
||||||
const [sessionExists, setSessionExists] = createSignal(false)
|
const [sessionExists, setSessionExists] = createSignal(false)
|
||||||
const { theme } = useTheme()
|
const { theme, mode, setMode } = useTheme()
|
||||||
const exit = useExit()
|
const exit = useExit()
|
||||||
|
|
||||||
useKeyboard(async (evt) => {
|
useKeyboard(async (evt) => {
|
||||||
@@ -238,6 +301,14 @@ function App() {
|
|||||||
},
|
},
|
||||||
category: "System",
|
category: "System",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: `Switch to ${mode() === "dark" ? "light" : "dark"} mode`,
|
||||||
|
value: "theme.switch_mode",
|
||||||
|
onSelect: () => {
|
||||||
|
setMode(mode() === "dark" ? "light" : "dark")
|
||||||
|
},
|
||||||
|
category: "System",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "Help",
|
title: "Help",
|
||||||
value: "help.show",
|
value: "help.show",
|
||||||
@@ -251,7 +322,7 @@ function App() {
|
|||||||
value: "app.exit",
|
value: "app.exit",
|
||||||
onSelect: exit,
|
onSelect: exit,
|
||||||
category: "System",
|
category: "System",
|
||||||
}
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
@@ -335,7 +406,9 @@ function App() {
|
|||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
>
|
>
|
||||||
<text fg={theme.textMuted}>open</text>
|
<text fg={theme.textMuted}>open</text>
|
||||||
<text attributes={TextAttributes.BOLD}>code </text>
|
<text fg={theme.text} attributes={TextAttributes.BOLD}>
|
||||||
|
code{" "}
|
||||||
|
</text>
|
||||||
<text fg={theme.textMuted}>v{Installation.VERSION}</text>
|
<text fg={theme.textMuted}>v{Installation.VERSION}</text>
|
||||||
</box>
|
</box>
|
||||||
<box paddingLeft={1} paddingRight={1}>
|
<box paddingLeft={1} paddingRight={1}>
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ export function DialogStatus() {
|
|||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD}>Status</text>
|
<text fg={theme.text} attributes={TextAttributes.BOLD}>
|
||||||
|
Status
|
||||||
|
</text>
|
||||||
<text fg={theme.textMuted}>esc</text>
|
<text fg={theme.textMuted}>esc</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={Object.keys(sync.data.mcp).length > 0} fallback={<text>No MCP Servers</text>}>
|
<Show when={Object.keys(sync.data.mcp).length > 0} fallback={<text>No MCP Servers</text>}>
|
||||||
<box>
|
<box>
|
||||||
<text>{Object.keys(sync.data.mcp).length} MCP Servers</text>
|
<text fg={theme.text}>{Object.keys(sync.data.mcp).length} MCP Servers</text>
|
||||||
<For each={Object.entries(sync.data.mcp)}>
|
<For each={Object.entries(sync.data.mcp)}>
|
||||||
{([key, item]) => (
|
{([key, item]) => (
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
@@ -35,7 +37,7 @@ export function DialogStatus() {
|
|||||||
>
|
>
|
||||||
•
|
•
|
||||||
</text>
|
</text>
|
||||||
<text wrapMode="word">
|
<text fg={theme.text} wrapMode="word">
|
||||||
<b>{key}</b>{" "}
|
<b>{key}</b>{" "}
|
||||||
<span style={{ fg: theme.textMuted }}>
|
<span style={{ fg: theme.textMuted }}>
|
||||||
<Switch>
|
<Switch>
|
||||||
@@ -52,7 +54,7 @@ export function DialogStatus() {
|
|||||||
</Show>
|
</Show>
|
||||||
{sync.data.lsp.length > 0 && (
|
{sync.data.lsp.length > 0 && (
|
||||||
<box>
|
<box>
|
||||||
<text>{sync.data.lsp.length} LSP Servers</text>
|
<text fg={theme.text}>{sync.data.lsp.length} LSP Servers</text>
|
||||||
<For each={sync.data.lsp}>
|
<For each={sync.data.lsp}>
|
||||||
{(item) => (
|
{(item) => (
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
@@ -67,7 +69,7 @@ export function DialogStatus() {
|
|||||||
>
|
>
|
||||||
•
|
•
|
||||||
</text>
|
</text>
|
||||||
<text wrapMode="word">
|
<text fg={theme.text} wrapMode="word">
|
||||||
<b>{item.id}</b> <span style={{ fg: theme.textMuted }}>{item.root}</span>
|
<b>{item.id}</b> <span style={{ fg: theme.textMuted }}>{item.root}</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
@@ -75,9 +77,12 @@ export function DialogStatus() {
|
|||||||
</For>
|
</For>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
<Show when={enabledFormatters().length > 0} fallback={<text>No Formatters</text>}>
|
<Show
|
||||||
|
when={enabledFormatters().length > 0}
|
||||||
|
fallback={<text fg={theme.text}>No Formatters</text>}
|
||||||
|
>
|
||||||
<box>
|
<box>
|
||||||
<text>{enabledFormatters().length} Formatters</text>
|
<text fg={theme.text}>{enabledFormatters().length} Formatters</text>
|
||||||
<For each={enabledFormatters()}>
|
<For each={enabledFormatters()}>
|
||||||
{(item) => (
|
{(item) => (
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
@@ -89,7 +94,7 @@ export function DialogStatus() {
|
|||||||
>
|
>
|
||||||
•
|
•
|
||||||
</text>
|
</text>
|
||||||
<text wrapMode="word">
|
<text wrapMode="word" fg={theme.text}>
|
||||||
<b>{item.name}</b>
|
<b>{item.name}</b>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
} from "@opentui/core"
|
} from "@opentui/core"
|
||||||
import { createEffect, createMemo, Match, Switch, type JSX, onMount, batch } from "solid-js"
|
import { createEffect, createMemo, Match, Switch, type JSX, onMount, batch } from "solid-js"
|
||||||
import { useLocal } from "@tui/context/local"
|
import { useLocal } from "@tui/context/local"
|
||||||
import { SyntaxTheme, useTheme } from "@tui/context/theme"
|
import { useTheme } from "@tui/context/theme"
|
||||||
import { SplitBorder } from "@tui/component/border"
|
import { SplitBorder } from "@tui/component/border"
|
||||||
import { useSDK } from "@tui/context/sdk"
|
import { useSDK } from "@tui/context/sdk"
|
||||||
import { useRoute } from "@tui/context/route"
|
import { useRoute } from "@tui/context/route"
|
||||||
@@ -60,7 +60,7 @@ export function Prompt(props: PromptProps) {
|
|||||||
const history = usePromptHistory()
|
const history = usePromptHistory()
|
||||||
const command = useCommandDialog()
|
const command = useCommandDialog()
|
||||||
const renderer = useRenderer()
|
const renderer = useRenderer()
|
||||||
const { theme } = useTheme()
|
const { theme, syntax } = useTheme()
|
||||||
|
|
||||||
const textareaKeybindings = createMemo(() => {
|
const textareaKeybindings = createMemo(() => {
|
||||||
const newlineBindings = keybind.all.input_newline || []
|
const newlineBindings = keybind.all.input_newline || []
|
||||||
@@ -86,9 +86,9 @@ export function Prompt(props: PromptProps) {
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
const fileStyleId = SyntaxTheme.getStyleId("extmark.file")!
|
const fileStyleId = syntax().getStyleId("extmark.file")!
|
||||||
const agentStyleId = SyntaxTheme.getStyleId("extmark.agent")!
|
const agentStyleId = syntax().getStyleId("extmark.agent")!
|
||||||
const pasteStyleId = SyntaxTheme.getStyleId("extmark.paste")!
|
const pasteStyleId = syntax().getStyleId("extmark.paste")!
|
||||||
let promptPartTypeId: number
|
let promptPartTypeId: number
|
||||||
|
|
||||||
command.register(() => {
|
command.register(() => {
|
||||||
@@ -315,9 +315,9 @@ export function Prompt(props: PromptProps) {
|
|||||||
const sessionID = props.sessionID
|
const sessionID = props.sessionID
|
||||||
? props.sessionID
|
? props.sessionID
|
||||||
: await (async () => {
|
: await (async () => {
|
||||||
const sessionID = await sdk.client.session.create({}).then((x) => x.data!.id)
|
const sessionID = await sdk.client.session.create({}).then((x) => x.data!.id)
|
||||||
return sessionID
|
return sessionID
|
||||||
})()
|
})()
|
||||||
const messageID = Identifier.ascending("message")
|
const messageID = Identifier.ascending("message")
|
||||||
let inputText = store.prompt.input
|
let inputText = store.prompt.input
|
||||||
|
|
||||||
@@ -680,7 +680,7 @@ export function Prompt(props: PromptProps) {
|
|||||||
onMouseDown={(r: MouseEvent) => r.target?.focus()}
|
onMouseDown={(r: MouseEvent) => r.target?.focus()}
|
||||||
focusedBackgroundColor={theme.backgroundElement}
|
focusedBackgroundColor={theme.backgroundElement}
|
||||||
cursorColor={theme.primary}
|
cursorColor={theme.primary}
|
||||||
syntaxStyle={SyntaxTheme}
|
syntaxStyle={syntax()}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box
|
||||||
@@ -691,7 +691,7 @@ export function Prompt(props: PromptProps) {
|
|||||||
></box>
|
></box>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text flexShrink={0} wrapMode="none">
|
<text flexShrink={0} wrapMode="none" fg={theme.text}>
|
||||||
<span style={{ fg: theme.textMuted }}>{local.model.parsed().provider}</span>{" "}
|
<span style={{ fg: theme.textMuted }}>{local.model.parsed().provider}</span>{" "}
|
||||||
<span style={{ bold: true }}>{local.model.parsed().model}</span>
|
<span style={{ bold: true }}>{local.model.parsed().model}</span>
|
||||||
</text>
|
</text>
|
||||||
@@ -701,14 +701,14 @@ export function Prompt(props: PromptProps) {
|
|||||||
</Match>
|
</Match>
|
||||||
<Match when={status() === "working"}>
|
<Match when={status() === "working"}>
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
esc <span style={{ fg: theme.textMuted }}>interrupt</span>
|
esc <span style={{ fg: theme.textMuted }}>interrupt</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={props.hint}>{props.hint!}</Match>
|
<Match when={props.hint}>{props.hint!}</Match>
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
ctrl+p <span style={{ fg: theme.textMuted }}>commands</span>
|
ctrl+p <span style={{ fg: theme.textMuted }}>commands</span>
|
||||||
</text>
|
</text>
|
||||||
</Match>
|
</Match>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,7 @@ export function Home() {
|
|||||||
const Hint = (
|
const Hint = (
|
||||||
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
||||||
<box flexShrink={0} flexDirection="row" gap={1}>
|
<box flexShrink={0} flexDirection="row" gap={1}>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={mcpError()}>
|
<Match when={mcpError()}>
|
||||||
<span style={{ fg: theme.error }}>•</span> mcp errors{" "}
|
<span style={{ fg: theme.error }}>•</span> mcp errors{" "}
|
||||||
@@ -76,7 +76,7 @@ function HelpRow(props: ParentProps<{ keybind: keyof KeybindsConfig }>) {
|
|||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
return (
|
return (
|
||||||
<box flexDirection="row" justifyContent="space-between" width="100%">
|
<box flexDirection="row" justifyContent="space-between" width="100%">
|
||||||
<text>{props.children}</text>
|
<text fg={theme.text}>{props.children}</text>
|
||||||
<text fg={theme.primary}>{keybind.print(props.keybind)}</text>
|
<text fg={theme.primary}>{keybind.print(props.keybind)}</text>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export function Header() {
|
|||||||
borderColor={theme.backgroundElement}
|
borderColor={theme.backgroundElement}
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
>
|
>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
<span style={{ bold: true, fg: theme.accent }}>#</span>{" "}
|
<span style={{ bold: true, fg: theme.accent }}>#</span>{" "}
|
||||||
<span style={{ bold: true }}>{session().title}</span>
|
<span style={{ bold: true }}>{session().title}</span>
|
||||||
</text>
|
</text>
|
||||||
@@ -64,7 +64,7 @@ export function Header() {
|
|||||||
</text>
|
</text>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
<text wrapMode="word">
|
<text fg={theme.text} wrapMode="word">
|
||||||
/share <span style={{ fg: theme.textMuted }}>to create a shareable link</span>
|
/share <span style={{ fg: theme.textMuted }}>to create a shareable link</span>
|
||||||
</text>
|
</text>
|
||||||
</Match>
|
</Match>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import path from "path"
|
|||||||
import { useRouteData } from "@tui/context/route"
|
import { useRouteData } from "@tui/context/route"
|
||||||
import { useSync } from "@tui/context/sync"
|
import { useSync } from "@tui/context/sync"
|
||||||
import { SplitBorder } from "@tui/component/border"
|
import { SplitBorder } from "@tui/component/border"
|
||||||
import { SyntaxTheme, useTheme } from "@tui/context/theme"
|
import { useTheme } from "@tui/context/theme"
|
||||||
import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers } from "@opentui/core"
|
import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers } from "@opentui/core"
|
||||||
import { Prompt, type PromptRef } from "@tui/component/prompt"
|
import { Prompt, type PromptRef } from "@tui/component/prompt"
|
||||||
import type {
|
import type {
|
||||||
@@ -641,7 +641,7 @@ function UserMessage(props: {
|
|||||||
borderColor={color()}
|
borderColor={color()}
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
>
|
>
|
||||||
<text>{text()?.text}</text>
|
<text fg={theme.text}>{text()?.text}</text>
|
||||||
<Show when={files().length}>
|
<Show when={files().length}>
|
||||||
<box flexDirection="row" paddingBottom={1} paddingTop={1} gap={1} flexWrap="wrap">
|
<box flexDirection="row" paddingBottom={1} paddingTop={1} gap={1} flexWrap="wrap">
|
||||||
<For each={files()}>
|
<For each={files()}>
|
||||||
@@ -652,7 +652,7 @@ function UserMessage(props: {
|
|||||||
return theme.secondary
|
return theme.secondary
|
||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
<span style={{ bg: bg(), fg: theme.background }}>
|
<span style={{ bg: bg(), fg: theme.background }}>
|
||||||
{" "}
|
{" "}
|
||||||
{MIME_BADGE[file.mime] ?? file.mime}{" "}
|
{MIME_BADGE[file.mime] ?? file.mime}{" "}
|
||||||
@@ -667,7 +667,7 @@ function UserMessage(props: {
|
|||||||
</For>
|
</For>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
{sync.data.config.username ?? "You"}{" "}
|
{sync.data.config.username ?? "You"}{" "}
|
||||||
<Show
|
<Show
|
||||||
when={queued()}
|
when={queued()}
|
||||||
@@ -782,7 +782,7 @@ function ReasoningPart(props: { part: ReasoningPart; message: AssistantMessage }
|
|||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
backgroundColor={theme.backgroundPanel}
|
backgroundColor={theme.backgroundPanel}
|
||||||
>
|
>
|
||||||
<text>{props.part.text.trim()}</text>
|
<text fg={theme.text}>{props.part.text.trim()}</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
@@ -791,13 +791,14 @@ function ReasoningPart(props: { part: ReasoningPart; message: AssistantMessage }
|
|||||||
|
|
||||||
function TextPart(props: { part: TextPart; message: AssistantMessage }) {
|
function TextPart(props: { part: TextPart; message: AssistantMessage }) {
|
||||||
const ctx = use()
|
const ctx = use()
|
||||||
|
const { syntax } = useTheme()
|
||||||
return (
|
return (
|
||||||
<Show when={props.part.text.trim()}>
|
<Show when={props.part.text.trim()}>
|
||||||
<box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0}>
|
<box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0}>
|
||||||
<code
|
<code
|
||||||
filetype="markdown"
|
filetype="markdown"
|
||||||
drawUnstyledText={false}
|
drawUnstyledText={false}
|
||||||
syntaxStyle={SyntaxTheme}
|
syntaxStyle={syntax()}
|
||||||
content={props.part.text.trim()}
|
content={props.part.text.trim()}
|
||||||
conceal={ctx.conceal()}
|
conceal={ctx.conceal()}
|
||||||
/>
|
/>
|
||||||
@@ -997,7 +998,7 @@ ToolRegistry.register<typeof WriteTool>({
|
|||||||
name: "write",
|
name: "write",
|
||||||
container: "block",
|
container: "block",
|
||||||
render(props) {
|
render(props) {
|
||||||
const { theme } = useTheme()
|
const { theme, syntax } = useTheme()
|
||||||
const lines = createMemo(() => {
|
const lines = createMemo(() => {
|
||||||
return props.input.content?.split("\n") ?? []
|
return props.input.content?.split("\n") ?? []
|
||||||
})
|
})
|
||||||
@@ -1028,7 +1029,7 @@ ToolRegistry.register<typeof WriteTool>({
|
|||||||
<box paddingLeft={1} flexGrow={1}>
|
<box paddingLeft={1} flexGrow={1}>
|
||||||
<code
|
<code
|
||||||
filetype={filetype(props.input.filePath!)}
|
filetype={filetype(props.input.filePath!)}
|
||||||
syntaxStyle={SyntaxTheme}
|
syntaxStyle={syntax()}
|
||||||
content={code()}
|
content={code()}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
@@ -1131,6 +1132,7 @@ ToolRegistry.register<typeof EditTool>({
|
|||||||
container: "block",
|
container: "block",
|
||||||
render(props) {
|
render(props) {
|
||||||
const ctx = use()
|
const ctx = use()
|
||||||
|
const { theme, syntax } = useTheme()
|
||||||
|
|
||||||
const style = createMemo(() => (ctx.width > 120 ? "split" : "stacked"))
|
const style = createMemo(() => (ctx.width > 120 ? "split" : "stacked"))
|
||||||
|
|
||||||
@@ -1210,21 +1212,21 @@ ToolRegistry.register<typeof EditTool>({
|
|||||||
</ToolTitle>
|
</ToolTitle>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={props.permission["diff"]}>
|
<Match when={props.permission["diff"]}>
|
||||||
<text>{props.permission["diff"]?.trim()}</text>
|
<text fg={theme.text}>{props.permission["diff"]?.trim()}</text>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={diff() && style() === "split"}>
|
<Match when={diff() && style() === "split"}>
|
||||||
<box paddingLeft={1} flexDirection="row" gap={2}>
|
<box paddingLeft={1} flexDirection="row" gap={2}>
|
||||||
<box flexGrow={1} flexBasis={0}>
|
<box flexGrow={1} flexBasis={0}>
|
||||||
<code filetype={ft()} syntaxStyle={SyntaxTheme} content={diff()!.oldContent} />
|
<code filetype={ft()} syntaxStyle={syntax()} content={diff()!.oldContent} />
|
||||||
</box>
|
</box>
|
||||||
<box flexGrow={1} flexBasis={0}>
|
<box flexGrow={1} flexBasis={0}>
|
||||||
<code filetype={ft()} syntaxStyle={SyntaxTheme} content={diff()!.newContent} />
|
<code filetype={ft()} syntaxStyle={syntax()} content={diff()!.newContent} />
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={code()}>
|
<Match when={code()}>
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<code filetype={ft()} syntaxStyle={SyntaxTheme} content={code()} />
|
<code filetype={ft()} syntaxStyle={syntax()} content={code()} />
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
@@ -1237,6 +1239,7 @@ ToolRegistry.register<typeof PatchTool>({
|
|||||||
name: "patch",
|
name: "patch",
|
||||||
container: "block",
|
container: "block",
|
||||||
render(props) {
|
render(props) {
|
||||||
|
const { theme } = useTheme()
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ToolTitle icon="%" fallback="Preparing patch..." when={true}>
|
<ToolTitle icon="%" fallback="Preparing patch..." when={true}>
|
||||||
@@ -1244,7 +1247,7 @@ ToolRegistry.register<typeof PatchTool>({
|
|||||||
</ToolTitle>
|
</ToolTitle>
|
||||||
<Show when={props.output}>
|
<Show when={props.output}>
|
||||||
<box>
|
<box>
|
||||||
<text>{props.output?.trim()}</text>
|
<text fg={theme.text}>{props.output?.trim()}</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function Sidebar(props: { sessionID: string }) {
|
|||||||
<Show when={session()}>
|
<Show when={session()}>
|
||||||
<box flexShrink={0} gap={1} width={40}>
|
<box flexShrink={0} gap={1} width={40}>
|
||||||
<box>
|
<box>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
<b>{session().title}</b>
|
<b>{session().title}</b>
|
||||||
</text>
|
</text>
|
||||||
<Show when={session().share?.url}>
|
<Show when={session().share?.url}>
|
||||||
@@ -50,7 +50,7 @@ export function Sidebar(props: { sessionID: string }) {
|
|||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
<box>
|
<box>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
<b>Context</b>
|
<b>Context</b>
|
||||||
</text>
|
</text>
|
||||||
<text fg={theme.textMuted}>{context()?.tokens ?? 0} tokens</text>
|
<text fg={theme.textMuted}>{context()?.tokens ?? 0} tokens</text>
|
||||||
@@ -59,7 +59,7 @@ export function Sidebar(props: { sessionID: string }) {
|
|||||||
</box>
|
</box>
|
||||||
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
<Show when={Object.keys(sync.data.mcp).length > 0}>
|
||||||
<box>
|
<box>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
<b>MCP</b>
|
<b>MCP</b>
|
||||||
</text>
|
</text>
|
||||||
<For each={Object.entries(sync.data.mcp)}>
|
<For each={Object.entries(sync.data.mcp)}>
|
||||||
@@ -77,7 +77,7 @@ export function Sidebar(props: { sessionID: string }) {
|
|||||||
>
|
>
|
||||||
•
|
•
|
||||||
</text>
|
</text>
|
||||||
<text wrapMode="word">
|
<text fg={theme.text} wrapMode="word">
|
||||||
{key}{" "}
|
{key}{" "}
|
||||||
<span style={{ fg: theme.textMuted }}>
|
<span style={{ fg: theme.textMuted }}>
|
||||||
<Switch>
|
<Switch>
|
||||||
@@ -96,7 +96,7 @@ export function Sidebar(props: { sessionID: string }) {
|
|||||||
</Show>
|
</Show>
|
||||||
<Show when={sync.data.lsp.length > 0}>
|
<Show when={sync.data.lsp.length > 0}>
|
||||||
<box>
|
<box>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
<b>LSP</b>
|
<b>LSP</b>
|
||||||
</text>
|
</text>
|
||||||
<For each={sync.data.lsp}>
|
<For each={sync.data.lsp}>
|
||||||
@@ -123,7 +123,7 @@ export function Sidebar(props: { sessionID: string }) {
|
|||||||
</Show>
|
</Show>
|
||||||
<Show when={session().summary?.diffs}>
|
<Show when={session().summary?.diffs}>
|
||||||
<box>
|
<box>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
<b>Modified Files</b>
|
<b>Modified Files</b>
|
||||||
</text>
|
</text>
|
||||||
<For each={session().summary?.diffs || []}>
|
<For each={session().summary?.diffs || []}>
|
||||||
@@ -155,7 +155,7 @@ export function Sidebar(props: { sessionID: string }) {
|
|||||||
</Show>
|
</Show>
|
||||||
<Show when={todo().length > 0}>
|
<Show when={todo().length > 0}>
|
||||||
<box>
|
<box>
|
||||||
<text>
|
<text fg={theme.text}>
|
||||||
<b>Todo</b>
|
<b>Todo</b>
|
||||||
</text>
|
</text>
|
||||||
<For each={todo()}>
|
<For each={todo()}>
|
||||||
|
|||||||
@@ -161,7 +161,9 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
|||||||
<box gap={1}>
|
<box gap={1}>
|
||||||
<box paddingLeft={3} paddingRight={2}>
|
<box paddingLeft={3} paddingRight={2}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD}>{props.title}</text>
|
<text fg={theme.text} attributes={TextAttributes.BOLD}>
|
||||||
|
{props.title}
|
||||||
|
</text>
|
||||||
<text fg={theme.textMuted}>esc</text>
|
<text fg={theme.textMuted}>esc</text>
|
||||||
</box>
|
</box>
|
||||||
<box paddingTop={1} paddingBottom={1}>
|
<box paddingTop={1} paddingBottom={1}>
|
||||||
|
|||||||
Reference in New Issue
Block a user