Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions packages/tui/src/component/dialog-pair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
const client = useClient()
const dialog = useDialog()
const dimensions = useTerminalDimensions()
const { theme } = useTheme()
const { themeV2 } = useTheme().contextual("elevated")
const [loadError, setLoadError] = createSignal<unknown>()
const [showPassword, setShowPassword] = createSignal(false)
const [passwordHover, setPasswordHover] = createSignal(false)
Expand Down Expand Up @@ -47,17 +47,17 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
<box flexDirection={horizontal() ? "row" : "column"} alignItems={horizontal() ? "flex-start" : "center"} gap={2}>
<box width={horizontal() ? 29 : "100%"} flexShrink={0} gap={1}>
<box>
<text fg={theme.textMuted}>URLs</text>
<For each={value.urls}>{(url) => <text fg={theme.text}>{url}</text>}</For>
<text fg={themeV2.text.subdued()}>URLs</text>
<For each={value.urls}>{(url) => <text fg={themeV2.text()}>{url}</text>}</For>
</box>
<box>
<text fg={theme.textMuted}>Username</text>
<text fg={theme.text}>{value.username}</text>
<text fg={themeV2.text.subdued()}>Username</text>
<text fg={themeV2.text()}>{value.username}</text>
</box>
<box>
<text fg={theme.textMuted}>Password</text>
<text fg={themeV2.text.subdued()}>Password</text>
<text
fg={passwordHover() ? theme.text : theme.textMuted}
fg={passwordHover() ? themeV2.text() : themeV2.text.subdued()}
wrapMode="word"
onMouseOver={() => setPasswordHover(true)}
onMouseOut={() => setPasswordHover(false)}
Expand All @@ -67,7 +67,7 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
</text>
</box>
<Show when={value.urls.some((url) => ["localhost", "127.0.0.1", "[::1]"].includes(new URL(url).hostname))}>
<text fg={theme.textMuted} wrapMode="word">
<text fg={themeV2.text.subdued()} wrapMode="word">
Run `opencode service set hostname 0.0.0.0` to access the service remotely.
</text>
</Show>
Expand All @@ -78,7 +78,7 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
flexShrink={0}
alignItems={horizontal() ? "flex-end" : "center"}
>
<text fg={theme.text}>{renderUnicodeCompact(JSON.stringify(value), { border: 1 })}</text>
<text fg={themeV2.text()}>{renderUnicodeCompact(JSON.stringify(value), { border: 1 })}</text>
</box>
</box>
)
Expand All @@ -87,17 +87,17 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
return (
<box paddingLeft={2} paddingRight={2} paddingBottom={1} gap={1}>
<box flexDirection="row" justifyContent="space-between">
<text fg={theme.text} attributes={TextAttributes.BOLD}>
<text fg={themeV2.text()} attributes={TextAttributes.BOLD}>
Pair
</text>
<text fg={theme.textMuted} onMouseUp={() => dialog.clear()}>
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
esc
</text>
</box>
<Show
when={loadError()}
fallback={
<Show when={info()} fallback={<text fg={theme.textMuted}>Loading server information…</text>}>
<Show when={info()} fallback={<text fg={themeV2.text.subdued()}>Loading server information…</text>}>
<Show
when={dimensions().height >= 36}
fallback={
Expand All @@ -116,11 +116,11 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
>
{(error) => (
<box>
<text fg={theme.error} attributes={TextAttributes.BOLD}>
<text fg={themeV2.text.feedback.error()} attributes={TextAttributes.BOLD}>
Could not load server information
</text>
<text fg={theme.textMuted}>{errorMessage(error())}</text>
<text fg={theme.textMuted}>Close and reopen Pair to try again.</text>
<text fg={themeV2.text.subdued()}>{errorMessage(error())}</text>
<text fg={themeV2.text.subdued()}>Close and reopen Pair to try again.</text>
</box>
)}
</Show>
Expand Down
23 changes: 12 additions & 11 deletions packages/tui/src/component/dialog-project-copy-name.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useDialog, type DialogContext } from "../ui/dialog"

export function DialogProjectCopyName(props: { onConfirm: (name: string) => void }) {
const dialog = useDialog()
const { theme } = useTheme()
const { themeV2 } = useTheme().contextual("elevated")
const shortcuts = Keymap.useShortcuts()
const [inputTarget, setInputTarget] = createSignal<InputRenderable>()
let input: InputRenderable
Expand Down Expand Up @@ -47,10 +47,10 @@ export function DialogProjectCopyName(props: { onConfirm: (name: string) => void
return (
<box paddingLeft={2} paddingRight={2} gap={1}>
<box flexDirection="row" justifyContent="space-between">
<text attributes={TextAttributes.BOLD} fg={theme.text}>
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
Name project copy
</text>
<text fg={theme.textMuted} onMouseUp={() => dialog.clear()}>
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
esc
</text>
</box>
Expand All @@ -61,17 +61,18 @@ export function DialogProjectCopyName(props: { onConfirm: (name: string) => void
}}
onSubmit={confirm}
placeholder="Project copy name"
placeholderColor={theme.textMuted}
textColor={theme.text}
focusedTextColor={theme.text}
cursorColor={theme.text}
placeholderColor={themeV2.text.subdued()}
textColor={themeV2.text.formfield()}
focusedTextColor={themeV2.text.formfield()}
cursorColor={themeV2.text.formfield()}
/>
<box paddingBottom={1} flexDirection="row" gap={2}>
<text fg={theme.text}>
enter <span style={{ fg: theme.textMuted }}>submit</span>
<text fg={themeV2.text()}>
enter <span style={{ fg: themeV2.text.subdued() }}>submit</span>
</text>
<text fg={theme.text}>
{shortcuts.get("dialog.project_copy.generate")} <span style={{ fg: theme.textMuted }}>generate one</span>
<text fg={themeV2.text()}>
{shortcuts.get("dialog.project_copy.generate")}{" "}
<span style={{ fg: themeV2.text.subdued() }}>generate one</span>
</text>
</box>
</box>
Expand Down
36 changes: 15 additions & 21 deletions packages/tui/src/component/dialog-status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,41 @@ export type DialogStatusProps = {}

export function DialogStatus() {
const data = useData()
const { theme } = useTheme()
const { themeV2 } = useTheme().contextual("elevated")
const dialog = useDialog()

const mcp = createMemo(() => data.location.mcp.server.list() ?? [])
const color = (status: string) => {
if (status === "connected") return themeV2.text.feedback.success()
if (status === "failed") return themeV2.text.feedback.error()
if (status === "needs_auth") return themeV2.text.feedback.warning()
if (status === "needs_client_registration") return themeV2.text.feedback.error()
return themeV2.text.subdued()
}
return (
<box paddingLeft={2} paddingRight={2} gap={1} paddingBottom={1}>
<box flexDirection="row" justifyContent="space-between">
<text fg={theme.text} attributes={TextAttributes.BOLD}>
<text fg={themeV2.text()} attributes={TextAttributes.BOLD}>
Status
</text>
<text fg={theme.textMuted} onMouseUp={() => dialog.clear()}>
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
esc
</text>
</box>
<Show when={mcp().length > 0} fallback={<text fg={theme.text}>No MCP servers</text>}>
<Show when={mcp().length > 0} fallback={<text fg={themeV2.text()}>No MCP servers</text>}>
<box>
<text fg={theme.text}>
<text fg={themeV2.text()}>
{mcp().length} MCP server{mcp().length === 1 ? "" : "s"}
</text>
<For each={mcp()}>
{(item) => (
<box flexDirection="row" gap={1}>
<text
flexShrink={0}
style={{
fg: (
{
connected: theme.success,
failed: theme.error,
disabled: theme.textMuted,
needs_auth: theme.warning,
needs_client_registration: theme.error,
} as Record<string, typeof theme.success>
)[item.status.status],
}}
>
<text flexShrink={0} style={{ fg: color(item.status.status) }}>
</text>
<text fg={theme.text} wrapMode="word">
<text fg={themeV2.text()} wrapMode="word">
<b>{item.name}</b>{" "}
<span style={{ fg: theme.textMuted }}>
<span style={{ fg: themeV2.text.subdued() }}>
<Switch fallback={item.status.status}>
<Match when={item.status.status === "connected"}>Connected</Match>
<Match when={item.status.status === "failed" && item.status}>{(val) => val().error}</Match>
Expand Down
13 changes: 9 additions & 4 deletions packages/tui/src/component/plugin-route-missing.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { useTheme } from "../context/theme"

export function PluginRouteMissing(props: { id: string; name: string; onHome: () => void }) {
const { theme } = useTheme()
const { themeV2 } = useTheme()

return (
<box width="100%" height="100%" alignItems="center" justifyContent="center" flexDirection="column" gap={1}>
<text fg={theme.warning}>
<text fg={themeV2.text.feedback.warning()}>
Unknown plugin route: {props.id}/{props.name}
</text>
<box onMouseUp={props.onHome} backgroundColor={theme.backgroundElement} paddingLeft={1} paddingRight={1}>
<text fg={theme.text}>go home</text>
<box
onMouseUp={props.onHome}
backgroundColor={themeV2.background.action("hovered")}
paddingLeft={1}
paddingRight={1}
>
<text fg={themeV2.text.action("hovered")}>go home</text>
</box>
</box>
)
Expand Down
6 changes: 3 additions & 3 deletions packages/tui/src/component/reconnecting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useTheme } from "../context/theme"
import { Spinner } from "./spinner"

export function Reconnecting() {
const theme = useTheme().theme
const { themeV2 } = useTheme()

return (
<box
Expand All @@ -12,12 +12,12 @@ export function Reconnecting() {
right={0}
bottom={0}
left={0}
backgroundColor={theme.background}
backgroundColor={themeV2.background()}
alignItems="center"
justifyContent="center"
>
<box width={62} maxWidth="90%" flexDirection="column" alignItems="center" gap={1}>
<Spinner color={theme.textMuted}>Waiting for background service...</Spinner>
<Spinner color={themeV2.text.subdued()}>Waiting for background service...</Spinner>
</box>
</box>
)
Expand Down
6 changes: 3 additions & 3 deletions packages/tui/src/component/startup-loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useTheme } from "../context/theme"
import { Spinner } from "./spinner"

export function StartupLoading(props: { ready: () => boolean }) {
const theme = useTheme().theme
const { themeV2 } = useTheme().contextual("elevated")
const [show, setShow] = createSignal(false)
const text = createMemo(() => (props.ready() ? "Finishing startup..." : "Loading plugins..."))
let wait: NodeJS.Timeout | undefined
Expand Down Expand Up @@ -54,8 +54,8 @@ export function StartupLoading(props: { ready: () => boolean }) {
return (
<Show when={show()}>
<box position="absolute" zIndex={5000} left={0} right={0} bottom={1} justifyContent="center" alignItems="center">
<box backgroundColor={theme.backgroundPanel} paddingLeft={1} paddingRight={1}>
<Spinner color={theme.textMuted}>{text()}</Spinner>
<box backgroundColor={themeV2.background()} paddingLeft={1} paddingRight={1}>
<Spinner color={themeV2.text.subdued()}>{text()}</Spinner>
</box>
</box>
</Show>
Expand Down
12 changes: 6 additions & 6 deletions packages/tui/src/ui/dialog-alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type DialogAlertProps = {

export function DialogAlert(props: DialogAlertProps) {
const dialog = useDialog()
const { theme } = useTheme()
const { themeV2 } = useTheme().contextual("elevated")

Keymap.createLayer(() => ({
mode: "modal",
Expand All @@ -30,27 +30,27 @@ export function DialogAlert(props: DialogAlertProps) {
return (
<box paddingLeft={2} paddingRight={2} gap={1}>
<box flexDirection="row" justifyContent="space-between">
<text attributes={TextAttributes.BOLD} fg={theme.text}>
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
{props.title}
</text>
<text fg={theme.textMuted} onMouseUp={() => dialog.clear()}>
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
esc
</text>
</box>
<box paddingBottom={1}>
<text fg={theme.textMuted}>{props.message}</text>
<text fg={themeV2.text.subdued()}>{props.message}</text>
</box>
<box flexDirection="row" justifyContent="flex-end" paddingBottom={1}>
<box
paddingLeft={3}
paddingRight={3}
backgroundColor={theme.primary}
backgroundColor={themeV2.background.action("focused")}
onMouseUp={() => {
props.onConfirm?.()
dialog.clear()
}}
>
<text fg={theme.selectedListItemText}>ok</text>
<text fg={themeV2.text.action("focused")}>ok</text>
</box>
</box>
</box>
Expand Down
12 changes: 6 additions & 6 deletions packages/tui/src/ui/dialog-confirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type DialogConfirmResult = boolean | undefined

export function DialogConfirm(props: DialogConfirmProps) {
const dialog = useDialog()
const { theme } = useTheme()
const { themeV2 } = useTheme().contextual("elevated")
const [store, setStore] = createStore({
active: "confirm" as "confirm" | "cancel",
})
Expand Down Expand Up @@ -57,30 +57,30 @@ export function DialogConfirm(props: DialogConfirmProps) {
return (
<box paddingLeft={2} paddingRight={2} gap={1}>
<box flexDirection="row" justifyContent="space-between">
<text attributes={TextAttributes.BOLD} fg={theme.text}>
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
{props.title}
</text>
<text fg={theme.textMuted} onMouseUp={() => dialog.clear()}>
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
esc
</text>
</box>
<box paddingBottom={1}>
<text fg={theme.textMuted}>{props.message}</text>
<text fg={themeV2.text.subdued()}>{props.message}</text>
</box>
<box flexDirection="row" justifyContent="flex-end" paddingBottom={1}>
<For each={["cancel", "confirm"] as const}>
{(key) => (
<box
paddingLeft={1}
paddingRight={1}
backgroundColor={key === store.active ? theme.primary : undefined}
backgroundColor={key === store.active ? themeV2.background.action("focused") : undefined}
onMouseUp={() => {
if (key === "confirm") props.onConfirm?.()
if (key === "cancel") props.onCancel?.()
dialog.clear()
}}
>
<text fg={key === store.active ? theme.selectedListItemText : theme.textMuted}>
<text fg={key === store.active ? themeV2.text.action("focused") : themeV2.text.subdued()}>
{Locale.titlecase(key === "cancel" ? (props.label ?? key) : key)}
</text>
</box>
Expand Down
12 changes: 6 additions & 6 deletions packages/tui/src/ui/dialog-export-result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useDialog, type DialogContext } from "./dialog"

export function DialogExportResult(props: { path: string; onClose?: () => void }) {
const dialog = useDialog()
const { theme } = useTheme()
const { themeV2 } = useTheme().contextual("elevated")

const close = () => {
props.onClose?.()
Expand All @@ -27,19 +27,19 @@ export function DialogExportResult(props: { path: string; onClose?: () => void }
return (
<box paddingLeft={2} paddingRight={2} gap={1}>
<box flexDirection="row" justifyContent="space-between">
<text attributes={TextAttributes.BOLD} fg={theme.text}>
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
Session exported
</text>
<text fg={theme.textMuted} onMouseUp={close}>
<text fg={themeV2.text.subdued()} onMouseUp={close}>
esc
</text>
</box>
<box>
<text fg={theme.text}>{props.path}</text>
<text fg={themeV2.text()}>{props.path}</text>
</box>
<box flexDirection="row" justifyContent="flex-end" gap={1} paddingBottom={1}>
<box paddingLeft={3} paddingRight={3} backgroundColor={theme.primary} onMouseUp={close}>
<text fg={theme.selectedListItemText}>Close</text>
<box paddingLeft={3} paddingRight={3} backgroundColor={themeV2.background.action("focused")} onMouseUp={close}>
<text fg={themeV2.text.action("focused")}>Close</text>
</box>
</box>
</box>
Expand Down
Loading
Loading