refactor(tui): expose theme colors as properties (#37995)
This commit is contained in:
parent
8cb9361149
commit
c0ba62b972
46 changed files with 740 additions and 749 deletions
|
|
@ -1088,7 +1088,7 @@ function App(props: { pair?: DialogPairCredentials; started: number }) {
|
||||||
width={dimensions().width}
|
width={dimensions().width}
|
||||||
height={dimensions().height}
|
height={dimensions().height}
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
onMouseDown={(evt) => {
|
onMouseDown={(evt) => {
|
||||||
if (!Flag.OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT) return
|
if (!Flag.OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT) return
|
||||||
if (evt.button !== MouseButton.RIGHT) return
|
if (evt.button !== MouseButton.RIGHT) return
|
||||||
|
|
|
||||||
|
|
@ -17,26 +17,26 @@ export function DevToolsSidebar() {
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
>
|
>
|
||||||
<box flexShrink={0} marginBottom={1}>
|
<box flexShrink={0} marginBottom={1}>
|
||||||
<box marginBottom={1}>
|
<box marginBottom={1}>
|
||||||
<text fg={themeV2.text.action()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.action.primary.default} attributes={TextAttributes.BOLD}>
|
||||||
Theme
|
Theme
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row">
|
<box flexDirection="row">
|
||||||
<text fg={themeV2.text.subdued()}>Mode</text>
|
<text fg={themeV2.text.subdued}>Mode</text>
|
||||||
<box flexGrow={1} />
|
<box flexGrow={1} />
|
||||||
<box
|
<box
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
backgroundColor={modeHovered() && canSwitchMode() ? themeV2.background.action("hovered") : undefined}
|
backgroundColor={modeHovered() && canSwitchMode() ? themeV2.background.action.primary.hovered : undefined}
|
||||||
onMouseOver={() => setModeHovered(canSwitchMode())}
|
onMouseOver={() => setModeHovered(canSwitchMode())}
|
||||||
onMouseOut={() => setModeHovered(false)}
|
onMouseOut={() => setModeHovered(false)}
|
||||||
onMouseUp={canSwitchMode() ? () => setMode(nextMode()) : undefined}
|
onMouseUp={canSwitchMode() ? () => setMode(nextMode()) : undefined}
|
||||||
>
|
>
|
||||||
<text fg={canSwitchMode() ? themeV2.text() : themeV2.text.subdued()}>{mode()}</text>
|
<text fg={canSwitchMode() ? themeV2.text.default : themeV2.text.subdued}>{mode()}</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -44,16 +44,16 @@ export function DevToolsSidebar() {
|
||||||
{(group) => (
|
{(group) => (
|
||||||
<box flexShrink={0} marginBottom={1}>
|
<box flexShrink={0} marginBottom={1}>
|
||||||
<box marginBottom={1}>
|
<box marginBottom={1}>
|
||||||
<text fg={themeV2.text.action()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.action.primary.default} attributes={TextAttributes.BOLD}>
|
||||||
{group.title}
|
{group.title}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<For each={group.entries}>
|
<For each={group.entries}>
|
||||||
{(entry) => (
|
{(entry) => (
|
||||||
<box flexDirection="row">
|
<box flexDirection="row">
|
||||||
<text fg={themeV2.text.subdued()}>{entry.key}</text>
|
<text fg={themeV2.text.subdued}>{entry.key}</text>
|
||||||
<box flexGrow={1} />
|
<box flexGrow={1} />
|
||||||
<text fg={themeV2.text()}>{String(entry.value)}</text>
|
<text fg={themeV2.text.default}>{String(entry.value)}</text>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,10 @@ export function DialogDebug() {
|
||||||
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 fg={themeV2.text()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.default} attributes={TextAttributes.BOLD}>
|
||||||
Debug
|
Debug
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -67,10 +67,10 @@ export function DialogDebug() {
|
||||||
<For each={entries()}>
|
<For each={entries()}>
|
||||||
{(entry) => (
|
{(entry) => (
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<text flexShrink={0} fg={themeV2.text.subdued()}>
|
<text flexShrink={0} fg={themeV2.text.subdued}>
|
||||||
{entry.label.padEnd(10)}
|
{entry.label.padEnd(10)}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text()} wrapMode="word">
|
<text fg={themeV2.text.default} wrapMode="word">
|
||||||
{entry.value}
|
{entry.value}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -78,12 +78,12 @@ export function DialogDebug() {
|
||||||
</For>
|
</For>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text fg={themeV2.text.subdued()}>Share this when reporting an issue.</text>
|
<text fg={themeV2.text.subdued}>Share this when reporting an issue.</text>
|
||||||
<text onMouseUp={copy}>
|
<text onMouseUp={copy}>
|
||||||
<span style={{ fg: copied() ? themeV2.text.feedback.success() : themeV2.text() }}>
|
<span style={{ fg: copied() ? themeV2.text.feedback.success.default : themeV2.text.default }}>
|
||||||
<b>{copied() ? "✓ copied" : "copy"}</b>{" "}
|
<b>{copied() ? "✓ copied" : "copy"}</b>{" "}
|
||||||
</span>
|
</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>enter</span>
|
<span style={{ fg: themeV2.text.subdued }}>enter</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ export function DialogIntegration(props: { onConnected?: OnIntegrationConnected
|
||||||
footer: connectionSummary(integration) || undefined,
|
footer: connectionSummary(integration) || undefined,
|
||||||
category: integration.id in INTEGRATION_PRIORITY ? "Popular" : "Services",
|
category: integration.id in INTEGRATION_PRIORITY ? "Popular" : "Services",
|
||||||
disabled: methods.length === 0,
|
disabled: methods.length === 0,
|
||||||
gutter: connected ? () => <text fg={themeV2.text.feedback.success()}>✓</text> : undefined,
|
gutter: connected ? () => <text fg={themeV2.text.feedback.success.default}>✓</text> : undefined,
|
||||||
onSelect: () =>
|
onSelect: () =>
|
||||||
credentialConnections(integration).length
|
credentialConnections(integration).length
|
||||||
? manageConnections(integration, methods, dialog, props.onConnected)
|
? manageConnections(integration, methods, dialog, props.onConnected)
|
||||||
|
|
@ -89,12 +89,12 @@ export function DialogIntegration(props: { onConnected?: OnIntegrationConnected
|
||||||
options={options()}
|
options={options()}
|
||||||
emptyView={
|
emptyView={
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.subdued()}>No integrations available</text>
|
<text fg={themeV2.text.subdued}>No integrations available</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
noMatchView={
|
noMatchView={
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.subdued()}>No integrations found</text>
|
<text fg={themeV2.text.subdued}>No integrations found</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
@ -295,24 +295,24 @@ function CommandView(props: { title: string; output: string; message: string })
|
||||||
return (
|
return (
|
||||||
<box gap={1} paddingBottom={1}>
|
<box gap={1} paddingBottom={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between" paddingLeft={2} paddingRight={2}>
|
<box flexDirection="row" justifyContent="space-between" paddingLeft={2} paddingRight={2}>
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
{props.title}
|
{props.title}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc close
|
esc close
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box
|
||||||
backgroundColor={overlayTheme.background()}
|
backgroundColor={overlayTheme.background.default}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
>
|
>
|
||||||
<text fg={overlayTheme.text()}>{props.output.trim()}</text>
|
<text fg={overlayTheme.text.default}>{props.output.trim()}</text>
|
||||||
</box>
|
</box>
|
||||||
<box paddingLeft={2} paddingRight={2}>
|
<box paddingLeft={2} paddingRight={2}>
|
||||||
<text fg={themeV2.text.subdued()}>{props.message}</text>
|
<text fg={themeV2.text.subdued}>{props.message}</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
|
|
@ -346,7 +346,7 @@ function KeyMethod(props: {
|
||||||
.catch((cause) => setError(message(cause)))
|
.catch((cause) => setError(message(cause)))
|
||||||
}}
|
}}
|
||||||
description={() => (
|
description={() => (
|
||||||
<Show when={error()}>{(value) => <text fg={themeV2.text.feedback.error()}>{value()}</text>}</Show>
|
<Show when={error()}>{(value) => <text fg={themeV2.text.feedback.error.default}>{value()}</text>}</Show>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
@ -536,9 +536,9 @@ function OAuthCode(props: {
|
||||||
}}
|
}}
|
||||||
description={() => (
|
description={() => (
|
||||||
<box gap={1}>
|
<box gap={1}>
|
||||||
<text fg={themeV2.text.subdued()}>{props.attempt.instructions}</text>
|
<text fg={themeV2.text.subdued}>{props.attempt.instructions}</text>
|
||||||
<Link href={props.attempt.url} fg={themeV2.markdown.link()} />
|
<Link href={props.attempt.url} fg={themeV2.markdown.link} />
|
||||||
<Show when={error()}>{(value) => <text fg={themeV2.text.feedback.error()}>{value()}</text>}</Show>
|
<Show when={error()}>{(value) => <text fg={themeV2.text.feedback.error.default}>{value()}</text>}</Show>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -551,27 +551,27 @@ function OAuthView(props: { title: string; url?: string; instructions?: string;
|
||||||
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} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
{props.title}
|
{props.title}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={props.url}>
|
<Show when={props.url}>
|
||||||
{(url) => (
|
{(url) => (
|
||||||
<box gap={1}>
|
<box gap={1}>
|
||||||
<Link href={url()} fg={themeV2.markdown.link()} />
|
<Link href={url()} fg={themeV2.markdown.link} />
|
||||||
<Show when={props.instructions}>
|
<Show when={props.instructions}>
|
||||||
{(instructions) => <text fg={themeV2.text.subdued()}>{instructions()}</text>}
|
{(instructions) => <text fg={themeV2.text.subdued}>{instructions()}</text>}
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</Show>
|
</Show>
|
||||||
<text fg={themeV2.text.subdued()}>{props.message}</text>
|
<text fg={themeV2.text.subdued}>{props.message}</text>
|
||||||
<Show when={props.copy}>
|
<Show when={props.copy}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
c <span style={{ fg: themeV2.text.subdued() }}>copy</span>
|
c <span style={{ fg: themeV2.text.subdued }}>copy</span>
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,11 @@ function statusError(status: McpServer["status"]) {
|
||||||
|
|
||||||
function Status(props: { enabled: boolean; loading: boolean }) {
|
function Status(props: { enabled: boolean; loading: boolean }) {
|
||||||
const { themeV2 } = useTheme().contextual("elevated")
|
const { themeV2 } = useTheme().contextual("elevated")
|
||||||
if (props.loading) return <span style={{ fg: themeV2.text.subdued() }}>⋯ Loading</span>
|
if (props.loading) return <span style={{ fg: themeV2.text.subdued }}>⋯ Loading</span>
|
||||||
if (props.enabled) {
|
if (props.enabled) {
|
||||||
return <span style={{ fg: themeV2.text.feedback.success(), attributes: TextAttributes.BOLD }}>✓ Enabled</span>
|
return <span style={{ fg: themeV2.text.feedback.success.default, attributes: TextAttributes.BOLD }}>✓ Enabled</span>
|
||||||
}
|
}
|
||||||
return <span style={{ fg: themeV2.text.subdued() }}>○ Disabled</span>
|
return <span style={{ fg: themeV2.text.subdued }}>○ Disabled</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DialogMcp() {
|
export function DialogMcp() {
|
||||||
|
|
@ -110,7 +110,7 @@ export function DialogMcp() {
|
||||||
]}
|
]}
|
||||||
footer={
|
footer={
|
||||||
<Show when={focusedError()}>
|
<Show when={focusedError()}>
|
||||||
<text fg={themeV2.text.subdued()}>enter to view error</text>
|
<text fg={themeV2.text.subdued}>enter to view error</text>
|
||||||
</Show>
|
</Show>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
@ -171,16 +171,16 @@ function DialogMcpError(props: { server: McpServer; onBack: () => void }) {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={4} paddingRight={4} paddingBottom={1} gap={1}>
|
<box paddingLeft={4} paddingRight={4} paddingBottom={1} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
MCP server: {props.server.name}
|
MCP server: {props.server.name}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={props.onBack}>
|
<text fg={themeV2.text.subdued} onMouseUp={props.onBack}>
|
||||||
esc back
|
esc back
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<text fg={themeV2.text.feedback.error()}>✗ Failed</text>
|
<text fg={themeV2.text.feedback.error.default}>✗ Failed</text>
|
||||||
<box
|
<box
|
||||||
backgroundColor={overlayTheme.background()}
|
backgroundColor={overlayTheme.background.default}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
|
|
@ -192,14 +192,14 @@ function DialogMcpError(props: { server: McpServer; onBack: () => void }) {
|
||||||
scrollbarOptions={{ visible: false }}
|
scrollbarOptions={{ visible: false }}
|
||||||
scrollAcceleration={getScrollAcceleration(config)}
|
scrollAcceleration={getScrollAcceleration(config)}
|
||||||
>
|
>
|
||||||
<text fg={overlayTheme.text()} wrapMode="word">
|
<text fg={overlayTheme.text.default} wrapMode="word">
|
||||||
{error()}
|
{error()}
|
||||||
</text>
|
</text>
|
||||||
</scrollbox>
|
</scrollbox>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text fg={themeV2.text.subdued()}>↑↓ scroll</text>
|
<text fg={themeV2.text.subdued}>↑↓ scroll</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={copy}>
|
<text fg={themeV2.text.subdued} onMouseUp={copy}>
|
||||||
{copied() ? "✓ copied" : "c copy details"}
|
{copied() ? "✓ copied" : "c copy details"}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -172,18 +172,18 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
|
||||||
return {
|
return {
|
||||||
title,
|
title,
|
||||||
titleView: isRemoving ? (
|
titleView: isRemoving ? (
|
||||||
<span style={{ fg: themeV2.text.feedback.error() }}>Deleting {item.location}</span>
|
<span style={{ fg: themeV2.text.feedback.error.default }}>Deleting {item.location}</span>
|
||||||
) : deleting ? (
|
) : deleting ? (
|
||||||
<span style={{ fg: themeV2.text.action.destructive() }}>
|
<span style={{ fg: themeV2.text.action.destructive.default }}>
|
||||||
Press {shortcuts.get("dialog.move_session.delete")} again to confirm
|
Press {shortcuts.get("dialog.move_session.delete")} again to confirm
|
||||||
</span>
|
</span>
|
||||||
) : suffix ? (
|
) : suffix ? (
|
||||||
<>
|
<>
|
||||||
{visible.slice(0, split)}
|
{visible.slice(0, split)}
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{visible.slice(split)}</span>
|
<span style={{ fg: themeV2.text.subdued }}>{visible.slice(split)}</span>
|
||||||
</>
|
</>
|
||||||
) : undefined,
|
) : undefined,
|
||||||
bg: deleting ? themeV2.background.action.destructive() : undefined,
|
bg: deleting ? themeV2.background.action.destructive.default : undefined,
|
||||||
value: {
|
value: {
|
||||||
type: "directory",
|
type: "directory",
|
||||||
directory: item.location,
|
directory: item.location,
|
||||||
|
|
@ -316,7 +316,7 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
|
||||||
title="Move session"
|
title="Move session"
|
||||||
titleView={
|
titleView={
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<text fg={themeV2.text()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.default} attributes={TextAttributes.BOLD}>
|
||||||
Move session
|
Move session
|
||||||
</text>
|
</text>
|
||||||
<Show when={working() || directories.loading || loadedProject.loading}>
|
<Show when={working() || directories.loading || loadedProject.loading}>
|
||||||
|
|
@ -329,25 +329,25 @@ export function DialogMoveSession(props: DialogMoveSessionProps) {
|
||||||
emptyView={
|
emptyView={
|
||||||
showError() ? (
|
showError() ? (
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.feedback.error()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.feedback.error.default} attributes={TextAttributes.BOLD}>
|
||||||
Could not load project directories
|
Could not load project directories
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()}>{errorMessage(loadError())}</text>
|
<text fg={themeV2.text.subdued}>{errorMessage(loadError())}</text>
|
||||||
<text fg={themeV2.text.subdued()}>Close and reopen Move session to try again.</text>
|
<text fg={themeV2.text.subdued}>Close and reopen Move session to try again.</text>
|
||||||
</box>
|
</box>
|
||||||
) : directories.loading || loadedProject.loading ? (
|
) : directories.loading || loadedProject.loading ? (
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.subdued()}>Loading project directories…</text>
|
<text fg={themeV2.text.subdued}>Loading project directories…</text>
|
||||||
</box>
|
</box>
|
||||||
) : (
|
) : (
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.subdued()}>No project directories available</text>
|
<text fg={themeV2.text.subdued}>No project directories available</text>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
noMatchView={
|
noMatchView={
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.subdued()}>No project directories found</text>
|
<text fg={themeV2.text.subdued}>No project directories found</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
locked={showError() || directories.loading || loadedProject.loading || Boolean(removing())}
|
locked={showError() || directories.loading || loadedProject.loading || Boolean(removing())}
|
||||||
|
|
|
||||||
|
|
@ -47,17 +47,17 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
|
||||||
<box flexDirection={horizontal() ? "row" : "column"} alignItems={horizontal() ? "flex-start" : "center"} gap={2}>
|
<box flexDirection={horizontal() ? "row" : "column"} alignItems={horizontal() ? "flex-start" : "center"} gap={2}>
|
||||||
<box width={horizontal() ? 29 : "100%"} flexShrink={0} gap={1}>
|
<box width={horizontal() ? 29 : "100%"} flexShrink={0} gap={1}>
|
||||||
<box>
|
<box>
|
||||||
<text fg={themeV2.text.subdued()}>URLs</text>
|
<text fg={themeV2.text.subdued}>URLs</text>
|
||||||
<For each={value.urls}>{(url) => <text fg={themeV2.text()}>{url}</text>}</For>
|
<For each={value.urls}>{(url) => <text fg={themeV2.text.default}>{url}</text>}</For>
|
||||||
</box>
|
</box>
|
||||||
<box>
|
<box>
|
||||||
<text fg={themeV2.text.subdued()}>Username</text>
|
<text fg={themeV2.text.subdued}>Username</text>
|
||||||
<text fg={themeV2.text()}>{value.username}</text>
|
<text fg={themeV2.text.default}>{value.username}</text>
|
||||||
</box>
|
</box>
|
||||||
<box>
|
<box>
|
||||||
<text fg={themeV2.text.subdued()}>Password</text>
|
<text fg={themeV2.text.subdued}>Password</text>
|
||||||
<text
|
<text
|
||||||
fg={passwordHover() ? themeV2.text() : themeV2.text.subdued()}
|
fg={passwordHover() ? themeV2.text.default : themeV2.text.subdued}
|
||||||
wrapMode="word"
|
wrapMode="word"
|
||||||
onMouseOver={() => setPasswordHover(true)}
|
onMouseOver={() => setPasswordHover(true)}
|
||||||
onMouseOut={() => setPasswordHover(false)}
|
onMouseOut={() => setPasswordHover(false)}
|
||||||
|
|
@ -67,7 +67,7 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={value.urls.some((url) => ["localhost", "127.0.0.1", "[::1]"].includes(new URL(url).hostname))}>
|
<Show when={value.urls.some((url) => ["localhost", "127.0.0.1", "[::1]"].includes(new URL(url).hostname))}>
|
||||||
<text fg={themeV2.text.subdued()} wrapMode="word">
|
<text fg={themeV2.text.subdued} wrapMode="word">
|
||||||
Run `opencode service set hostname 0.0.0.0` to access the service remotely.
|
Run `opencode service set hostname 0.0.0.0` to access the service remotely.
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -78,7 +78,7 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
alignItems={horizontal() ? "flex-end" : "center"}
|
alignItems={horizontal() ? "flex-end" : "center"}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text()}>{renderUnicodeCompact(JSON.stringify(value), { border: 1 })}</text>
|
<text fg={themeV2.text.default}>{renderUnicodeCompact(JSON.stringify(value), { border: 1 })}</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
|
|
@ -87,17 +87,17 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} paddingBottom={1} gap={1}>
|
<box paddingLeft={2} paddingRight={2} paddingBottom={1} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text fg={themeV2.text()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.default} attributes={TextAttributes.BOLD}>
|
||||||
Pair
|
Pair
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<Show
|
<Show
|
||||||
when={loadError()}
|
when={loadError()}
|
||||||
fallback={
|
fallback={
|
||||||
<Show when={info()} fallback={<text fg={themeV2.text.subdued()}>Loading server information…</text>}>
|
<Show when={info()} fallback={<text fg={themeV2.text.subdued}>Loading server information…</text>}>
|
||||||
<Show
|
<Show
|
||||||
when={dimensions().height >= 36}
|
when={dimensions().height >= 36}
|
||||||
fallback={
|
fallback={
|
||||||
|
|
@ -116,11 +116,11 @@ export function DialogPair(props: { credentials?: DialogPairCredentials }) {
|
||||||
>
|
>
|
||||||
{(error) => (
|
{(error) => (
|
||||||
<box>
|
<box>
|
||||||
<text fg={themeV2.text.feedback.error()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.feedback.error.default} attributes={TextAttributes.BOLD}>
|
||||||
Could not load server information
|
Could not load server information
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()}>{errorMessage(error())}</text>
|
<text fg={themeV2.text.subdued}>{errorMessage(error())}</text>
|
||||||
<text fg={themeV2.text.subdued()}>Close and reopen Pair to try again.</text>
|
<text fg={themeV2.text.subdued}>Close and reopen Pair to try again.</text>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</Show>
|
</Show>
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,10 @@ export function DialogProjectCopyName(props: { onConfirm: (name: string) => void
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
Name project copy
|
Name project copy
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -61,18 +61,17 @@ export function DialogProjectCopyName(props: { onConfirm: (name: string) => void
|
||||||
}}
|
}}
|
||||||
onSubmit={confirm}
|
onSubmit={confirm}
|
||||||
placeholder="Project copy name"
|
placeholder="Project copy name"
|
||||||
placeholderColor={themeV2.text.subdued()}
|
placeholderColor={themeV2.text.subdued}
|
||||||
textColor={themeV2.text.formfield()}
|
textColor={themeV2.text.formfield.default}
|
||||||
focusedTextColor={themeV2.text.formfield()}
|
focusedTextColor={themeV2.text.formfield.default}
|
||||||
cursorColor={themeV2.text.formfield()}
|
cursorColor={themeV2.text.formfield.default}
|
||||||
/>
|
/>
|
||||||
<box paddingBottom={1} flexDirection="row" gap={2}>
|
<box paddingBottom={1} flexDirection="row" gap={2}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
enter <span style={{ fg: themeV2.text.subdued() }}>submit</span>
|
enter <span style={{ fg: themeV2.text.subdued }}>submit</span>
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
{shortcuts.get("dialog.project_copy.generate")}{" "}
|
{shortcuts.get("dialog.project_copy.generate")} <span style={{ fg: themeV2.text.subdued }}>generate one</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>generate one</span>
|
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ export function DialogRetryAction(props: DialogRetryActionProps) {
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
const { themeV2 } = useTheme().contextual("elevated")
|
const { themeV2 } = useTheme().contextual("elevated")
|
||||||
const showGoTreatment = () => props.link === GO_URL
|
const showGoTreatment = () => props.link === GO_URL
|
||||||
const textBg = () => (showGoTreatment() ? panelOverlay(themeV2.background()) : undefined)
|
const textBg = () => (showGoTreatment() ? panelOverlay(themeV2.background.default) : undefined)
|
||||||
const [selected, setSelected] = createSignal<"dismiss" | "action">("action")
|
const [selected, setSelected] = createSignal<"dismiss" | "action">("action")
|
||||||
|
|
||||||
Keymap.createLayer(() => ({
|
Keymap.createLayer(() => ({
|
||||||
|
|
@ -85,26 +85,26 @@ export function DialogRetryAction(props: DialogRetryActionProps) {
|
||||||
) : null}
|
) : null}
|
||||||
<box zIndex={1} paddingLeft={PAD_X} paddingRight={PAD_X} paddingBottom={1} gap={1}>
|
<box zIndex={1} paddingLeft={PAD_X} paddingRight={PAD_X} paddingBottom={1} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()} bg={textBg()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default} bg={textBg()}>
|
||||||
{props.title}
|
{props.title}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} bg={textBg()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} bg={textBg()} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box gap={0}>
|
<box gap={0}>
|
||||||
<text fg={themeV2.text.subdued()} bg={textBg()}>
|
<text fg={themeV2.text.subdued} bg={textBg()}>
|
||||||
{props.message}
|
{props.message}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
{props.link ? (
|
{props.link ? (
|
||||||
showGoTreatment() ? (
|
showGoTreatment() ? (
|
||||||
<box alignItems="center" justifyContent="flex-end" height={7} paddingBottom={1}>
|
<box alignItems="center" justifyContent="flex-end" height={7} paddingBottom={1}>
|
||||||
<Link href={props.link} fg={themeV2.markdown.link()} bg={textBg()} wrapMode="none" />
|
<Link href={props.link} fg={themeV2.markdown.link} bg={textBg()} wrapMode="none" />
|
||||||
</box>
|
</box>
|
||||||
) : (
|
) : (
|
||||||
<box width="100%" flexDirection="row" justifyContent="center" paddingBottom={1}>
|
<box width="100%" flexDirection="row" justifyContent="center" paddingBottom={1}>
|
||||||
<Link href={props.link} fg={themeV2.markdown.link()} wrapMode="none" />
|
<Link href={props.link} fg={themeV2.markdown.link} wrapMode="none" />
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -115,13 +115,13 @@ export function DialogRetryAction(props: DialogRetryActionProps) {
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
backgroundColor={
|
backgroundColor={
|
||||||
selected() === "dismiss" ? themeV2.background.action("focused") : RGBA.fromInts(0, 0, 0, 0)
|
selected() === "dismiss" ? themeV2.background.action.primary.focused : RGBA.fromInts(0, 0, 0, 0)
|
||||||
}
|
}
|
||||||
onMouseOver={() => setSelected("dismiss")}
|
onMouseOver={() => setSelected("dismiss")}
|
||||||
onMouseUp={() => dismiss(props, dialog)}
|
onMouseUp={() => dismiss(props, dialog)}
|
||||||
>
|
>
|
||||||
<text
|
<text
|
||||||
fg={selected() === "dismiss" ? themeV2.text.action("focused") : themeV2.text.subdued()}
|
fg={selected() === "dismiss" ? themeV2.text.action.primary.focused : themeV2.text.subdued}
|
||||||
bg={selected() === "dismiss" ? undefined : textBg()}
|
bg={selected() === "dismiss" ? undefined : textBg()}
|
||||||
attributes={selected() === "dismiss" ? TextAttributes.BOLD : undefined}
|
attributes={selected() === "dismiss" ? TextAttributes.BOLD : undefined}
|
||||||
>
|
>
|
||||||
|
|
@ -131,12 +131,14 @@ export function DialogRetryAction(props: DialogRetryActionProps) {
|
||||||
<box
|
<box
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
backgroundColor={selected() === "action" ? themeV2.background.action("focused") : RGBA.fromInts(0, 0, 0, 0)}
|
backgroundColor={
|
||||||
|
selected() === "action" ? themeV2.background.action.primary.focused : RGBA.fromInts(0, 0, 0, 0)
|
||||||
|
}
|
||||||
onMouseOver={() => setSelected("action")}
|
onMouseOver={() => setSelected("action")}
|
||||||
onMouseUp={() => runAction(props, dialog)}
|
onMouseUp={() => runAction(props, dialog)}
|
||||||
>
|
>
|
||||||
<text
|
<text
|
||||||
fg={selected() === "action" ? themeV2.text.action("focused") : themeV2.text()}
|
fg={selected() === "action" ? themeV2.text.action.primary.focused : themeV2.text.default}
|
||||||
bg={selected() === "action" ? undefined : textBg()}
|
bg={selected() === "action" ? undefined : textBg()}
|
||||||
attributes={selected() === "action" ? TextAttributes.BOLD : undefined}
|
attributes={selected() === "action" ? TextAttributes.BOLD : undefined}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -64,17 +64,17 @@ export function DialogSessionDeleteFailed(props: {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
Failed to Delete Session
|
Failed to Delete Session
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<text fg={themeV2.text.subdued()} wrapMode="word">
|
<text fg={themeV2.text.subdued} wrapMode="word">
|
||||||
{`The session "${props.session}" could not be deleted because the workspace "${props.workspace}" is not available.`}
|
{`The session "${props.session}" could not be deleted because the workspace "${props.workspace}" is not available.`}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} wrapMode="word">
|
<text fg={themeV2.text.subdued} wrapMode="word">
|
||||||
Choose how you want to recover this broken workspace session.
|
Choose how you want to recover this broken workspace session.
|
||||||
</text>
|
</text>
|
||||||
<box flexDirection="column" paddingBottom={1} gap={1}>
|
<box flexDirection="column" paddingBottom={1} gap={1}>
|
||||||
|
|
@ -86,7 +86,7 @@ export function DialogSessionDeleteFailed(props: {
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
backgroundColor={item.id === store.active ? themeV2.background.action("focused") : undefined}
|
backgroundColor={item.id === store.active ? themeV2.background.action.primary.focused : undefined}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
setStore("active", item.id)
|
setStore("active", item.id)
|
||||||
void confirm()
|
void confirm()
|
||||||
|
|
@ -94,12 +94,12 @@ export function DialogSessionDeleteFailed(props: {
|
||||||
>
|
>
|
||||||
<text
|
<text
|
||||||
attributes={TextAttributes.BOLD}
|
attributes={TextAttributes.BOLD}
|
||||||
fg={item.id === store.active ? themeV2.text.action("focused") : themeV2.text()}
|
fg={item.id === store.active ? themeV2.text.action.primary.focused : themeV2.text.default}
|
||||||
>
|
>
|
||||||
{item.title}
|
{item.title}
|
||||||
</text>
|
</text>
|
||||||
<text
|
<text
|
||||||
fg={item.id === store.active ? themeV2.text.action("focused") : themeV2.text.subdued()}
|
fg={item.id === store.active ? themeV2.text.action.primary.focused : themeV2.text.subdued}
|
||||||
wrapMode="word"
|
wrapMode="word"
|
||||||
>
|
>
|
||||||
{item.description}
|
{item.description}
|
||||||
|
|
|
||||||
|
|
@ -63,29 +63,29 @@ export function DialogSkill(props: DialogSkillProps) {
|
||||||
<Switch
|
<Switch
|
||||||
fallback={
|
fallback={
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.subdued()}>No skills available</text>
|
<text fg={themeV2.text.subdued}>No skills available</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Match when={showError()}>
|
<Match when={showError()}>
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.feedback.error()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.feedback.error.default} attributes={TextAttributes.BOLD}>
|
||||||
Could not load skills
|
Could not load skills
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()}>{errorMessage(loadError())}</text>
|
<text fg={themeV2.text.subdued}>{errorMessage(loadError())}</text>
|
||||||
<text fg={themeV2.text.subdued()}>Close and reopen Skills to try again.</text>
|
<text fg={themeV2.text.subdued}>Close and reopen Skills to try again.</text>
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={skills.loading}>
|
<Match when={skills.loading}>
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.subdued()}>Loading skills…</text>
|
<text fg={themeV2.text.subdued}>Loading skills…</text>
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
}
|
}
|
||||||
noMatchView={
|
noMatchView={
|
||||||
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
<box paddingLeft={4} paddingRight={4} paddingTop={1}>
|
||||||
<text fg={themeV2.text.subdued()}>No skills found</text>
|
<text fg={themeV2.text.subdued}>No skills found</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -13,25 +13,25 @@ export function DialogStatus() {
|
||||||
|
|
||||||
const mcp = createMemo(() => data.location.mcp.server.list() ?? [])
|
const mcp = createMemo(() => data.location.mcp.server.list() ?? [])
|
||||||
const color = (status: string) => {
|
const color = (status: string) => {
|
||||||
if (status === "connected") return themeV2.text.feedback.success()
|
if (status === "connected") return themeV2.text.feedback.success.default
|
||||||
if (status === "failed") return themeV2.text.feedback.error()
|
if (status === "failed") return themeV2.text.feedback.error.default
|
||||||
if (status === "needs_auth") return themeV2.text.feedback.warning()
|
if (status === "needs_auth") return themeV2.text.feedback.warning.default
|
||||||
if (status === "needs_client_registration") return themeV2.text.feedback.error()
|
if (status === "needs_client_registration") return themeV2.text.feedback.error.default
|
||||||
return themeV2.text.subdued()
|
return themeV2.text.subdued
|
||||||
}
|
}
|
||||||
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 fg={themeV2.text()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.default} attributes={TextAttributes.BOLD}>
|
||||||
Status
|
Status
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={mcp().length > 0} fallback={<text fg={themeV2.text()}>No MCP servers</text>}>
|
<Show when={mcp().length > 0} fallback={<text fg={themeV2.text.default}>No MCP servers</text>}>
|
||||||
<box>
|
<box>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
{mcp().length} MCP server{mcp().length === 1 ? "" : "s"}
|
{mcp().length} MCP server{mcp().length === 1 ? "" : "s"}
|
||||||
</text>
|
</text>
|
||||||
<For each={mcp()}>
|
<For each={mcp()}>
|
||||||
|
|
@ -40,9 +40,9 @@ export function DialogStatus() {
|
||||||
<text flexShrink={0} style={{ fg: color(item.status.status) }}>
|
<text flexShrink={0} style={{ fg: color(item.status.status) }}>
|
||||||
•
|
•
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text()} wrapMode="word">
|
<text fg={themeV2.text.default} wrapMode="word">
|
||||||
<b>{item.name}</b>{" "}
|
<b>{item.name}</b>{" "}
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>
|
<span style={{ fg: themeV2.text.subdued }}>
|
||||||
<Switch fallback={item.status.status}>
|
<Switch fallback={item.status.status}>
|
||||||
<Match when={item.status.status === "connected"}>Connected</Match>
|
<Match when={item.status.status === "connected"}>Connected</Match>
|
||||||
<Match when={item.status.status === "failed" && item.status}>{(val) => val().error}</Match>
|
<Match when={item.status.status === "failed" && item.status}>{(val) => val().error}</Match>
|
||||||
|
|
|
||||||
|
|
@ -72,21 +72,21 @@ export function DialogWorkspaceFileChanges(props: {
|
||||||
return (
|
return (
|
||||||
<box gap={1}>
|
<box gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between" paddingLeft={2} paddingRight={2}>
|
<box flexDirection="row" justifyContent="space-between" paddingLeft={2} paddingRight={2}>
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
{props.title ?? "File Changes Found"}
|
{props.title ?? "File Changes Found"}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box paddingLeft={2} paddingRight={2}>
|
<box paddingLeft={2} paddingRight={2}>
|
||||||
<text fg={themeV2.text.subdued()} wrapMode="word">
|
<text fg={themeV2.text.subdued} wrapMode="word">
|
||||||
{props.message ?? "Do you want to move these changes with the session?"}
|
{props.message ?? "Do you want to move these changes with the session?"}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<scrollbox
|
<scrollbox
|
||||||
height={height()}
|
height={height()}
|
||||||
backgroundColor={overlayTheme.background()}
|
backgroundColor={overlayTheme.background.default}
|
||||||
scrollbarOptions={{ visible: false }}
|
scrollbarOptions={{ visible: false }}
|
||||||
scrollAcceleration={scrollAcceleration()}
|
scrollAcceleration={scrollAcceleration()}
|
||||||
>
|
>
|
||||||
|
|
@ -95,18 +95,16 @@ export function DialogWorkspaceFileChanges(props: {
|
||||||
<box flexDirection="row" justifyContent="space-between" paddingLeft={2} paddingRight={2}>
|
<box flexDirection="row" justifyContent="space-between" paddingLeft={2} paddingRight={2}>
|
||||||
<box flexDirection="row" minWidth={0} flexShrink={1}>
|
<box flexDirection="row" minWidth={0} flexShrink={1}>
|
||||||
<box width={2} flexShrink={0}>
|
<box width={2} flexShrink={0}>
|
||||||
<text fg={overlayTheme.text.subdued()}>{statusLabel(item.status)}</text>
|
<text fg={overlayTheme.text.subdued}>{statusLabel(item.status)}</text>
|
||||||
</box>
|
</box>
|
||||||
<FilePath value={item.file} maxWidth={fileNameWidth()} fg={overlayTheme.text.subdued()} />
|
<FilePath value={item.file} maxWidth={fileNameWidth()} fg={overlayTheme.text.subdued} />
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" gap={1} minWidth={7} flexShrink={0} justifyContent="flex-end">
|
<box flexDirection="row" gap={1} minWidth={7} flexShrink={0} justifyContent="flex-end">
|
||||||
<text>
|
<text>
|
||||||
{" "}
|
{" "}
|
||||||
{item.additions ? (
|
{item.additions ? <span style={{ fg: overlayTheme.diff.text.added }}>+{item.additions}</span> : null}
|
||||||
<span style={{ fg: overlayTheme.diff.text.added() }}>+{item.additions}</span>
|
|
||||||
) : null}
|
|
||||||
{item.deletions ? (
|
{item.deletions ? (
|
||||||
<span style={{ fg: overlayTheme.diff.text.removed() }}> -{item.deletions}</span>
|
<span style={{ fg: overlayTheme.diff.text.removed }}> -{item.deletions}</span>
|
||||||
) : null}
|
) : null}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -120,14 +118,16 @@ export function DialogWorkspaceFileChanges(props: {
|
||||||
<box
|
<box
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
backgroundColor={item === store.active ? themeV2.background.action("focused") : undefined}
|
backgroundColor={item === store.active ? themeV2.background.action.primary.focused : undefined}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
setStore("active", item)
|
setStore("active", item)
|
||||||
props.onSelect(item)
|
props.onSelect(item)
|
||||||
dialog.clear()
|
dialog.clear()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<text fg={item === store.active ? themeV2.text.action("focused") : themeV2.text.subdued()}>{item}</text>
|
<text fg={item === store.active ? themeV2.text.action.primary.focused : themeV2.text.subdued}>
|
||||||
|
{item}
|
||||||
|
</text>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ export function Logo() {
|
||||||
const { themeV2 } = useTheme()
|
const { themeV2 } = useTheme()
|
||||||
|
|
||||||
const renderLine = (line: string, fg: RGBA, bold: boolean): JSX.Element[] => {
|
const renderLine = (line: string, fg: RGBA, bold: boolean): JSX.Element[] => {
|
||||||
const shadow = tint(themeV2.background(), fg, 0.25)
|
const shadow = tint(themeV2.background.default, fg, 0.25)
|
||||||
const attrs = bold ? TextAttributes.BOLD : undefined
|
const attrs = bold ? TextAttributes.BOLD : undefined
|
||||||
return Array.from(line).map((char) => {
|
return Array.from(line).map((char) => {
|
||||||
if (char === "_") {
|
if (char === "_") {
|
||||||
|
|
@ -52,8 +52,8 @@ export function Logo() {
|
||||||
<For each={logo.left}>
|
<For each={logo.left}>
|
||||||
{(line, index) => (
|
{(line, index) => (
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<box flexDirection="row">{renderLine(line, themeV2.text.subdued(), false)}</box>
|
<box flexDirection="row">{renderLine(line, themeV2.text.subdued, false)}</box>
|
||||||
<box flexDirection="row">{renderLine(logo.right[index()], themeV2.text(), true)}</box>
|
<box flexDirection="row">{renderLine(logo.right[index()], themeV2.text.default, true)}</box>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,16 @@ export function PluginRouteMissing(props: { id: string; name: string; onHome: ()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box width="100%" height="100%" alignItems="center" justifyContent="center" flexDirection="column" gap={1}>
|
<box width="100%" height="100%" alignItems="center" justifyContent="center" flexDirection="column" gap={1}>
|
||||||
<text fg={themeV2.text.feedback.warning()}>
|
<text fg={themeV2.text.feedback.warning.default}>
|
||||||
Unknown plugin route: {props.id}/{props.name}
|
Unknown plugin route: {props.id}/{props.name}
|
||||||
</text>
|
</text>
|
||||||
<box
|
<box
|
||||||
onMouseUp={props.onHome}
|
onMouseUp={props.onHome}
|
||||||
backgroundColor={themeV2.background.action("hovered")}
|
backgroundColor={themeV2.background.action.primary.hovered}
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.action("hovered")}>go home</text>
|
<text fg={themeV2.text.action.primary.hovered}>go home</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -297,8 +297,8 @@ export function Prompt(props: PromptProps) {
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (!input || input.isDestroyed) return
|
if (!input || input.isDestroyed) return
|
||||||
if (props.disabled) input.cursorColor = themeV2.background.surface.offset()
|
if (props.disabled) input.cursorColor = themeV2.background.surface.offset
|
||||||
if (!props.disabled) input.cursorColor = themeV2.text()
|
if (!props.disabled) input.cursorColor = themeV2.text.default
|
||||||
})
|
})
|
||||||
|
|
||||||
const usage = createMemo(() => {
|
const usage = createMemo(() => {
|
||||||
|
|
@ -1304,10 +1304,10 @@ export function Prompt(props: PromptProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const highlight = createMemo(() => {
|
const highlight = createMemo(() => {
|
||||||
if (leader()) return themeV2.border()
|
if (leader()) return themeV2.border.default
|
||||||
if (store.mode === "shell") return themeV2.background.action()
|
if (store.mode === "shell") return themeV2.background.action.primary.default
|
||||||
const agent = local.agent.current()
|
const agent = local.agent.current()
|
||||||
if (!agent) return themeV2.border()
|
if (!agent) return themeV2.border.default
|
||||||
return local.agent.color(agent.id)
|
return local.agent.color(agent.id)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -1324,7 +1324,7 @@ export function Prompt(props: PromptProps) {
|
||||||
() => !!local.agent.current() && store.mode === "normal" && showVariant(),
|
() => !!local.agent.current() && store.mode === "normal" && showVariant(),
|
||||||
animationsEnabled,
|
animationsEnabled,
|
||||||
)
|
)
|
||||||
const borderHighlight = createMemo(() => tint(themeV2.border(), highlight(), agentMetaAlpha()))
|
const borderHighlight = createMemo(() => tint(themeV2.border.default, highlight(), agentMetaAlpha()))
|
||||||
|
|
||||||
const placeholderText = createMemo(() => {
|
const placeholderText = createMemo(() => {
|
||||||
if (props.showPlaceholder === false) return undefined
|
if (props.showPlaceholder === false) return undefined
|
||||||
|
|
@ -1344,7 +1344,7 @@ export function Prompt(props: PromptProps) {
|
||||||
|
|
||||||
const spinnerDef = createMemo(() => {
|
const spinnerDef = createMemo(() => {
|
||||||
const agent = status() === "running" ? local.agent.current() : local.agent.current()
|
const agent = status() === "running" ? local.agent.current() : local.agent.current()
|
||||||
const color = agent ? local.agent.color(agent.id) : themeV2.border()
|
const color = agent ? local.agent.color(agent.id) : themeV2.border.default
|
||||||
return {
|
return {
|
||||||
frames: createFrames({
|
frames: createFrames({
|
||||||
color,
|
color,
|
||||||
|
|
@ -1364,7 +1364,7 @@ export function Prompt(props: PromptProps) {
|
||||||
})
|
})
|
||||||
const maxHeight = createMemo(() => Math.max(6, Math.floor(dimensions().height / 3)))
|
const maxHeight = createMemo(() => Math.max(6, Math.floor(dimensions().height / 3)))
|
||||||
|
|
||||||
const promptBg = createMemo(() => themeV2.raise(themeV2.background.surface.offset()))
|
const promptBg = createMemo(() => themeV2.raise(themeV2.background.surface.offset))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -1390,9 +1390,9 @@ export function Prompt(props: PromptProps) {
|
||||||
<textarea
|
<textarea
|
||||||
width="100%"
|
width="100%"
|
||||||
placeholder={placeholderText()}
|
placeholder={placeholderText()}
|
||||||
placeholderColor={themeV2.text.subdued()}
|
placeholderColor={themeV2.text.subdued}
|
||||||
textColor={leader() ? themeV2.text.subdued() : themeV2.text()}
|
textColor={leader() ? themeV2.text.subdued : themeV2.text.default}
|
||||||
focusedTextColor={leader() ? themeV2.text.subdued() : themeV2.text()}
|
focusedTextColor={leader() ? themeV2.text.subdued : themeV2.text.default}
|
||||||
minHeight={1}
|
minHeight={1}
|
||||||
maxHeight={maxHeight()}
|
maxHeight={maxHeight()}
|
||||||
onContentChange={() => {
|
onContentChange={() => {
|
||||||
|
|
@ -1452,7 +1452,7 @@ export function Prompt(props: PromptProps) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// setTimeout is a workaround and needs to be addressed properly
|
// setTimeout is a workaround and needs to be addressed properly
|
||||||
if (!input || input.isDestroyed) return
|
if (!input || input.isDestroyed) return
|
||||||
input.cursorColor = themeV2.text()
|
input.cursorColor = themeV2.text.default
|
||||||
}, 0)
|
}, 0)
|
||||||
}}
|
}}
|
||||||
onMouseDown={(r: MouseEvent) => {
|
onMouseDown={(r: MouseEvent) => {
|
||||||
|
|
@ -1460,7 +1460,7 @@ export function Prompt(props: PromptProps) {
|
||||||
r.target?.focus()
|
r.target?.focus()
|
||||||
}}
|
}}
|
||||||
focusedBackgroundColor="transparent"
|
focusedBackgroundColor="transparent"
|
||||||
cursorColor={props.disabled ? themeV2.background.surface.offset() : themeV2.text()}
|
cursorColor={props.disabled ? themeV2.background.surface.offset : themeV2.text.default}
|
||||||
syntaxStyle={syntax()}
|
syntaxStyle={syntax()}
|
||||||
/>
|
/>
|
||||||
<box flexDirection="row" flexShrink={0} paddingTop={1} gap={1} justifyContent="space-between">
|
<box flexDirection="row" flexShrink={0} paddingTop={1} gap={1} justifyContent="space-between">
|
||||||
|
|
@ -1472,24 +1472,24 @@ export function Prompt(props: PromptProps) {
|
||||||
{store.mode === "shell" ? "Shell" : Locale.titlecase(agent().id)}
|
{store.mode === "shell" ? "Shell" : Locale.titlecase(agent().id)}
|
||||||
</text>
|
</text>
|
||||||
<Show when={store.mode === "normal" && local.permission.mode === "auto"}>
|
<Show when={store.mode === "normal" && local.permission.mode === "auto"}>
|
||||||
<text fg={fadeColor(themeV2.text.subdued(), agentMetaAlpha())}>auto</text>
|
<text fg={fadeColor(themeV2.text.subdued, agentMetaAlpha())}>auto</text>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={store.mode === "normal"}>
|
<Show when={store.mode === "normal"}>
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<text fg={fadeColor(themeV2.text.subdued(), modelMetaAlpha())}>·</text>
|
<text fg={fadeColor(themeV2.text.subdued, modelMetaAlpha())}>·</text>
|
||||||
<text
|
<text
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
fg={fadeColor(leader() ? themeV2.text.subdued() : themeV2.text(), modelMetaAlpha())}
|
fg={fadeColor(leader() ? themeV2.text.subdued : themeV2.text.default, modelMetaAlpha())}
|
||||||
>
|
>
|
||||||
{local.model.parsed().model}
|
{local.model.parsed().model}
|
||||||
</text>
|
</text>
|
||||||
<text fg={fadeColor(themeV2.text.subdued(), modelMetaAlpha())}>{currentProviderLabel()}</text>
|
<text fg={fadeColor(themeV2.text.subdued, modelMetaAlpha())}>{currentProviderLabel()}</text>
|
||||||
<Show when={showVariant()}>
|
<Show when={showVariant()}>
|
||||||
<text fg={fadeColor(themeV2.text.subdued(), variantMetaAlpha())}>·</text>
|
<text fg={fadeColor(themeV2.text.subdued, variantMetaAlpha())}>·</text>
|
||||||
<text>
|
<text>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fg: fadeColor(themeV2.text.feedback.warning(), variantMetaAlpha()),
|
fg: fadeColor(themeV2.text.feedback.warning.default, variantMetaAlpha()),
|
||||||
bold: true,
|
bold: true,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -1543,12 +1543,12 @@ export function Prompt(props: PromptProps) {
|
||||||
<Match when={status() === "running"}>
|
<Match when={status() === "running"}>
|
||||||
<box flexDirection="row" gap={1} flexGrow={1} justifyContent="flex-start">
|
<box flexDirection="row" gap={1} flexGrow={1} justifyContent="flex-start">
|
||||||
<box marginLeft={1}>
|
<box marginLeft={1}>
|
||||||
<Show when={config.animations ?? true} fallback={<text fg={themeV2.text.subdued()}>[⋯]</text>}>
|
<Show when={config.animations ?? true} fallback={<text fg={themeV2.text.subdued}>[⋯]</text>}>
|
||||||
<spinner color={spinnerDef().color} frames={spinnerDef().frames} interval={40} />
|
<spinner color={spinnerDef().color} frames={spinnerDef().frames} interval={40} />
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
<text
|
<text
|
||||||
fg={store.interrupt > 0 ? themeV2.background.action() : themeV2.text()}
|
fg={store.interrupt > 0 ? themeV2.background.action.primary.default : themeV2.text.default}
|
||||||
wrapMode="none"
|
wrapMode="none"
|
||||||
truncate
|
truncate
|
||||||
flexShrink={1}
|
flexShrink={1}
|
||||||
|
|
@ -1556,7 +1556,7 @@ export function Prompt(props: PromptProps) {
|
||||||
esc{" "}
|
esc{" "}
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fg: store.interrupt > 0 ? themeV2.background.action() : themeV2.text.subdued(),
|
fg: store.interrupt > 0 ? themeV2.background.action.primary.default : themeV2.text.subdued,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{store.interrupt > 0 ? "again to interrupt" : "interrupt"}
|
{store.interrupt > 0 ? "again to interrupt" : "interrupt"}
|
||||||
|
|
@ -1567,16 +1567,16 @@ export function Prompt(props: PromptProps) {
|
||||||
<Match when={move.progress()}>
|
<Match when={move.progress()}>
|
||||||
{(progress) => (
|
{(progress) => (
|
||||||
<box paddingLeft={3} height={1} minHeight={0} flexShrink={1}>
|
<box paddingLeft={3} height={1} minHeight={0} flexShrink={1}>
|
||||||
<Spinner color={themeV2.hue.accent(500)}>
|
<Spinner color={themeV2.hue.accent[500]}>
|
||||||
{progress()}
|
{progress()}
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{".".repeat(move.creatingDots())}</span>
|
<span style={{ fg: themeV2.text.subdued }}>{".".repeat(move.creatingDots())}</span>
|
||||||
</Spinner>
|
</Spinner>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={move.pendingNew()}>
|
<Match when={move.pendingNew()}>
|
||||||
<box paddingLeft={3} height={1} minHeight={0} flexShrink={1}>
|
<box paddingLeft={3} height={1} minHeight={0} flexShrink={1}>
|
||||||
<text fg={themeV2.hue.accent(500)} wrapMode="none" truncate>
|
<text fg={themeV2.hue.accent[500]} wrapMode="none" truncate>
|
||||||
(new working copy)
|
(new working copy)
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -1584,7 +1584,7 @@ export function Prompt(props: PromptProps) {
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
<Show when={!props.hint && locationLabel()} fallback={props.hint ?? <text />}>
|
<Show when={!props.hint && locationLabel()} fallback={props.hint ?? <text />}>
|
||||||
{(location) => (
|
{(location) => (
|
||||||
<text fg={themeV2.text.subdued()} wrapMode="none" truncate flexGrow={1} flexShrink={1}>
|
<text fg={themeV2.text.subdued} wrapMode="none" truncate flexGrow={1} flexShrink={1}>
|
||||||
{location()}
|
{location()}
|
||||||
</text>
|
</text>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1598,7 +1598,7 @@ export function Prompt(props: PromptProps) {
|
||||||
wrapMode="none"
|
wrapMode="none"
|
||||||
truncate
|
truncate
|
||||||
flexShrink={1}
|
flexShrink={1}
|
||||||
fg={editorContextLabelState() === "pending" ? themeV2.hue.accent(500) : themeV2.text.subdued()}
|
fg={editorContextLabelState() === "pending" ? themeV2.hue.accent[500] : themeV2.text.subdued}
|
||||||
>
|
>
|
||||||
{file()}
|
{file()}
|
||||||
</text>
|
</text>
|
||||||
|
|
@ -1608,40 +1608,40 @@ export function Prompt(props: PromptProps) {
|
||||||
<Match when={store.mode === "normal"}>
|
<Match when={store.mode === "normal"}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={liveWorkStatusVisible() || statusItems().length > 0}>
|
<Match when={liveWorkStatusVisible() || statusItems().length > 0}>
|
||||||
<text fg={themeV2.text.subdued()} wrapMode="none" truncate flexShrink={1}>
|
<text fg={themeV2.text.subdued} wrapMode="none" truncate flexShrink={1}>
|
||||||
<Show when={liveWorkStatusVisible() && liveWorkShortcut()}>
|
<Show when={liveWorkStatusVisible() && liveWorkShortcut()}>
|
||||||
{(shortcut) => <span style={{ fg: themeV2.text() }}>{shortcut()} </span>}
|
{(shortcut) => <span style={{ fg: themeV2.text.default }}>{shortcut()} </span>}
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={subagentStatusLabel()}>
|
<Show when={subagentStatusLabel()}>
|
||||||
{(label) => <span style={{ fg: themeV2.text.subdued() }}>{label()}</span>}
|
{(label) => <span style={{ fg: themeV2.text.subdued }}>{label()}</span>}
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={subagentStatusLabel() && shellStatusLabel()}>
|
<Show when={subagentStatusLabel() && shellStatusLabel()}>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}> · </span>
|
<span style={{ fg: themeV2.text.subdued }}> · </span>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={shellStatusLabel()}>
|
<Show when={shellStatusLabel()}>
|
||||||
{(label) => <span style={{ fg: themeV2.text.subdued() }}>{label()}</span>}
|
{(label) => <span style={{ fg: themeV2.text.subdued }}>{label()}</span>}
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={liveWorkStatusVisible() && statusItems().length > 0}>
|
<Show when={liveWorkStatusVisible() && statusItems().length > 0}>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}> · </span>
|
<span style={{ fg: themeV2.text.subdued }}> · </span>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={statusItems().length > 0}>
|
<Show when={statusItems().length > 0}>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{statusItems().join(" · ")}</span>
|
<span style={{ fg: themeV2.text.subdued }}>{statusItems().join(" · ")}</span>
|
||||||
</Show>
|
</Show>
|
||||||
</text>
|
</text>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
<text fg={themeV2.text()} flexShrink={0}>
|
<text fg={themeV2.text.default} flexShrink={0}>
|
||||||
{agentShortcut()} <span style={{ fg: themeV2.text.subdued() }}>agents</span>
|
{agentShortcut()} <span style={{ fg: themeV2.text.subdued }}>agents</span>
|
||||||
</text>
|
</text>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
<text fg={themeV2.text()} flexShrink={0}>
|
<text fg={themeV2.text.default} flexShrink={0}>
|
||||||
{paletteShortcut()} <span style={{ fg: themeV2.text.subdued() }}>commands</span>
|
{paletteShortcut()} <span style={{ fg: themeV2.text.subdued }}>commands</span>
|
||||||
</text>
|
</text>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={store.mode === "shell"}>
|
<Match when={store.mode === "shell"}>
|
||||||
<text fg={themeV2.text()} flexShrink={0}>
|
<text fg={themeV2.text.default} flexShrink={0}>
|
||||||
esc <span style={{ fg: themeV2.text.subdued() }}>exit shell mode</span>
|
esc <span style={{ fg: themeV2.text.subdued }}>exit shell mode</span>
|
||||||
</text>
|
</text>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,12 @@ export function Reconnecting() {
|
||||||
right={0}
|
right={0}
|
||||||
bottom={0}
|
bottom={0}
|
||||||
left={0}
|
left={0}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
>
|
>
|
||||||
<box width={62} maxWidth="90%" flexDirection="column" alignItems="center" gap={1}>
|
<box width={62} maxWidth="90%" flexDirection="column" alignItems="center" gap={1}>
|
||||||
<Spinner color={themeV2.text.subdued()}>Waiting for background service...</Spinner>
|
<Spinner color={themeV2.text.subdued}>Waiting for background service...</Spinner>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ registerOpencodeSpinner()
|
||||||
export function Spinner(props: { children?: JSX.Element; color?: RGBA }) {
|
export function Spinner(props: { children?: JSX.Element; color?: RGBA }) {
|
||||||
const { themeV2 } = useTheme()
|
const { themeV2 } = useTheme()
|
||||||
const config = useConfig().data
|
const config = useConfig().data
|
||||||
const color = () => props.color ?? themeV2.text.subdued()
|
const color = () => props.color ?? themeV2.text.subdued
|
||||||
return (
|
return (
|
||||||
<Show
|
<Show
|
||||||
when={config.animations ?? true}
|
when={config.animations ?? true}
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@ export function StartupLoading(props: { ready: () => boolean }) {
|
||||||
return (
|
return (
|
||||||
<Show when={show()}>
|
<Show when={show()}>
|
||||||
<box position="absolute" zIndex={5000} left={0} right={0} bottom={1} justifyContent="center" alignItems="center">
|
<box position="absolute" zIndex={5000} left={0} right={0} bottom={1} justifyContent="center" alignItems="center">
|
||||||
<box backgroundColor={themeV2.background()} paddingLeft={1} paddingRight={1}>
|
<box backgroundColor={themeV2.background.default} paddingLeft={1} paddingRight={1}>
|
||||||
<Spinner color={themeV2.text.subdued()}>{text()}</Spinner>
|
<Spinner color={themeV2.text.subdued}>{text()}</Spinner>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,10 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
})
|
})
|
||||||
const colors = createMemo(() => {
|
const colors = createMemo(() => {
|
||||||
const step = mode() === "light" ? 800 : 200
|
const step = mode() === "light" ? 800 : 200
|
||||||
return dedupeWith(themeV2.categorical(step), (first, second) => first.equals(second))
|
return dedupeWith(
|
||||||
|
themeV2.categorical.map((scale) => scale[step]),
|
||||||
|
(first, second) => first.equals(second),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
list() {
|
list() {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ function Directory(props: { context: Plugin.Context; maxWidth: number }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show when={directory()}>
|
<Show when={directory()}>
|
||||||
{(value) => <FilePath value={value()} maxWidth={props.maxWidth} fg={themeV2.text.subdued()} />}
|
{(value) => <FilePath value={value()} maxWidth={props.maxWidth} fg={themeV2.text.subdued} />}
|
||||||
</Show>
|
</Show>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -31,20 +31,18 @@ function Mcp(props: { context: Plugin.Context }) {
|
||||||
return (
|
return (
|
||||||
<Show when={list().length}>
|
<Show when={list().length}>
|
||||||
<box gap={1} flexDirection="row" flexShrink={0}>
|
<box gap={1} flexDirection="row" flexShrink={0}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={failed()}>
|
<Match when={failed()}>
|
||||||
<span style={{ fg: themeV2.text.feedback.error() }}>⊙ </span>
|
<span style={{ fg: themeV2.text.feedback.error.default }}>⊙ </span>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
<span style={{ fg: count() > 0 ? themeV2.text.feedback.success() : themeV2.text.subdued() }}>
|
<span style={{ fg: count() > 0 ? themeV2.text.feedback.success.default : themeV2.text.subdued }}>⊙ </span>
|
||||||
⊙{" "}
|
|
||||||
</span>
|
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
{count()} MCP
|
{count()} MCP
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()}>/status</text>
|
<text fg={themeV2.text.subdued}>/status</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
)
|
)
|
||||||
|
|
@ -78,7 +76,7 @@ function View(props: { context: Plugin.Context }) {
|
||||||
<Mcp context={props.context} />
|
<Mcp context={props.context} />
|
||||||
<box flexGrow={1} />
|
<box flexGrow={1} />
|
||||||
<box flexShrink={0}>
|
<box flexShrink={0}>
|
||||||
<text fg={themeV2.text.subdued()}>{InstallationVersion}</text>
|
<text fg={themeV2.text.subdued}>{InstallationVersion}</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -20,20 +20,20 @@ function View(props: { context: Plugin.Context; sessionID: string }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box>
|
<box>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
<b>Context</b>
|
<b>Context</b>
|
||||||
</text>
|
</text>
|
||||||
<Show when={state()} fallback={<text fg={themeV2.text.subdued()}>Not measured</text>}>
|
<Show when={state()} fallback={<text fg={themeV2.text.subdued}>Not measured</text>}>
|
||||||
{(value) => (
|
{(value) => (
|
||||||
<>
|
<>
|
||||||
<text fg={themeV2.text.subdued()}>{value().tokens.toLocaleString()} tokens</text>
|
<text fg={themeV2.text.subdued}>{value().tokens.toLocaleString()} tokens</text>
|
||||||
<Show when={value().percent !== undefined}>
|
<Show when={value().percent !== undefined}>
|
||||||
<text fg={themeV2.text.subdued()}>{value().percent}% used</text>
|
<text fg={themeV2.text.subdued}>{value().percent}% used</text>
|
||||||
</Show>
|
</Show>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Show>
|
</Show>
|
||||||
<text fg={themeV2.text.subdued()}>{money.format(cost())} spent</text>
|
<text fg={themeV2.text.subdued}>{money.format(cost())} spent</text>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ function View(props: { context: Plugin.Context }) {
|
||||||
props.context.location ? abbreviateHome(props.context.location.directory, paths.home) : undefined,
|
props.context.location ? abbreviateHome(props.context.location.directory, paths.home) : undefined,
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<Show when={directory()}>{(value) => <FilePath value={value()} maxWidth={38} fg={themeV2.text.subdued()} />}</Show>
|
<Show when={directory()}>{(value) => <FilePath value={value()} maxWidth={38} fg={themeV2.text.subdued} />}</Show>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ function View() {
|
||||||
const { themeV2 } = useTheme()
|
const { themeV2 } = useTheme()
|
||||||
return (
|
return (
|
||||||
<box>
|
<box>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
<b>LSP</b>
|
<b>LSP</b>
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()}>LSP status unavailable</text>
|
<text fg={themeV2.text.subdued}>LSP status unavailable</text>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,12 @@ function View(props: { context: Plugin.Context; sessionID: string }) {
|
||||||
)
|
)
|
||||||
|
|
||||||
const dot = (status: string) => {
|
const dot = (status: string) => {
|
||||||
if (status === "connected") return themeV2.text.feedback.success()
|
if (status === "connected") return themeV2.text.feedback.success.default
|
||||||
if (status === "failed") return themeV2.text.feedback.error()
|
if (status === "failed") return themeV2.text.feedback.error.default
|
||||||
if (status === "disabled") return themeV2.text.subdued()
|
if (status === "disabled") return themeV2.text.subdued
|
||||||
if (status === "needs_auth") return themeV2.text.feedback.warning()
|
if (status === "needs_auth") return themeV2.text.feedback.warning.default
|
||||||
if (status === "needs_client_registration") return themeV2.text.feedback.error()
|
if (status === "needs_client_registration") return themeV2.text.feedback.error.default
|
||||||
return themeV2.text.subdued()
|
return themeV2.text.subdued
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -32,12 +32,12 @@ function View(props: { context: Plugin.Context; sessionID: string }) {
|
||||||
<box>
|
<box>
|
||||||
<box flexDirection="row" gap={1} onMouseDown={() => list().length > 2 && setOpen((x) => !x)}>
|
<box flexDirection="row" gap={1} onMouseDown={() => list().length > 2 && setOpen((x) => !x)}>
|
||||||
<Show when={list().length > 2}>
|
<Show when={list().length > 2}>
|
||||||
<text fg={themeV2.text()}>{open() ? "▼" : "▶"}</text>
|
<text fg={themeV2.text.default}>{open() ? "▼" : "▶"}</text>
|
||||||
</Show>
|
</Show>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
<b>MCP</b>
|
<b>MCP</b>
|
||||||
<Show when={!open()}>
|
<Show when={!open()}>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>
|
<span style={{ fg: themeV2.text.subdued }}>
|
||||||
{" "}
|
{" "}
|
||||||
({on()} active{bad() > 0 ? `, ${bad()} error${bad() > 1 ? "s" : ""}` : ""})
|
({on()} active{bad() > 0 ? `, ${bad()} error${bad() > 1 ? "s" : ""}` : ""})
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -56,9 +56,9 @@ function View(props: { context: Plugin.Context; sessionID: string }) {
|
||||||
>
|
>
|
||||||
•
|
•
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text()} wrapMode="word">
|
<text fg={themeV2.text.default} wrapMode="word">
|
||||||
{item.name}{" "}
|
{item.name}{" "}
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>
|
<span style={{ fg: themeV2.text.subdued }}>
|
||||||
<Switch fallback={item.status.status}>
|
<Switch fallback={item.status.status}>
|
||||||
<Match when={item.status.status === "connected"}>Connected</Match>
|
<Match when={item.status.status === "connected"}>Connected</Match>
|
||||||
<Match when={item.status.status === "failed"}>
|
<Match when={item.status.status === "failed"}>
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export function Panel(props: Omit<JSX.IntrinsicElements["box"], "border"> & { bo
|
||||||
? {}
|
? {}
|
||||||
: {
|
: {
|
||||||
border: panelBorderSides(group?.axis ?? "y", border),
|
border: panelBorderSides(group?.axis ?? "y", border),
|
||||||
borderColor: themeV2.border(),
|
borderColor: themeV2.border.default,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -60,7 +60,7 @@ function panelBorderSides(axis: Axis, border: Exclude<PanelBorder, "none">): Bor
|
||||||
export function Separator(props: { axis?: Axis; color?: ColorInput; start?: SeparatorEdge; end?: SeparatorEdge }) {
|
export function Separator(props: { axis?: Axis; color?: ColorInput; start?: SeparatorEdge; end?: SeparatorEdge }) {
|
||||||
const group = usePanelGroup()
|
const group = usePanelGroup()
|
||||||
const { themeV2 } = useTheme()
|
const { themeV2 } = useTheme()
|
||||||
const color = () => props.color ?? themeV2.border()
|
const color = () => props.color ?? themeV2.border.default
|
||||||
const axis = () => props.axis ?? crossAxis(group?.axis ?? "y")
|
const axis = () => props.axis ?? crossAxis(group?.axis ?? "y")
|
||||||
if (axis() === "y") {
|
if (axis() === "y") {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -43,19 +43,19 @@ function Scrap(props: { context: Plugin.Context }) {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box width={dimensions().width} height={dimensions().height} backgroundColor={themeV2.background()}>
|
<box width={dimensions().width} height={dimensions().height} backgroundColor={themeV2.background.default}>
|
||||||
<box flexGrow={1} />
|
<box flexGrow={1} />
|
||||||
<box
|
<box
|
||||||
height={1}
|
height={1}
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
backgroundColor={elevatedTheme.background()}
|
backgroundColor={elevatedTheme.background.default}
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
flexDirection="row"
|
flexDirection="row"
|
||||||
>
|
>
|
||||||
<text fg={elevatedTheme.text.subdued()}>~/code/anomalyco/opencode</text>
|
<text fg={elevatedTheme.text.subdued}>~/code/anomalyco/opencode</text>
|
||||||
<box flexGrow={1} />
|
<box flexGrow={1} />
|
||||||
<text fg={elevatedTheme.text.subdued()}>esc home</text>
|
<text fg={elevatedTheme.text.subdued}>esc home</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,8 @@ export function Composer(props: ComposerProps) {
|
||||||
<box
|
<box
|
||||||
{...SplitBorder}
|
{...SplitBorder}
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
borderColor={themeV2.border()}
|
borderColor={themeV2.border.default}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
|
|
@ -125,7 +125,7 @@ export function Composer(props: ComposerProps) {
|
||||||
<Show
|
<Show
|
||||||
when={tabList().length > 1}
|
when={tabList().length > 1}
|
||||||
fallback={
|
fallback={
|
||||||
<text fg={themeV2.text()} attributes={TextAttributes.BOLD}>
|
<text fg={themeV2.text.default} attributes={TextAttributes.BOLD}>
|
||||||
{tabList()[0]?.label ?? ""}
|
{tabList()[0]?.label ?? ""}
|
||||||
</text>
|
</text>
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +136,7 @@ export function Composer(props: ComposerProps) {
|
||||||
const isActive = createMemo(() => store.active === t.id)
|
const isActive = createMemo(() => store.active === t.id)
|
||||||
return (
|
return (
|
||||||
<text
|
<text
|
||||||
fg={isActive() ? themeV2.text() : themeV2.text.subdued()}
|
fg={isActive() ? themeV2.text.default : themeV2.text.subdued}
|
||||||
attributes={isActive() ? TextAttributes.BOLD : undefined}
|
attributes={isActive() ? TextAttributes.BOLD : undefined}
|
||||||
>
|
>
|
||||||
{t.label}
|
{t.label}
|
||||||
|
|
@ -146,7 +146,7 @@ export function Composer(props: ComposerProps) {
|
||||||
</For>
|
</For>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={close}>
|
<text fg={themeV2.text.subdued} onMouseUp={close}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -156,19 +156,19 @@ export function Composer(props: ComposerProps) {
|
||||||
<For each={footerHints()}>
|
<For each={footerHints()}>
|
||||||
{(hint) => (
|
{(hint) => (
|
||||||
<text>
|
<text>
|
||||||
<span style={{ fg: themeV2.text() }}>
|
<span style={{ fg: themeV2.text.default }}>
|
||||||
<b>{hint.label}</b>{" "}
|
<b>{hint.label}</b>{" "}
|
||||||
</span>
|
</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{hint.shortcut}</span>
|
<span style={{ fg: themeV2.text.subdued }}>{hint.shortcut}</span>
|
||||||
</text>
|
</text>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
<Show when={tabList().length > 1}>
|
<Show when={tabList().length > 1}>
|
||||||
<text>
|
<text>
|
||||||
<span style={{ fg: themeV2.text() }}>
|
<span style={{ fg: themeV2.text.default }}>
|
||||||
<b>tabs</b>{" "}
|
<b>tabs</b>{" "}
|
||||||
</span>
|
</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>←/→</span>
|
<span style={{ fg: themeV2.text.subdued }}>←/→</span>
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ export function ShellTab(props: { sessionID: string }) {
|
||||||
return (
|
return (
|
||||||
<Show when={composer.active("shell")}>
|
<Show when={composer.active("shell")}>
|
||||||
<scrollbox scrollbarOptions={{ visible: false }} maxHeight={5} ref={(r: ScrollBoxRenderable) => (scroll = r)}>
|
<scrollbox scrollbarOptions={{ visible: false }} maxHeight={5} ref={(r: ScrollBoxRenderable) => (scroll = r)}>
|
||||||
<Show when={entries().length > 0} fallback={<text fg={themeV2.text.subdued()}> No shell commands</text>}>
|
<Show when={entries().length > 0} fallback={<text fg={themeV2.text.subdued}> No shell commands</text>}>
|
||||||
<For each={entries()}>
|
<For each={entries()}>
|
||||||
{(shell, index) => {
|
{(shell, index) => {
|
||||||
const active = createMemo(() => index() === store.selected)
|
const active = createMemo(() => index() === store.selected)
|
||||||
|
|
@ -107,11 +107,13 @@ export function ShellTab(props: { sessionID: string }) {
|
||||||
flexDirection="row"
|
flexDirection="row"
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
backgroundColor={themeV2.background.action({ focused: active() })}
|
backgroundColor={
|
||||||
|
active() ? themeV2.background.action.primary.focused : themeV2.background.action.primary.default
|
||||||
|
}
|
||||||
onMouseOver={() => setStore("selected", index())}
|
onMouseOver={() => setStore("selected", index())}
|
||||||
>
|
>
|
||||||
<text
|
<text
|
||||||
fg={themeV2.text.action({ focused: active() })}
|
fg={active() ? themeV2.text.action.primary.focused : themeV2.text.action.primary.default}
|
||||||
attributes={active() ? TextAttributes.BOLD : undefined}
|
attributes={active() ? TextAttributes.BOLD : undefined}
|
||||||
wrapMode="none"
|
wrapMode="none"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -205,7 +205,7 @@ export function SubagentsTab(props: { sessionID: string }) {
|
||||||
return (
|
return (
|
||||||
<Show when={composer.active("subagents")}>
|
<Show when={composer.active("subagents")}>
|
||||||
<scrollbox scrollbarOptions={{ visible: false }} maxHeight={5} ref={(r: ScrollBoxRenderable) => (scroll = r)}>
|
<scrollbox scrollbarOptions={{ visible: false }} maxHeight={5} ref={(r: ScrollBoxRenderable) => (scroll = r)}>
|
||||||
<Show when={entries().length > 0} fallback={<text fg={themeV2.text.subdued()}> No subagents</text>}>
|
<Show when={entries().length > 0} fallback={<text fg={themeV2.text.subdued}> No subagents</text>}>
|
||||||
<For each={entries()}>
|
<For each={entries()}>
|
||||||
{(entry, index) => {
|
{(entry, index) => {
|
||||||
const active = createMemo(() => index() === selected())
|
const active = createMemo(() => index() === selected())
|
||||||
|
|
@ -218,7 +218,13 @@ export function SubagentsTab(props: { sessionID: string }) {
|
||||||
flexDirection="row"
|
flexDirection="row"
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
backgroundColor={themeV2.background.action({ focused: active(), selected: entry.current })}
|
backgroundColor={
|
||||||
|
active()
|
||||||
|
? themeV2.background.action.primary.focused
|
||||||
|
: entry.current
|
||||||
|
? themeV2.background.action.primary.selected
|
||||||
|
: themeV2.background.action.primary.default
|
||||||
|
}
|
||||||
onMouseOver={() => setStore("selected", index())}
|
onMouseOver={() => setStore("selected", index())}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
setStore("selected", index())
|
setStore("selected", index())
|
||||||
|
|
@ -227,7 +233,13 @@ export function SubagentsTab(props: { sessionID: string }) {
|
||||||
>
|
>
|
||||||
<box flexGrow={1} minWidth={0} flexDirection="row">
|
<box flexGrow={1} minWidth={0} flexDirection="row">
|
||||||
<text
|
<text
|
||||||
fg={themeV2.text.action({ focused: active(), selected: entry.current })}
|
fg={
|
||||||
|
active()
|
||||||
|
? themeV2.text.action.primary.focused
|
||||||
|
: entry.current
|
||||||
|
? themeV2.text.action.primary.selected
|
||||||
|
: themeV2.text.action.primary.default
|
||||||
|
}
|
||||||
attributes={active() ? TextAttributes.BOLD : undefined}
|
attributes={active() ? TextAttributes.BOLD : undefined}
|
||||||
wrapMode="none"
|
wrapMode="none"
|
||||||
>
|
>
|
||||||
|
|
@ -235,14 +247,7 @@ export function SubagentsTab(props: { sessionID: string }) {
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={status()}>
|
<Show when={status()}>
|
||||||
<text
|
<text fg={active() ? themeV2.text.action.primary.focused : themeV2.text.subdued} wrapMode="none">
|
||||||
fg={
|
|
||||||
active()
|
|
||||||
? themeV2.text.action({ focused: active(), selected: entry.current })
|
|
||||||
: themeV2.text.subdued()
|
|
||||||
}
|
|
||||||
wrapMode="none"
|
|
||||||
>
|
|
||||||
{status()}
|
{status()}
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,7 @@ export function Footer() {
|
||||||
const mcp = createMemo(
|
const mcp = createMemo(
|
||||||
() => (data.location.mcp.server.list() ?? []).filter((x) => x.status.status === "connected").length,
|
() => (data.location.mcp.server.list() ?? []).filter((x) => x.status.status === "connected").length,
|
||||||
)
|
)
|
||||||
const mcpError = createMemo(() =>
|
const mcpError = createMemo(() => (data.location.mcp.server.list() ?? []).some((x) => x.status.status === "failed"))
|
||||||
(data.location.mcp.server.list() ?? []).some((x) => x.status.status === "failed"),
|
|
||||||
)
|
|
||||||
const permissions = createMemo(() => {
|
const permissions = createMemo(() => {
|
||||||
if (route.data.type !== "session") return []
|
if (route.data.type !== "session") return []
|
||||||
return data.session.permission.list(route.data.sessionID) ?? []
|
return data.session.permission.list(route.data.sessionID) ?? []
|
||||||
|
|
@ -54,35 +52,35 @@ export function Footer() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box flexDirection="row" justifyContent="space-between" gap={1} flexShrink={0}>
|
<box flexDirection="row" justifyContent="space-between" gap={1} flexShrink={0}>
|
||||||
<text fg={themeV2.text.subdued()}>{directory()}</text>
|
<text fg={themeV2.text.subdued}>{directory()}</text>
|
||||||
<box gap={2} flexDirection="row" flexShrink={0}>
|
<box gap={2} flexDirection="row" flexShrink={0}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={store.welcome}>
|
<Match when={store.welcome}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
Get started <span style={{ fg: themeV2.text.subdued() }}>/connect</span>
|
Get started <span style={{ fg: themeV2.text.subdued }}>/connect</span>
|
||||||
</text>
|
</text>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={connected()}>
|
<Match when={connected()}>
|
||||||
<Show when={permissions().length > 0}>
|
<Show when={permissions().length > 0}>
|
||||||
<text fg={themeV2.text.feedback.warning()}>
|
<text fg={themeV2.text.feedback.warning.default}>
|
||||||
<span style={{ fg: themeV2.text.feedback.warning() }}>△</span> {permissions().length} Permission
|
<span style={{ fg: themeV2.text.feedback.warning.default }}>△</span> {permissions().length} Permission
|
||||||
{permissions().length > 1 ? "s" : ""}
|
{permissions().length > 1 ? "s" : ""}
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={mcp()}>
|
<Show when={mcp()}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={mcpError()}>
|
<Match when={mcpError()}>
|
||||||
<span style={{ fg: themeV2.text.feedback.error() }}>⊙ </span>
|
<span style={{ fg: themeV2.text.feedback.error.default }}>⊙ </span>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
<span style={{ fg: themeV2.text.feedback.success() }}>⊙ </span>
|
<span style={{ fg: themeV2.text.feedback.success.default }}>⊙ </span>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
{mcp()} MCP
|
{mcp()} MCP
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
<text fg={themeV2.text.subdued()}>/status</text>
|
<text fg={themeV2.text.subdued}>/status</text>
|
||||||
</Match>
|
</Match>
|
||||||
</Switch>
|
</Switch>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -624,27 +624,27 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box
|
<box
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
borderColor={themeV2.hue.interactive(themeMode() === "light" ? 800 : 200)}
|
borderColor={themeV2.hue.interactive[themeMode() === "light" ? 800 : 200]}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
>
|
>
|
||||||
<box gap={1} paddingLeft={1} paddingRight={3} paddingTop={1} paddingBottom={1}>
|
<box gap={1} paddingLeft={1} paddingRight={3} paddingTop={1} paddingBottom={1}>
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<text fg={themeV2.text.subdued()}>{props.form.title}</text>
|
<text fg={themeV2.text.subdued}>{props.form.title}</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={message()}>
|
<Show when={message()}>
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<text fg={themeV2.text()}>{message()}</text>
|
<text fg={themeV2.text.default}>{message()}</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={!single() && !tabbed()}>
|
<Show when={!single() && !tabbed()}>
|
||||||
<box flexDirection="row" gap={1} paddingLeft={1}>
|
<box flexDirection="row" gap={1} paddingLeft={1}>
|
||||||
<text fg={themeV2.text.subdued()}>
|
<text fg={themeV2.text.subdued}>
|
||||||
{confirm() ? "Review" : `Field ${Math.min(store.tab, fields().length - 1) + 1} of ${fields().length}`}
|
{confirm() ? "Review" : `Field ${Math.min(store.tab, fields().length - 1) + 1} of ${fields().length}`}
|
||||||
</text>
|
</text>
|
||||||
<Show when={fields().length > 0}>
|
<Show when={fields().length > 0}>
|
||||||
<text fg={themeV2.text.subdued()}>
|
<text fg={themeV2.text.subdued}>
|
||||||
· {answered()}/{fields().length} completed
|
· {answered()}/{fields().length} completed
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -661,10 +661,10 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
backgroundColor={
|
backgroundColor={
|
||||||
isTab()
|
isTab()
|
||||||
? themeV2.background.formfield("selected")
|
? themeV2.background.formfield.selected
|
||||||
: tabHover() === index()
|
: tabHover() === index()
|
||||||
? themeV2.background.formfield("focused")
|
? themeV2.background.formfield.focused
|
||||||
: themeV2.background()
|
: themeV2.background.default
|
||||||
}
|
}
|
||||||
onMouseOver={() => setTabHover(index())}
|
onMouseOver={() => setTabHover(index())}
|
||||||
onMouseOut={() => setTabHover(null)}
|
onMouseOut={() => setTabHover(null)}
|
||||||
|
|
@ -676,12 +676,12 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
<text
|
<text
|
||||||
fg={
|
fg={
|
||||||
isTab()
|
isTab()
|
||||||
? themeV2.text.formfield("selected")
|
? themeV2.text.formfield.selected
|
||||||
: tabHover() === index()
|
: tabHover() === index()
|
||||||
? themeV2.text.formfield("focused")
|
? themeV2.text.formfield.focused
|
||||||
: isAnswered()
|
: isAnswered()
|
||||||
? themeV2.text()
|
? themeV2.text.default
|
||||||
: themeV2.text.subdued()
|
: themeV2.text.subdued
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{truncate(formLabel(item), 24)}
|
{truncate(formLabel(item), 24)}
|
||||||
|
|
@ -693,10 +693,10 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
<box
|
<box
|
||||||
backgroundColor={
|
backgroundColor={
|
||||||
confirm()
|
confirm()
|
||||||
? themeV2.background.formfield("selected")
|
? themeV2.background.formfield.selected
|
||||||
: tabHover() === "confirm"
|
: tabHover() === "confirm"
|
||||||
? themeV2.background.formfield("focused")
|
? themeV2.background.formfield.focused
|
||||||
: themeV2.background()
|
: themeV2.background.default
|
||||||
}
|
}
|
||||||
onMouseOver={() => setTabHover("confirm")}
|
onMouseOver={() => setTabHover("confirm")}
|
||||||
onMouseOut={() => setTabHover(null)}
|
onMouseOut={() => setTabHover(null)}
|
||||||
|
|
@ -705,7 +705,7 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
selectTabFromMouse()
|
selectTabFromMouse()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.formfield(confirm() ? "selected" : "default")}>Confirm</text>
|
<text fg={confirm() ? themeV2.text.formfield.selected : themeV2.text.formfield.default}>Confirm</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -714,13 +714,13 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
{(external) => (
|
{(external) => (
|
||||||
<box paddingLeft={1} gap={1}>
|
<box paddingLeft={1} gap={1}>
|
||||||
<Show when={external().title}>
|
<Show when={external().title}>
|
||||||
<text fg={themeV2.text()}>{external().title}</text>
|
<text fg={themeV2.text.default}>{external().title}</text>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={external().description}>
|
<Show when={external().description}>
|
||||||
<text fg={themeV2.text.subdued()}>{external().description}</text>
|
<text fg={themeV2.text.subdued}>{external().description}</text>
|
||||||
</Show>
|
</Show>
|
||||||
<text
|
<text
|
||||||
fg={themeV2.background.action()}
|
fg={themeV2.background.action.primary.default}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
if (renderer.getSelection()?.getSelectedText()) return
|
if (renderer.getSelection()?.getSelectedText()) return
|
||||||
openExternal()
|
openExternal()
|
||||||
|
|
@ -729,7 +729,9 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
{external().url}
|
{external().url}
|
||||||
</text>
|
</text>
|
||||||
<text
|
<text
|
||||||
fg={store.answers[external().key] === true ? themeV2.text.feedback.success() : themeV2.text.subdued()}
|
fg={
|
||||||
|
store.answers[external().key] === true ? themeV2.text.feedback.success.default : themeV2.text.subdued
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{store.answers[external().key] === true
|
{store.answers[external().key] === true
|
||||||
? "✓ Acknowledged"
|
? "✓ Acknowledged"
|
||||||
|
|
@ -744,7 +746,7 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
<Show when={!confirm() && answerField()}>
|
<Show when={!confirm() && answerField()}>
|
||||||
<box paddingLeft={1} gap={1}>
|
<box paddingLeft={1} gap={1}>
|
||||||
<box>
|
<box>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
{answerField()!.description ?? formLabel(answerField()!)}
|
{answerField()!.description ?? formLabel(answerField()!)}
|
||||||
{answerField()!.required ? " (required)" : ""}
|
{answerField()!.required ? " (required)" : ""}
|
||||||
{multi() ? " (select all that apply)" : ""}
|
{multi() ? " (select all that apply)" : ""}
|
||||||
|
|
@ -765,12 +767,12 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
input() || formDisplayValue(answerField()!, store.answers[answerField()!.key], "(none)")
|
input() || formDisplayValue(answerField()!, store.answers[answerField()!.key], "(none)")
|
||||||
}
|
}
|
||||||
placeholder={placeholder()}
|
placeholder={placeholder()}
|
||||||
placeholderColor={themeV2.text.subdued()}
|
placeholderColor={themeV2.text.subdued}
|
||||||
minHeight={1}
|
minHeight={1}
|
||||||
maxHeight={6}
|
maxHeight={6}
|
||||||
textColor={themeV2.text()}
|
textColor={themeV2.text.default}
|
||||||
focusedTextColor={themeV2.text()}
|
focusedTextColor={themeV2.text.default}
|
||||||
cursorColor={themeV2.text()}
|
cursorColor={themeV2.text.default}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -795,25 +797,39 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
>
|
>
|
||||||
<box flexDirection="row">
|
<box flexDirection="row">
|
||||||
<box
|
<box
|
||||||
backgroundColor={active() ? themeV2.background.formfield("focused") : themeV2.background()}
|
backgroundColor={
|
||||||
|
active() ? themeV2.background.formfield.focused : themeV2.background.default
|
||||||
|
}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.formfield(active() ? "focused" : "default")}>{`${i() + 1}.`}</text>
|
<text
|
||||||
|
fg={active() ? themeV2.text.formfield.focused : themeV2.text.formfield.default}
|
||||||
|
>{`${i() + 1}.`}</text>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box
|
||||||
backgroundColor={active() ? themeV2.background.formfield("focused") : themeV2.background()}
|
backgroundColor={
|
||||||
|
active() ? themeV2.background.formfield.focused : themeV2.background.default
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.formfield(active() ? "focused" : picked() ? "selected" : "default")}>
|
<text
|
||||||
|
fg={
|
||||||
|
active()
|
||||||
|
? themeV2.text.formfield.focused
|
||||||
|
: picked()
|
||||||
|
? themeV2.text.formfield.selected
|
||||||
|
: themeV2.text.formfield.default
|
||||||
|
}
|
||||||
|
>
|
||||||
{multi() ? `[${picked() ? "✓" : " "}] ${row.label}` : row.label}
|
{multi() ? `[${picked() ? "✓" : " "}] ${row.label}` : row.label}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={!multi()}>
|
<Show when={!multi()}>
|
||||||
<text fg={themeV2.text.formfield("selected")}>{picked() ? " ✓" : ""}</text>
|
<text fg={themeV2.text.formfield.selected}>{picked() ? " ✓" : ""}</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
<Show when={row.description}>
|
<Show when={row.description}>
|
||||||
<box paddingLeft={3}>
|
<box paddingLeft={3}>
|
||||||
<text fg={themeV2.text.subdued()}>{row.description}</text>
|
<text fg={themeV2.text.subdued}>{row.description}</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -831,28 +847,30 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
>
|
>
|
||||||
<box flexDirection="row">
|
<box flexDirection="row">
|
||||||
<box
|
<box
|
||||||
backgroundColor={other() ? themeV2.background.formfield("focused") : themeV2.background()}
|
backgroundColor={other() ? themeV2.background.formfield.focused : themeV2.background.default}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.formfield(other() ? "focused" : "default")}>
|
<text fg={other() ? themeV2.text.formfield.focused : themeV2.text.formfield.default}>
|
||||||
{`${rows().length + 1}.`}
|
{`${rows().length + 1}.`}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box backgroundColor={other() ? themeV2.background.formfield("focused") : themeV2.background()}>
|
<box
|
||||||
|
backgroundColor={other() ? themeV2.background.formfield.focused : themeV2.background.default}
|
||||||
|
>
|
||||||
<text
|
<text
|
||||||
fg={
|
fg={
|
||||||
other()
|
other()
|
||||||
? themeV2.text.formfield("focused")
|
? themeV2.text.formfield.focused
|
||||||
: customPicked()
|
: customPicked()
|
||||||
? themeV2.text.feedback.success()
|
? themeV2.text.feedback.success.default
|
||||||
: themeV2.text()
|
: themeV2.text.default
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{multi() ? `[${customPicked() ? "✓" : " "}] Type your own answer` : "Type your own answer"}
|
{multi() ? `[${customPicked() ? "✓" : " "}] Type your own answer` : "Type your own answer"}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={!multi()}>
|
<Show when={!multi()}>
|
||||||
<text fg={themeV2.text.feedback.success()}>{customPicked() ? " ✓" : ""}</text>
|
<text fg={themeV2.text.feedback.success.default}>{customPicked() ? " ✓" : ""}</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
<Show when={store.editing}>
|
<Show when={store.editing}>
|
||||||
|
|
@ -868,18 +886,18 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
}}
|
}}
|
||||||
initialValue={input()}
|
initialValue={input()}
|
||||||
placeholder="Type your own answer"
|
placeholder="Type your own answer"
|
||||||
placeholderColor={themeV2.text.subdued()}
|
placeholderColor={themeV2.text.subdued}
|
||||||
minHeight={1}
|
minHeight={1}
|
||||||
maxHeight={6}
|
maxHeight={6}
|
||||||
textColor={themeV2.text()}
|
textColor={themeV2.text.default}
|
||||||
focusedTextColor={themeV2.text()}
|
focusedTextColor={themeV2.text.default}
|
||||||
cursorColor={themeV2.text()}
|
cursorColor={themeV2.text.default}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={!store.editing && input()}>
|
<Show when={!store.editing && input()}>
|
||||||
<box paddingLeft={3}>
|
<box paddingLeft={3}>
|
||||||
<text fg={themeV2.text.subdued()}>{input()}</text>
|
<text fg={themeV2.text.subdued}>{input()}</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -892,7 +910,7 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
<Show when={confirm()}>
|
<Show when={confirm()}>
|
||||||
<Show when={tabbed()}>
|
<Show when={tabbed()}>
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<text fg={themeV2.text()}>Review</text>
|
<text fg={themeV2.text.default}>Review</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<scrollbox
|
<scrollbox
|
||||||
|
|
@ -907,10 +925,12 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<text>
|
<text>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{truncate(formLabel(item), 40)}:</span>{" "}
|
<span style={{ fg: themeV2.text.subdued }}>{truncate(formLabel(item), 40)}:</span>{" "}
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fg: acknowledged() ? themeV2.text.feedback.success() : themeV2.text.feedback.error(),
|
fg: acknowledged()
|
||||||
|
? themeV2.text.feedback.success.default
|
||||||
|
: themeV2.text.feedback.error.default,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{acknowledged() ? "Acknowledged" : "(acknowledgement required)"}
|
{acknowledged() ? "Acknowledged" : "(acknowledgement required)"}
|
||||||
|
|
@ -926,15 +946,15 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<text>
|
<text>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{truncate(formLabel(item), 40)}:</span>{" "}
|
<span style={{ fg: themeV2.text.subdued }}>{truncate(formLabel(item), 40)}:</span>{" "}
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fg:
|
fg:
|
||||||
invalid() || missing()
|
invalid() || missing()
|
||||||
? themeV2.text.feedback.error()
|
? themeV2.text.feedback.error.default
|
||||||
: answered()
|
: answered()
|
||||||
? themeV2.text()
|
? themeV2.text.default
|
||||||
: themeV2.text.subdued(),
|
: themeV2.text.subdued,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{invalid() ?? (answered() ? value() : missing() ? "(required)" : "(not answered)")}
|
{invalid() ?? (answered() ? value() : missing() ? "(required)" : "(not answered)")}
|
||||||
|
|
@ -958,41 +978,41 @@ export function FormPrompt(props: { form: FormWithLocation }) {
|
||||||
>
|
>
|
||||||
<box flexDirection="row" gap={2}>
|
<box flexDirection="row" gap={2}>
|
||||||
<Show when={!single()}>
|
<Show when={!single()}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
{"⇆"} <span style={{ fg: themeV2.text.subdued() }}>tab</span>
|
{"⇆"} <span style={{ fg: themeV2.text.subdued }}>tab</span>
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={!confirm() && !textual() && !externalField()}>
|
<Show when={!confirm() && !textual() && !externalField()}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
{"↑↓"} <span style={{ fg: themeV2.text.subdued() }}>select</span>
|
{"↑↓"} <span style={{ fg: themeV2.text.subdued }}>select</span>
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={confirm() && fields().length > 0}>
|
<Show when={confirm() && fields().length > 0}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
{"↑↓"} <span style={{ fg: themeV2.text.subdued() }}>scroll</span>
|
{"↑↓"} <span style={{ fg: themeV2.text.subdued }}>scroll</span>
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
<text
|
<text
|
||||||
fg={themeV2.text()}
|
fg={themeV2.text.default}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
if (renderer.getSelection()?.getSelectedText()) return
|
if (renderer.getSelection()?.getSelectedText()) return
|
||||||
if (confirm()) submit()
|
if (confirm()) submit()
|
||||||
if (externalField()) acknowledgeExternal()
|
if (externalField()) acknowledgeExternal()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
enter <span style={{ fg: themeV2.text.subdued() }}>{actionLabel()}</span>
|
enter <span style={{ fg: themeV2.text.subdued }}>{actionLabel()}</span>
|
||||||
</text>
|
</text>
|
||||||
<Show when={externalField() && clipboard.write}>
|
<Show when={externalField() && clipboard.write}>
|
||||||
<text fg={themeV2.text()} onMouseUp={copyExternal}>
|
<text fg={themeV2.text.default} onMouseUp={copyExternal}>
|
||||||
c <span style={{ fg: themeV2.text.subdued() }}>copy</span>
|
c <span style={{ fg: themeV2.text.subdued }}>copy</span>
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
<text fg={themeV2.text()} onMouseUp={cancel}>
|
<text fg={themeV2.text.default} onMouseUp={cancel}>
|
||||||
esc <span style={{ fg: themeV2.text.subdued() }}>dismiss</span>
|
esc <span style={{ fg: themeV2.text.subdued }}>dismiss</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={store.error}>
|
<Show when={store.error}>
|
||||||
<text fg={themeV2.text.feedback.error()}>{store.error}</text>
|
<text fg={themeV2.text.feedback.error.default}>{store.error}</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -919,8 +919,8 @@ export function Session() {
|
||||||
paddingLeft: 1,
|
paddingLeft: 1,
|
||||||
visible: showScrollbar(),
|
visible: showScrollbar(),
|
||||||
trackOptions: {
|
trackOptions: {
|
||||||
backgroundColor: themeV2.raise(themeV2.background.surface.offset()),
|
backgroundColor: themeV2.raise(themeV2.background.surface.offset),
|
||||||
foregroundColor: themeV2.border(),
|
foregroundColor: themeV2.border.default,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
stickyScroll={!navigationMessage()}
|
stickyScroll={!navigationMessage()}
|
||||||
|
|
@ -1098,8 +1098,8 @@ function BackgroundToolHint(props: { messages: SessionMessageInfo[] }) {
|
||||||
<Show when={visible() && shortcut()}>
|
<Show when={visible() && shortcut()}>
|
||||||
{(value) => (
|
{(value) => (
|
||||||
<box marginTop={1} paddingLeft={3} flexShrink={0}>
|
<box marginTop={1} paddingLeft={3} flexShrink={0}>
|
||||||
<text fg={themeV2.text.subdued()}>
|
<text fg={themeV2.text.subdued}>
|
||||||
Press <span style={{ fg: themeV2.text() }}>{value()}</span> to move running work to the background
|
Press <span style={{ fg: themeV2.text.default }}>{value()}</span> to move running work to the background
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1209,13 +1209,13 @@ function SessionReasoningGroupView(props: {
|
||||||
icon={expanded() ? "-" : "+"}
|
icon={expanded() ? "-" : "+"}
|
||||||
color={
|
color={
|
||||||
!props.completed
|
!props.completed
|
||||||
? themeV2.text()
|
? themeV2.text.default
|
||||||
: hover() || expanded()
|
: hover() || expanded()
|
||||||
? themeV2.text.feedback.warning()
|
? themeV2.text.feedback.warning.default
|
||||||
: RGBA.fromValues(
|
: RGBA.fromValues(
|
||||||
themeV2.text.feedback.warning().r,
|
themeV2.text.feedback.warning.default.r,
|
||||||
themeV2.text.feedback.warning().g,
|
themeV2.text.feedback.warning.default.g,
|
||||||
themeV2.text.feedback.warning().b,
|
themeV2.text.feedback.warning.default.b,
|
||||||
0.6,
|
0.6,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1258,7 +1258,7 @@ function SessionReasoningGroupView(props: {
|
||||||
<box
|
<box
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
borderColor={themeV2.raise(themeV2.background.surface.offset())}
|
borderColor={themeV2.raise(themeV2.background.surface.offset)}
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
>
|
>
|
||||||
<code
|
<code
|
||||||
|
|
@ -1268,7 +1268,7 @@ function SessionReasoningGroupView(props: {
|
||||||
syntaxStyle={syntax()}
|
syntaxStyle={syntax()}
|
||||||
content={content()}
|
content={content()}
|
||||||
conceal={ctx.markdownMode() === "rendered"}
|
conceal={ctx.markdownMode() === "rendered"}
|
||||||
fg={themeV2.text.subdued()}
|
fg={themeV2.text.subdued}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -1326,7 +1326,7 @@ function SessionGroupView(props: {
|
||||||
<Show when={grouped().length > 0}>
|
<Show when={grouped().length > 0}>
|
||||||
<InlineToolRow
|
<InlineToolRow
|
||||||
icon={props.completed ? "→" : "✱"}
|
icon={props.completed ? "→" : "✱"}
|
||||||
color={hover() ? themeV2.text() : themeV2.text.subdued()}
|
color={hover() ? themeV2.text.default : themeV2.text.subdued}
|
||||||
complete={props.completed}
|
complete={props.completed}
|
||||||
pending={label()}
|
pending={label()}
|
||||||
spinner={!props.completed}
|
spinner={!props.completed}
|
||||||
|
|
@ -1372,25 +1372,25 @@ function AssistantFooter(props: { message: SessionMessageAssistant }) {
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
borderColor={themeV2.text.feedback.error()}
|
borderColor={themeV2.text.feedback.error.default}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.subdued()}>{errorMessage(props.message.error)}</text>
|
<text fg={themeV2.text.subdued}>{errorMessage(props.message.error)}</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<AssistantRetry retry={props.message.retry} />
|
<AssistantRetry retry={props.message.retry} />
|
||||||
<box paddingLeft={3} marginTop={props.message.error && !interrupted() ? 1 : 0}>
|
<box paddingLeft={3} marginTop={props.message.error && !interrupted() ? 1 : 0}>
|
||||||
<text>
|
<text>
|
||||||
<span style={{ fg: props.message.error ? themeV2.text.subdued() : local.agent.color(props.message.agent) }}>
|
<span style={{ fg: props.message.error ? themeV2.text.subdued : local.agent.color(props.message.agent) }}>
|
||||||
{Locale.titlecase(props.message.agent)}
|
{Locale.titlecase(props.message.agent)}
|
||||||
</span>
|
</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}> · {model()}</span>
|
<span style={{ fg: themeV2.text.subdued }}> · {model()}</span>
|
||||||
<Show when={duration()}>
|
<Show when={duration()}>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}> · {Locale.duration(duration())}</span>
|
<span style={{ fg: themeV2.text.subdued }}> · {Locale.duration(duration())}</span>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={interrupted()}>
|
<Show when={interrupted()}>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}> · interrupted</span>
|
<span style={{ fg: themeV2.text.subdued }}> · interrupted</span>
|
||||||
</Show>
|
</Show>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -1409,7 +1409,7 @@ function SessionSwitchMessageV2(props: { message: SessionMessageInfo }) {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={3}>
|
<box paddingLeft={3}>
|
||||||
<text fg={themeV2.text.subdued()}>{text()}</text>
|
<text fg={themeV2.text.subdued}>{text()}</text>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1436,15 +1436,15 @@ function SessionNoticeMessageV2(props: { message: SessionMessageInfo }) {
|
||||||
const heading = () => `${state() === "completed" ? "↳" : "!"} ${actor()} ${status()}`
|
const heading = () => `${state() === "completed" ? "↳" : "!"} ${actor()} ${status()}`
|
||||||
const suffix = () => Locale.truncateWidth(` · ${description()}`, Math.max(0, ctx.width - 3 - stringWidth(heading())))
|
const suffix = () => Locale.truncateWidth(` · ${description()}`, Math.max(0, ctx.width - 3 - stringWidth(heading())))
|
||||||
const color = () => {
|
const color = () => {
|
||||||
if (state() === "error") return themeV2.text.feedback.error()
|
if (state() === "error") return themeV2.text.feedback.error.default
|
||||||
if (state() === "cancelled") return themeV2.text.feedback.warning()
|
if (state() === "cancelled") return themeV2.text.feedback.warning.default
|
||||||
return themeV2.text.feedback.info()
|
return themeV2.text.feedback.info.default
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Show
|
<Show
|
||||||
when={completion()}
|
when={completion()}
|
||||||
fallback={
|
fallback={
|
||||||
<InlineToolRow icon="◈" color={themeV2.text.subdued()} pending="Notice" complete={true}>
|
<InlineToolRow icon="◈" color={themeV2.text.subdued} pending="Notice" complete={true}>
|
||||||
{text()}
|
{text()}
|
||||||
</InlineToolRow>
|
</InlineToolRow>
|
||||||
}
|
}
|
||||||
|
|
@ -1452,7 +1452,7 @@ function SessionNoticeMessageV2(props: { message: SessionMessageInfo }) {
|
||||||
<box marginLeft={3}>
|
<box marginLeft={3}>
|
||||||
<text wrapMode="none">
|
<text wrapMode="none">
|
||||||
<span style={{ fg: color() }}>{heading()}</span>
|
<span style={{ fg: color() }}>{heading()}</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{suffix()}</span>
|
<span style={{ fg: themeV2.text.subdued }}>{suffix()}</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -1462,7 +1462,7 @@ function SessionNoticeMessageV2(props: { message: SessionMessageInfo }) {
|
||||||
function SessionSkillMessage(props: { message: Extract<SessionMessageInfo, { type: "skill" }> }) {
|
function SessionSkillMessage(props: { message: Extract<SessionMessageInfo, { type: "skill" }> }) {
|
||||||
const { themeV2 } = useTheme()
|
const { themeV2 } = useTheme()
|
||||||
return (
|
return (
|
||||||
<InlineToolRow icon="→" color={themeV2.text.subdued()} pending="Skill" complete={true}>
|
<InlineToolRow icon="→" color={themeV2.text.subdued} pending="Skill" complete={true}>
|
||||||
Skill {props.message.name}
|
Skill {props.message.name}
|
||||||
</InlineToolRow>
|
</InlineToolRow>
|
||||||
)
|
)
|
||||||
|
|
@ -1476,7 +1476,8 @@ function CompactionMessage(props: { message: Extract<SessionMessageInfo, { type:
|
||||||
const text = () =>
|
const text = () =>
|
||||||
props.message.status === "failed" ? (cancelled() ? "" : props.message.error.message) : props.message.summary
|
props.message.status === "failed" ? (cancelled() ? "" : props.message.error.message) : props.message.summary
|
||||||
const content = createMemo(() => text().trim())
|
const content = createMemo(() => text().trim())
|
||||||
const color = () => (status() === "failed" && !cancelled() ? themeV2.text.feedback.error() : themeV2.text.subdued())
|
const color = () =>
|
||||||
|
status() === "failed" && !cancelled() ? themeV2.text.feedback.error.default : themeV2.text.subdued
|
||||||
return (
|
return (
|
||||||
<box>
|
<box>
|
||||||
<box flexDirection="row" alignItems="center">
|
<box flexDirection="row" alignItems="center">
|
||||||
|
|
@ -1508,8 +1509,8 @@ function CompactionMessage(props: { message: Extract<SessionMessageInfo, { type:
|
||||||
content={content()}
|
content={content()}
|
||||||
tableOptions={{ style: "grid" }}
|
tableOptions={{ style: "grid" }}
|
||||||
conceal={ctx.markdownMode() === "rendered"}
|
conceal={ctx.markdownMode() === "rendered"}
|
||||||
fg={themeV2.markdown()}
|
fg={themeV2.markdown.text}
|
||||||
bg={themeV2.background()}
|
bg={themeV2.background.default}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -1521,12 +1522,12 @@ function CompactionQueued() {
|
||||||
const { themeV2 } = useTheme()
|
const { themeV2 } = useTheme()
|
||||||
return (
|
return (
|
||||||
<box flexDirection="row" alignItems="center">
|
<box flexDirection="row" alignItems="center">
|
||||||
<box border={["top"]} borderColor={themeV2.border()} flexGrow={1} />
|
<box border={["top"]} borderColor={themeV2.border.default} flexGrow={1} />
|
||||||
<box flexDirection="row" gap={1} paddingLeft={1} paddingRight={1}>
|
<box flexDirection="row" gap={1} paddingLeft={1} paddingRight={1}>
|
||||||
<text fg={themeV2.text.subdued()}>◇</text>
|
<text fg={themeV2.text.subdued}>◇</text>
|
||||||
<text fg={themeV2.text.subdued()}>Compaction queued</text>
|
<text fg={themeV2.text.subdued}>Compaction queued</text>
|
||||||
</box>
|
</box>
|
||||||
<box border={["top"]} borderColor={themeV2.border()} flexGrow={1} />
|
<box border={["top"]} borderColor={themeV2.border.default} flexGrow={1} />
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1572,15 +1573,15 @@ function RevertMessage(props: {
|
||||||
marginTop={1}
|
marginTop={1}
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
borderColor={themeV2.background()}
|
borderColor={themeV2.background.default}
|
||||||
>
|
>
|
||||||
<box
|
<box
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
backgroundColor={hover() ? themeV2.raise(themeV2.background()) : themeV2.background()}
|
backgroundColor={hover() ? themeV2.raise(themeV2.background.default) : themeV2.background.default}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.subdued()}>
|
<text fg={themeV2.text.subdued}>
|
||||||
{props.count} message{props.count === 1 ? "" : "s"} reverted
|
{props.count} message{props.count === 1 ? "" : "s"} reverted
|
||||||
</text>
|
</text>
|
||||||
<Show when={props.files.length > 0}>
|
<Show when={props.files.length > 0}>
|
||||||
|
|
@ -1588,7 +1589,7 @@ function RevertMessage(props: {
|
||||||
<For each={props.files}>
|
<For each={props.files}>
|
||||||
{(file) => (
|
{(file) => (
|
||||||
<box flexDirection="row" gap={1} flexShrink={0}>
|
<box flexDirection="row" gap={1} flexShrink={0}>
|
||||||
<text fg={themeV2.text.subdued()}>{statusLabel(file.status)}</text>
|
<text fg={themeV2.text.subdued}>{statusLabel(file.status)}</text>
|
||||||
<FilePath
|
<FilePath
|
||||||
value={file.file}
|
value={file.file}
|
||||||
maxWidth={Math.max(
|
maxWidth={Math.max(
|
||||||
|
|
@ -1598,21 +1599,21 @@ function RevertMessage(props: {
|
||||||
(file.additions > 0 ? stringWidth(`+${file.additions}`) + 1 : 0) -
|
(file.additions > 0 ? stringWidth(`+${file.additions}`) + 1 : 0) -
|
||||||
(file.deletions > 0 ? stringWidth(`-${file.deletions}`) + 1 : 0),
|
(file.deletions > 0 ? stringWidth(`-${file.deletions}`) + 1 : 0),
|
||||||
)}
|
)}
|
||||||
fg={themeV2.text()}
|
fg={themeV2.text.default}
|
||||||
/>
|
/>
|
||||||
<Show when={file.additions > 0}>
|
<Show when={file.additions > 0}>
|
||||||
<text fg={themeV2.diff.text.added()}>+{file.additions}</text>
|
<text fg={themeV2.diff.text.added}>+{file.additions}</text>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={file.deletions > 0}>
|
<Show when={file.deletions > 0}>
|
||||||
<text fg={themeV2.diff.text.removed()}>-{file.deletions}</text>
|
<text fg={themeV2.diff.text.removed}>-{file.deletions}</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<text fg={themeV2.text.subdued()}>
|
<text fg={themeV2.text.subdued}>
|
||||||
<span style={{ fg: themeV2.text() }}>{redoKey()}</span> or /redo to restore
|
<span style={{ fg: themeV2.text.default }}>{redoKey()}</span> or /redo to restore
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -1630,13 +1631,13 @@ function ShellMessage(props: { message: Extract<SessionMessageInfo, { type: "she
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
gap={1}
|
gap={1}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
borderColor={themeV2.background()}
|
borderColor={themeV2.background.default}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text()}>$ {props.message.command}</text>
|
<text fg={themeV2.text.default}>$ {props.message.command}</text>
|
||||||
<Show when={output()}>
|
<Show when={output()}>
|
||||||
<text fg={themeV2.text.subdued()}>{output()}</text>
|
<text fg={themeV2.text.subdued}>{output()}</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
|
|
@ -1661,7 +1662,7 @@ function UserMessage(props: { message: SessionMessageUser }) {
|
||||||
<Show when={props.message.text.trim() || files().length}>
|
<Show when={props.message.text.trim() || files().length}>
|
||||||
<box
|
<box
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
borderColor={queued() ? themeV2.border() : color()}
|
borderColor={queued() ? themeV2.border.default : color()}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
>
|
>
|
||||||
<box
|
<box
|
||||||
|
|
@ -1684,27 +1685,27 @@ function UserMessage(props: { message: SessionMessageUser }) {
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
backgroundColor={hover() ? themeV2.raise(themeV2.background()) : themeV2.background()}
|
backgroundColor={hover() ? themeV2.raise(themeV2.background.default) : themeV2.background.default}
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text()}>{props.message.text}</text>
|
<text fg={themeV2.text.default}>{props.message.text}</text>
|
||||||
<Show when={files().length}>
|
<Show when={files().length}>
|
||||||
<box flexDirection="row" paddingTop={1} gap={1} flexWrap="wrap">
|
<box flexDirection="row" paddingTop={1} gap={1} flexWrap="wrap">
|
||||||
<For each={files()}>
|
<For each={files()}>
|
||||||
{(file) => {
|
{(file) => {
|
||||||
const label = file.mime === "application/x-directory" ? "dir" : "file"
|
const label = file.mime === "application/x-directory" ? "dir" : "file"
|
||||||
return (
|
return (
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
bg: themeV2.hue.accent(mode() === "light" ? 700 : 200),
|
bg: themeV2.hue.accent[mode() === "light" ? 700 : 200],
|
||||||
fg: themeV2.background(),
|
fg: themeV2.background.default,
|
||||||
bold: true,
|
bold: true,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{` ${label} `}
|
{` ${label} `}
|
||||||
</span>
|
</span>
|
||||||
<span style={{ bg: themeV2.raise(themeV2.background()), fg: themeV2.text.subdued() }}>
|
<span style={{ bg: themeV2.raise(themeV2.background.default), fg: themeV2.text.subdued }}>
|
||||||
{" "}
|
{" "}
|
||||||
{file.name ?? (file.source.type === "uri" ? file.source.uri : "attachment")}{" "}
|
{file.name ?? (file.source.type === "uri" ? file.source.uri : "attachment")}{" "}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -1809,11 +1810,11 @@ function AssistantMessage(props: { message: SessionMessageAssistant; last: boole
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
borderColor={themeV2.text.feedback.error()}
|
borderColor={themeV2.text.feedback.error.default}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.subdued()}>{errorMessage(props.message.error)}</text>
|
<text fg={themeV2.text.subdued}>{errorMessage(props.message.error)}</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<AssistantRetry retry={props.message.retry} />
|
<AssistantRetry retry={props.message.retry} />
|
||||||
|
|
@ -1821,14 +1822,12 @@ function AssistantMessage(props: { message: SessionMessageAssistant; last: boole
|
||||||
<Match when={props.last || final() || props.message.error}>
|
<Match when={props.last || final() || props.message.error}>
|
||||||
<box paddingLeft={3}>
|
<box paddingLeft={3}>
|
||||||
<text>
|
<text>
|
||||||
<span
|
<span style={{ fg: props.message.error ? themeV2.text.subdued : local.agent.color(props.message.agent) }}>
|
||||||
style={{ fg: props.message.error ? themeV2.text.subdued() : local.agent.color(props.message.agent) }}
|
|
||||||
>
|
|
||||||
{Locale.titlecase(props.message.agent)}
|
{Locale.titlecase(props.message.agent)}
|
||||||
</span>
|
</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}> · {model()}</span>
|
<span style={{ fg: themeV2.text.subdued }}> · {model()}</span>
|
||||||
<Show when={duration()}>
|
<Show when={duration()}>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}> · {Locale.duration(duration())}</span>
|
<span style={{ fg: themeV2.text.subdued }}> · {Locale.duration(duration())}</span>
|
||||||
</Show>
|
</Show>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -1844,7 +1843,7 @@ function AssistantRetry(props: { retry: SessionMessageAssistant["retry"] }) {
|
||||||
<Show when={props.retry}>
|
<Show when={props.retry}>
|
||||||
{(retry) => (
|
{(retry) => (
|
||||||
<box paddingLeft={3} marginTop={1}>
|
<box paddingLeft={3} marginTop={1}>
|
||||||
<text fg={themeV2.text.subdued()}>
|
<text fg={themeV2.text.subdued}>
|
||||||
Retry attempt {retry().attempt} scheduled: {retry().error.message} [{retry().error.type}]
|
Retry attempt {retry().attempt} scheduled: {retry().error.message} [{retry().error.type}]
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -1867,7 +1866,7 @@ function ExplorationSummary(props: { parts: SessionMessageAssistantTool[]; activ
|
||||||
<box flexDirection="column">
|
<box flexDirection="column">
|
||||||
<InlineToolRow
|
<InlineToolRow
|
||||||
icon="✱"
|
icon="✱"
|
||||||
color={themeV2.text.subdued()}
|
color={themeV2.text.subdued}
|
||||||
complete={!props.active}
|
complete={!props.active}
|
||||||
pending="Exploring"
|
pending="Exploring"
|
||||||
spinner={props.active}
|
spinner={props.active}
|
||||||
|
|
@ -1877,7 +1876,7 @@ function ExplorationSummary(props: { parts: SessionMessageAssistantTool[]; activ
|
||||||
<For each={props.parts}>
|
<For each={props.parts}>
|
||||||
{(part, index) => (
|
{(part, index) => (
|
||||||
<box paddingLeft={5}>
|
<box paddingLeft={5}>
|
||||||
<text fg={part.state.status === "error" ? themeV2.text.feedback.error() : themeV2.text.subdued()}>
|
<text fg={part.state.status === "error" ? themeV2.text.feedback.error.default : themeV2.text.subdued}>
|
||||||
{index() === props.parts.length - 1 ? "└" : "├"} {label(part)}
|
{index() === props.parts.length - 1 ? "└" : "├"} {label(part)}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -1922,7 +1921,7 @@ function ReasoningPart(props: {
|
||||||
<box
|
<box
|
||||||
border={!inMinimal() || expanded() ? ["left"] : undefined}
|
border={!inMinimal() || expanded() ? ["left"] : undefined}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
borderColor={themeV2.raise(themeV2.background())}
|
borderColor={themeV2.raise(themeV2.background.default)}
|
||||||
paddingLeft={!inMinimal() || expanded() ? 1 : 0}
|
paddingLeft={!inMinimal() || expanded() ? 1 : 0}
|
||||||
>
|
>
|
||||||
<box onMouseUp={toggle}>
|
<box onMouseUp={toggle}>
|
||||||
|
|
@ -1940,7 +1939,7 @@ function ReasoningPart(props: {
|
||||||
<box
|
<box
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
borderColor={themeV2.raise(themeV2.background())}
|
borderColor={themeV2.raise(themeV2.background.default)}
|
||||||
paddingLeft={inMinimal() ? 3 : 1}
|
paddingLeft={inMinimal() ? 3 : 1}
|
||||||
>
|
>
|
||||||
<code
|
<code
|
||||||
|
|
@ -1950,7 +1949,7 @@ function ReasoningPart(props: {
|
||||||
syntaxStyle={syntax()}
|
syntaxStyle={syntax()}
|
||||||
content={content()}
|
content={content()}
|
||||||
conceal={ctx.markdownMode() === "rendered"}
|
conceal={ctx.markdownMode() === "rendered"}
|
||||||
fg={themeV2.text.subdued()}
|
fg={themeV2.text.subdued}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -1976,12 +1975,12 @@ function ReasoningHeader(props: {
|
||||||
const fg = () =>
|
const fg = () =>
|
||||||
props.open
|
props.open
|
||||||
? RGBA.fromValues(
|
? RGBA.fromValues(
|
||||||
themeV2.text.feedback.warning().r,
|
themeV2.text.feedback.warning.default.r,
|
||||||
themeV2.text.feedback.warning().g,
|
themeV2.text.feedback.warning.default.g,
|
||||||
themeV2.text.feedback.warning().b,
|
themeV2.text.feedback.warning.default.b,
|
||||||
0.6,
|
0.6,
|
||||||
)
|
)
|
||||||
: themeV2.text.feedback.warning()
|
: themeV2.text.feedback.warning.default
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|
@ -2027,8 +2026,8 @@ function TextPart(props: { last: boolean; part: SessionMessageAssistantText }) {
|
||||||
content={props.part.text.trim()}
|
content={props.part.text.trim()}
|
||||||
tableOptions={{ style: "grid" }}
|
tableOptions={{ style: "grid" }}
|
||||||
conceal={ctx.markdownMode() === "rendered"}
|
conceal={ctx.markdownMode() === "rendered"}
|
||||||
fg={themeV2.markdown()}
|
fg={themeV2.markdown.text}
|
||||||
bg={themeV2.background()}
|
bg={themeV2.background.default}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -2135,7 +2134,7 @@ function GenericTool(props: ToolProps) {
|
||||||
<Show when={Object.keys(props.input).length > 0}>
|
<Show when={Object.keys(props.input).length > 0}>
|
||||||
<box gap={1}>
|
<box gap={1}>
|
||||||
<text>
|
<text>
|
||||||
<span style={{ bg: themeV2.raise(themeV2.background()), fg: themeV2.text.subdued() }}> Input </span>
|
<span style={{ bg: themeV2.raise(themeV2.background.default), fg: themeV2.text.subdued }}> Input </span>
|
||||||
</text>
|
</text>
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<code
|
<code
|
||||||
|
|
@ -2144,7 +2143,7 @@ function GenericTool(props: ToolProps) {
|
||||||
syntaxStyle={syntax()}
|
syntaxStyle={syntax()}
|
||||||
conceal={false}
|
conceal={false}
|
||||||
drawUnstyledText={false}
|
drawUnstyledText={false}
|
||||||
fg={themeV2.text()}
|
fg={themeV2.text.default}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -2153,10 +2152,13 @@ function GenericTool(props: ToolProps) {
|
||||||
{(value) => (
|
{(value) => (
|
||||||
<box gap={1}>
|
<box gap={1}>
|
||||||
<text>
|
<text>
|
||||||
<span style={{ bg: themeV2.raise(themeV2.background()), fg: themeV2.text.subdued() }}> Output </span>
|
<span style={{ bg: themeV2.raise(themeV2.background.default), fg: themeV2.text.subdued }}>
|
||||||
|
{" "}
|
||||||
|
Output{" "}
|
||||||
|
</span>
|
||||||
</text>
|
</text>
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<text fg={themeV2.text()} wrapMode="word">
|
<text fg={themeV2.text.default} wrapMode="word">
|
||||||
{value()}
|
{value()}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -2208,10 +2210,10 @@ function InlineTool(props: {
|
||||||
const clickable = createMemo(() => Boolean(props.onClick || failed()))
|
const clickable = createMemo(() => Boolean(props.onClick || failed()))
|
||||||
const fg = createMemo(() => {
|
const fg = createMemo(() => {
|
||||||
if (props.color) return props.color
|
if (props.color) return props.color
|
||||||
if (permission()) return themeV2.text.feedback.warning()
|
if (permission()) return themeV2.text.feedback.warning.default
|
||||||
if (failed()) return themeV2.text.feedback.error()
|
if (failed()) return themeV2.text.feedback.error.default
|
||||||
if (hover() && props.onClick) return themeV2.text()
|
if (hover() && props.onClick) return themeV2.text.default
|
||||||
return themeV2.text.subdued()
|
return themeV2.text.subdued
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -2219,7 +2221,7 @@ function InlineTool(props: {
|
||||||
icon={props.icon}
|
icon={props.icon}
|
||||||
iconColor={props.iconColor}
|
iconColor={props.iconColor}
|
||||||
color={fg()}
|
color={fg()}
|
||||||
errorColor={themeV2.text.feedback.error()}
|
errorColor={themeV2.text.feedback.error.default}
|
||||||
failed={failed()}
|
failed={failed()}
|
||||||
denied={Boolean(denied())}
|
denied={Boolean(denied())}
|
||||||
error={error()}
|
error={error()}
|
||||||
|
|
@ -2343,7 +2345,7 @@ function InlineToolLabel(props: { color?: RGBA; denied?: boolean; status: JSX.El
|
||||||
function StatusBadge(props: { children: string }) {
|
function StatusBadge(props: { children: string }) {
|
||||||
const { themeV2 } = useTheme()
|
const { themeV2 } = useTheme()
|
||||||
return (
|
return (
|
||||||
<text flexShrink={0} bg={themeV2.raise(themeV2.background())} fg={themeV2.text.subdued()}>
|
<text flexShrink={0} bg={themeV2.raise(themeV2.background.default)} fg={themeV2.text.subdued}>
|
||||||
{" "}
|
{" "}
|
||||||
{props.children}{" "}
|
{props.children}{" "}
|
||||||
</text>
|
</text>
|
||||||
|
|
@ -2376,9 +2378,9 @@ function BlockTool(props: {
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
gap={1}
|
gap={1}
|
||||||
backgroundColor={hover() ? themeV2.raise(themeV2.background()) : themeV2.background()}
|
backgroundColor={hover() ? themeV2.raise(themeV2.background.default) : themeV2.background.default}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
borderColor={themeV2.background()}
|
borderColor={themeV2.background.default}
|
||||||
onMouseOver={() => props.onClick && setHover(true)}
|
onMouseOver={() => props.onClick && setHover(true)}
|
||||||
onMouseOut={() => setHover(false)}
|
onMouseOut={() => setHover(false)}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
|
|
@ -2394,10 +2396,12 @@ function BlockTool(props: {
|
||||||
<Show
|
<Show
|
||||||
when={props.spinner}
|
when={props.spinner}
|
||||||
fallback={
|
fallback={
|
||||||
<text fg={permission() ? themeV2.text.feedback.warning() : themeV2.text.subdued()}>{title()}</text>
|
<text fg={permission() ? themeV2.text.feedback.warning.default : themeV2.text.subdued}>
|
||||||
|
{title()}
|
||||||
|
</text>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Spinner color={permission() ? themeV2.text.feedback.warning() : themeV2.text.subdued()}>
|
<Spinner color={permission() ? themeV2.text.feedback.warning.default : themeV2.text.subdued}>
|
||||||
{title().replace(/^# /, "")}
|
{title().replace(/^# /, "")}
|
||||||
</Spinner>
|
</Spinner>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -2410,26 +2414,26 @@ function BlockTool(props: {
|
||||||
<Show
|
<Show
|
||||||
when={props.spinner}
|
when={props.spinner}
|
||||||
fallback={
|
fallback={
|
||||||
<text flexShrink={0} fg={permission() ? themeV2.text.feedback.warning() : themeV2.text.subdued()}>
|
<text flexShrink={0} fg={permission() ? themeV2.text.feedback.warning.default : themeV2.text.subdued}>
|
||||||
{path().label}
|
{path().label}
|
||||||
</text>
|
</text>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Spinner color={permission() ? themeV2.text.feedback.warning() : themeV2.text.subdued()}>
|
<Spinner color={permission() ? themeV2.text.feedback.warning.default : themeV2.text.subdued}>
|
||||||
{path().label.replace(/^# /, "")}
|
{path().label.replace(/^# /, "")}
|
||||||
</Spinner>
|
</Spinner>
|
||||||
</Show>
|
</Show>
|
||||||
<FilePath
|
<FilePath
|
||||||
value={path().value}
|
value={path().value}
|
||||||
maxWidth={Math.max(2, ctx.width - 4 - stringWidth(path().label) - (props.spinner ? 2 : 0))}
|
maxWidth={Math.max(2, ctx.width - 4 - stringWidth(path().label) - (props.spinner ? 2 : 0))}
|
||||||
fg={permission() ? themeV2.text.feedback.warning() : themeV2.text.subdued()}
|
fg={permission() ? themeV2.text.feedback.warning.default : themeV2.text.subdued}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</Show>
|
</Show>
|
||||||
{props.children}
|
{props.children}
|
||||||
<Show when={error()}>
|
<Show when={error()}>
|
||||||
<text fg={themeV2.text.feedback.error()}>{error()}</text>
|
<text fg={themeV2.text.feedback.error.default}>{error()}</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
)
|
)
|
||||||
|
|
@ -2444,7 +2448,7 @@ function Shell(props: ToolProps) {
|
||||||
const request = data.session.permission.list(ctx.sessionID)?.[0]
|
const request = data.session.permission.list(ctx.sessionID)?.[0]
|
||||||
return request?.source?.type === "tool" && request.source.callID === props.part.id
|
return request?.source?.type === "tool" && request.source.callID === props.part.id
|
||||||
})
|
})
|
||||||
const color = createMemo(() => (permission() ? themeV2.text.feedback.warning() : themeV2.text()))
|
const color = createMemo(() => (permission() ? themeV2.text.feedback.warning.default : themeV2.text.default))
|
||||||
const shellID = createMemo(() => stringValue(props.metadata.shellID))
|
const shellID = createMemo(() => stringValue(props.metadata.shellID))
|
||||||
const backgroundRunning = createMemo(() => {
|
const backgroundRunning = createMemo(() => {
|
||||||
const id = shellID()
|
const id = shellID()
|
||||||
|
|
@ -2506,7 +2510,7 @@ function Shell(props: ToolProps) {
|
||||||
isRunning() || props.part.state.status === "streaming" ? (
|
isRunning() || props.part.state.status === "streaming" ? (
|
||||||
<Spinner color={color()}>Writing command...</Spinner>
|
<Spinner color={color()}>Writing command...</Spinner>
|
||||||
) : (
|
) : (
|
||||||
<text fg={themeV2.text.subdued()}>Writing command...</text>
|
<text fg={themeV2.text.subdued}>Writing command...</text>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -2514,14 +2518,14 @@ function Shell(props: ToolProps) {
|
||||||
when={isRunning()}
|
when={isRunning()}
|
||||||
fallback={
|
fallback={
|
||||||
<text>
|
<text>
|
||||||
<span style={{ fg: themeV2.text() }}>{limited().slice(0, input().length)}</span>
|
<span style={{ fg: themeV2.text.default }}>{limited().slice(0, input().length)}</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{limited().slice(input().length)}</span>
|
<span style={{ fg: themeV2.text.subdued }}>{limited().slice(input().length)}</span>
|
||||||
</text>
|
</text>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Spinner color={color()}>
|
<Spinner color={color()}>
|
||||||
<span style={{ fg: themeV2.text() }}>{limited().slice(0, input().length)}</span>
|
<span style={{ fg: themeV2.text.default }}>{limited().slice(0, input().length)}</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{limited().slice(input().length)}</span>
|
<span style={{ fg: themeV2.text.subdued }}>{limited().slice(input().length)}</span>
|
||||||
</Spinner>
|
</Spinner>
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -2547,10 +2551,10 @@ function Write(props: ToolProps) {
|
||||||
path={{ label: "# Wrote", value: pathFormatter.format(stringValue(props.input.path)) }}
|
path={{ label: "# Wrote", value: pathFormatter.format(stringValue(props.input.path)) }}
|
||||||
part={props.part}
|
part={props.part}
|
||||||
>
|
>
|
||||||
<line_number fg={themeV2.text.subdued()} minWidth={3} paddingRight={1}>
|
<line_number fg={themeV2.text.subdued} minWidth={3} paddingRight={1}>
|
||||||
<code
|
<code
|
||||||
conceal={false}
|
conceal={false}
|
||||||
fg={themeV2.text()}
|
fg={themeV2.text.default}
|
||||||
filetype={filetype(stringValue(props.input.path))}
|
filetype={filetype(stringValue(props.input.path))}
|
||||||
syntaxStyle={syntax()}
|
syntaxStyle={syntax()}
|
||||||
content={code()}
|
content={code()}
|
||||||
|
|
@ -2605,7 +2609,7 @@ function Read(props: ToolProps) {
|
||||||
<For each={loaded()}>
|
<For each={loaded()}>
|
||||||
{(filepath) => (
|
{(filepath) => (
|
||||||
<box paddingLeft={3}>
|
<box paddingLeft={3}>
|
||||||
<text paddingLeft={3} fg={themeV2.text.subdued()}>
|
<text paddingLeft={3} fg={themeV2.text.subdued}>
|
||||||
↳ Loaded {pathFormatter.format(filepath)}
|
↳ Loaded {pathFormatter.format(filepath)}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -2724,7 +2728,7 @@ function Execute(props: ToolProps) {
|
||||||
<>
|
<>
|
||||||
<InlineTool
|
<InlineTool
|
||||||
icon={hasRuntimeError() ? "✗" : props.part.state.status === "completed" ? "✓" : "│"}
|
icon={hasRuntimeError() ? "✗" : props.part.state.status === "completed" ? "✓" : "│"}
|
||||||
color={hasRuntimeError() ? themeV2.text.feedback.error() : undefined}
|
color={hasRuntimeError() ? themeV2.text.feedback.error.default : undefined}
|
||||||
spinner={isLoading()}
|
spinner={isLoading()}
|
||||||
pending="execute"
|
pending="execute"
|
||||||
complete={true}
|
complete={true}
|
||||||
|
|
@ -2736,7 +2740,7 @@ function Execute(props: ToolProps) {
|
||||||
<box paddingLeft={3}>
|
<box paddingLeft={3}>
|
||||||
<For each={outputPreview().split("\n")}>
|
<For each={outputPreview().split("\n")}>
|
||||||
{(line, index) => (
|
{(line, index) => (
|
||||||
<text paddingLeft={3} fg={themeV2.text.feedback.error()}>
|
<text paddingLeft={3} fg={themeV2.text.feedback.error.default}>
|
||||||
{index() === 0 ? "↳ " : " "}
|
{index() === 0 ? "↳ " : " "}
|
||||||
{line}
|
{line}
|
||||||
</text>
|
</text>
|
||||||
|
|
@ -2778,16 +2782,16 @@ function Edit(props: ToolProps) {
|
||||||
showLineNumbers={true}
|
showLineNumbers={true}
|
||||||
width="100%"
|
width="100%"
|
||||||
wrapMode={ctx.diffWrapMode()}
|
wrapMode={ctx.diffWrapMode()}
|
||||||
fg={themeV2.text()}
|
fg={themeV2.text.default}
|
||||||
addedBg={themeV2.diff.background.added()}
|
addedBg={themeV2.diff.background.added}
|
||||||
removedBg={themeV2.diff.background.removed()}
|
removedBg={themeV2.diff.background.removed}
|
||||||
contextBg={themeV2.diff.background.context()}
|
contextBg={themeV2.diff.background.context}
|
||||||
addedSignColor={themeV2.diff.highlight.added()}
|
addedSignColor={themeV2.diff.highlight.added}
|
||||||
removedSignColor={themeV2.diff.highlight.removed()}
|
removedSignColor={themeV2.diff.highlight.removed}
|
||||||
lineNumberFg={themeV2.diff.lineNumber.text()}
|
lineNumberFg={themeV2.diff.lineNumber.text}
|
||||||
lineNumberBg={themeV2.diff.background.context()}
|
lineNumberBg={themeV2.diff.background.context}
|
||||||
addedLineNumberBg={themeV2.diff.lineNumber.background.added()}
|
addedLineNumberBg={themeV2.diff.lineNumber.background.added}
|
||||||
removedLineNumberBg={themeV2.diff.lineNumber.background.removed()}
|
removedLineNumberBg={themeV2.diff.lineNumber.background.removed}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
<Diagnostics diagnostics={props.metadata.diagnostics} filePath={stringValue(props.input.path) ?? ""} />
|
<Diagnostics diagnostics={props.metadata.diagnostics} filePath={stringValue(props.input.path) ?? ""} />
|
||||||
|
|
@ -2852,7 +2856,7 @@ function ApplyPatch(props: ToolProps) {
|
||||||
<Show
|
<Show
|
||||||
when={file.type !== "delete"}
|
when={file.type !== "delete"}
|
||||||
fallback={
|
fallback={
|
||||||
<text fg={themeV2.diff.text.removed()}>
|
<text fg={themeV2.diff.text.removed}>
|
||||||
-{file.deletions} line{file.deletions !== 1 ? "s" : ""}
|
-{file.deletions} line{file.deletions !== 1 ? "s" : ""}
|
||||||
</text>
|
</text>
|
||||||
}
|
}
|
||||||
|
|
@ -2866,16 +2870,16 @@ function ApplyPatch(props: ToolProps) {
|
||||||
showLineNumbers={true}
|
showLineNumbers={true}
|
||||||
width="100%"
|
width="100%"
|
||||||
wrapMode={ctx.diffWrapMode()}
|
wrapMode={ctx.diffWrapMode()}
|
||||||
fg={themeV2.text()}
|
fg={themeV2.text.default}
|
||||||
addedBg={themeV2.diff.background.added()}
|
addedBg={themeV2.diff.background.added}
|
||||||
removedBg={themeV2.diff.background.removed()}
|
removedBg={themeV2.diff.background.removed}
|
||||||
contextBg={themeV2.diff.background.context()}
|
contextBg={themeV2.diff.background.context}
|
||||||
addedSignColor={themeV2.diff.highlight.added()}
|
addedSignColor={themeV2.diff.highlight.added}
|
||||||
removedSignColor={themeV2.diff.highlight.removed()}
|
removedSignColor={themeV2.diff.highlight.removed}
|
||||||
lineNumberFg={themeV2.diff.lineNumber.text()}
|
lineNumberFg={themeV2.diff.lineNumber.text}
|
||||||
lineNumberBg={themeV2.diff.background.context()}
|
lineNumberBg={themeV2.diff.background.context}
|
||||||
addedLineNumberBg={themeV2.diff.lineNumber.background.added()}
|
addedLineNumberBg={themeV2.diff.lineNumber.background.added}
|
||||||
removedLineNumberBg={themeV2.diff.lineNumber.background.removed()}
|
removedLineNumberBg={themeV2.diff.lineNumber.background.removed}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -2898,7 +2902,7 @@ function ApplyPatch(props: ToolProps) {
|
||||||
<FilePath
|
<FilePath
|
||||||
value={file.resource}
|
value={file.resource}
|
||||||
maxWidth={Math.max(2, ctx.width - 3)}
|
maxWidth={Math.max(2, ctx.width - 3)}
|
||||||
fg={file.type === "delete" ? themeV2.diff.text.removed() : themeV2.text.subdued()}
|
fg={file.type === "delete" ? themeV2.diff.text.removed : themeV2.text.subdued}
|
||||||
/>
|
/>
|
||||||
</BlockTool>
|
</BlockTool>
|
||||||
)}
|
)}
|
||||||
|
|
@ -2945,8 +2949,8 @@ function Question(props: ToolProps) {
|
||||||
<For each={questions()}>
|
<For each={questions()}>
|
||||||
{(q, i) => (
|
{(q, i) => (
|
||||||
<box flexDirection="column">
|
<box flexDirection="column">
|
||||||
<text fg={themeV2.text.subdued()}>{q.question}</text>
|
<text fg={themeV2.text.subdued}>{q.question}</text>
|
||||||
<text fg={themeV2.text()}>{format(answers()?.[i()])}</text>
|
<text fg={themeV2.text.default}>{format(answers()?.[i()])}</text>
|
||||||
</box>
|
</box>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
|
|
@ -2987,7 +2991,7 @@ function Diagnostics(props: { diagnostics: unknown; filePath: string }) {
|
||||||
<box>
|
<box>
|
||||||
<For each={errors()}>
|
<For each={errors()}>
|
||||||
{(diagnostic) => (
|
{(diagnostic) => (
|
||||||
<text fg={themeV2.text.feedback.error()}>
|
<text fg={themeV2.text.feedback.error.default}>
|
||||||
Error [{diagnostic.range.start.line + 1}:{diagnostic.range.start.character + 1}] {diagnostic.message}
|
Error [{diagnostic.range.start.line + 1}:{diagnostic.range.start.character + 1}] {diagnostic.message}
|
||||||
</text>
|
</text>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ function EditBody(props: { file?: string; diff?: string; patch?: string }) {
|
||||||
scrollAcceleration={scrollAcceleration()}
|
scrollAcceleration={scrollAcceleration()}
|
||||||
verticalScrollbarOptions={{
|
verticalScrollbarOptions={{
|
||||||
trackOptions: {
|
trackOptions: {
|
||||||
backgroundColor: themeV2.background(),
|
backgroundColor: themeV2.background.default,
|
||||||
foregroundColor: themeV2.scrollbar(),
|
foregroundColor: themeV2.scrollbar.default,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -58,16 +58,16 @@ function EditBody(props: { file?: string; diff?: string; patch?: string }) {
|
||||||
showLineNumbers={true}
|
showLineNumbers={true}
|
||||||
width="100%"
|
width="100%"
|
||||||
wrapMode="word"
|
wrapMode="word"
|
||||||
fg={themeV2.text()}
|
fg={themeV2.text.default}
|
||||||
addedBg={themeV2.diff.background.added()}
|
addedBg={themeV2.diff.background.added}
|
||||||
removedBg={themeV2.diff.background.removed()}
|
removedBg={themeV2.diff.background.removed}
|
||||||
contextBg={themeV2.diff.background.context()}
|
contextBg={themeV2.diff.background.context}
|
||||||
addedSignColor={themeV2.diff.highlight.added()}
|
addedSignColor={themeV2.diff.highlight.added}
|
||||||
removedSignColor={themeV2.diff.highlight.removed()}
|
removedSignColor={themeV2.diff.highlight.removed}
|
||||||
lineNumberFg={themeV2.diff.lineNumber.text()}
|
lineNumberFg={themeV2.diff.lineNumber.text}
|
||||||
lineNumberBg={themeV2.diff.background.context()}
|
lineNumberBg={themeV2.diff.background.context}
|
||||||
addedLineNumberBg={themeV2.diff.lineNumber.background.added()}
|
addedLineNumberBg={themeV2.diff.lineNumber.background.added}
|
||||||
removedLineNumberBg={themeV2.diff.lineNumber.background.removed()}
|
removedLineNumberBg={themeV2.diff.lineNumber.background.removed}
|
||||||
/>
|
/>
|
||||||
</scrollbox>
|
</scrollbox>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -76,7 +76,7 @@ function EditBody(props: { file?: string; diff?: string; patch?: string }) {
|
||||||
when={props.patch}
|
when={props.patch}
|
||||||
fallback={
|
fallback={
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<text fg={themeV2.text.subdued()}>No diff provided</text>
|
<text fg={themeV2.text.subdued}>No diff provided</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -86,8 +86,8 @@ function EditBody(props: { file?: string; diff?: string; patch?: string }) {
|
||||||
scrollAcceleration={scrollAcceleration()}
|
scrollAcceleration={scrollAcceleration()}
|
||||||
verticalScrollbarOptions={{
|
verticalScrollbarOptions={{
|
||||||
trackOptions: {
|
trackOptions: {
|
||||||
backgroundColor: themeV2.background(),
|
backgroundColor: themeV2.background.default,
|
||||||
foregroundColor: themeV2.scrollbar(),
|
foregroundColor: themeV2.scrollbar.default,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -97,7 +97,7 @@ function EditBody(props: { file?: string; diff?: string; patch?: string }) {
|
||||||
streaming={true}
|
streaming={true}
|
||||||
syntaxStyle={syntax()}
|
syntaxStyle={syntax()}
|
||||||
content={patch()}
|
content={patch()}
|
||||||
fg={themeV2.text.subdued()}
|
fg={themeV2.text.subdued}
|
||||||
/>
|
/>
|
||||||
</scrollbox>
|
</scrollbox>
|
||||||
)}
|
)}
|
||||||
|
|
@ -140,7 +140,7 @@ export function PermissionPrompt(props: { request: PermissionV2Request; director
|
||||||
body={
|
body={
|
||||||
<box paddingLeft={1} gap={1}>
|
<box paddingLeft={1} gap={1}>
|
||||||
<For each={permissionAlwaysLines(props.request)}>
|
<For each={permissionAlwaysLines(props.request)}>
|
||||||
{(line, index) => <text fg={index() === 0 ? themeV2.text.subdued() : themeV2.text()}>{line}</text>}
|
{(line, index) => <text fg={index() === 0 ? themeV2.text.subdued : themeV2.text.default}>{line}</text>}
|
||||||
</For>
|
</For>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
|
|
@ -192,9 +192,9 @@ export function PermissionPrompt(props: { request: PermissionV2Request; director
|
||||||
) : props.request.action === "external_directory" ? (
|
) : props.request.action === "external_directory" ? (
|
||||||
<Show when={current.lines.length > 0}>
|
<Show when={current.lines.length > 0}>
|
||||||
<box paddingLeft={1} gap={1}>
|
<box paddingLeft={1} gap={1}>
|
||||||
<text fg={themeV2.text.subdued()}>Patterns</text>
|
<text fg={themeV2.text.subdued}>Patterns</text>
|
||||||
<box>
|
<box>
|
||||||
<For each={current.lines}>{(line) => <text fg={themeV2.text()}>{line}</text>}</For>
|
<For each={current.lines}>{(line) => <text fg={themeV2.text.default}>{line}</text>}</For>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
@ -207,8 +207,8 @@ export function PermissionPrompt(props: { request: PermissionV2Request; director
|
||||||
props.request.action === "shell" ||
|
props.request.action === "shell" ||
|
||||||
props.request.action === "subagent" ||
|
props.request.action === "subagent" ||
|
||||||
props.request.action === "task"
|
props.request.action === "task"
|
||||||
? themeV2.text()
|
? themeV2.text.default
|
||||||
: themeV2.text.subdued()
|
: themeV2.text.subdued
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{line}
|
{line}
|
||||||
|
|
@ -221,15 +221,15 @@ export function PermissionPrompt(props: { request: PermissionV2Request; director
|
||||||
const header = () => (
|
const header = () => (
|
||||||
<box flexDirection="column" gap={0}>
|
<box flexDirection="column" gap={0}>
|
||||||
<box flexDirection="row" gap={1} flexShrink={0}>
|
<box flexDirection="row" gap={1} flexShrink={0}>
|
||||||
<text fg={themeV2.text.feedback.warning()}>{"△"}</text>
|
<text fg={themeV2.text.feedback.warning.default}>{"△"}</text>
|
||||||
<text fg={themeV2.text()}>Permission required</text>
|
<text fg={themeV2.text.default}>Permission required</text>
|
||||||
</box>
|
</box>
|
||||||
<Show when={props.request.action !== "shell" && current.title}>
|
<Show when={props.request.action !== "shell" && current.title}>
|
||||||
<box flexDirection="row" gap={1} paddingLeft={2} flexShrink={0}>
|
<box flexDirection="row" gap={1} paddingLeft={2} flexShrink={0}>
|
||||||
<text fg={themeV2.text.subdued()} flexShrink={0}>
|
<text fg={themeV2.text.subdued} flexShrink={0}>
|
||||||
{current.icon}
|
{current.icon}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text()}>{current.title}</text>
|
<text fg={themeV2.text.default}>{current.title}</text>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -329,18 +329,18 @@ function RejectPrompt(props: {
|
||||||
role: "dialog",
|
role: "dialog",
|
||||||
label: `Reject permission: ${props.action}`,
|
label: `Reject permission: ${props.action}`,
|
||||||
}))}
|
}))}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
borderColor={themeV2.text.feedback.error()}
|
borderColor={themeV2.text.feedback.error.default}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
>
|
>
|
||||||
<box gap={1} paddingLeft={1} paddingRight={3} paddingTop={1} paddingBottom={1}>
|
<box gap={1} paddingLeft={1} paddingRight={3} paddingTop={1} paddingBottom={1}>
|
||||||
<box flexDirection="row" gap={1} paddingLeft={1}>
|
<box flexDirection="row" gap={1} paddingLeft={1}>
|
||||||
<text fg={themeV2.text.feedback.error()}>{"△"}</text>
|
<text fg={themeV2.text.feedback.error.default}>{"△"}</text>
|
||||||
<text fg={themeV2.text()}>Reject permission</text>
|
<text fg={themeV2.text.default}>Reject permission</text>
|
||||||
</box>
|
</box>
|
||||||
<box paddingLeft={1}>
|
<box paddingLeft={1}>
|
||||||
<text fg={themeV2.text.subdued()}>Tell OpenCode what to do differently</text>
|
<text fg={themeV2.text.subdued}>Tell OpenCode what to do differently</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box
|
||||||
|
|
@ -350,7 +350,7 @@ function RejectPrompt(props: {
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
paddingRight={3}
|
paddingRight={3}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
backgroundColor={themeV2.raise(themeV2.background())}
|
backgroundColor={themeV2.raise(themeV2.background.default)}
|
||||||
justifyContent={narrow() ? "flex-start" : "space-between"}
|
justifyContent={narrow() ? "flex-start" : "space-between"}
|
||||||
alignItems={narrow() ? "flex-start" : "center"}
|
alignItems={narrow() ? "flex-start" : "center"}
|
||||||
gap={1}
|
gap={1}
|
||||||
|
|
@ -369,9 +369,9 @@ function RejectPrompt(props: {
|
||||||
val.traits = { status: "REJECT" }
|
val.traits = { status: "REJECT" }
|
||||||
}}
|
}}
|
||||||
focused
|
focused
|
||||||
textColor={themeV2.text()}
|
textColor={themeV2.text.default}
|
||||||
focusedTextColor={themeV2.text()}
|
focusedTextColor={themeV2.text.default}
|
||||||
cursorColor={themeV2.text()}
|
cursorColor={themeV2.text.default}
|
||||||
/>
|
/>
|
||||||
<box
|
<box
|
||||||
id="session.permission.reject.actions"
|
id="session.permission.reject.actions"
|
||||||
|
|
@ -394,8 +394,8 @@ function RejectPrompt(props: {
|
||||||
}))}
|
}))}
|
||||||
onMouseUp={() => props.onConfirm(input.plainText)}
|
onMouseUp={() => props.onConfirm(input.plainText)}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
enter <span style={{ fg: themeV2.text.subdued() }}>confirm</span>
|
enter <span style={{ fg: themeV2.text.subdued }}>confirm</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box
|
||||||
|
|
@ -408,8 +408,8 @@ function RejectPrompt(props: {
|
||||||
}))}
|
}))}
|
||||||
onMouseUp={props.onCancel}
|
onMouseUp={props.onCancel}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
esc <span style={{ fg: themeV2.text.subdued() }}>cancel</span>
|
esc <span style={{ fg: themeV2.text.subdued }}>cancel</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -534,9 +534,9 @@ function Prompt<const T extends Record<string, string>>(props: {
|
||||||
label: props.semanticLabel ?? props.title,
|
label: props.semanticLabel ?? props.title,
|
||||||
expanded: store.expanded,
|
expanded: store.expanded,
|
||||||
}))}
|
}))}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
borderColor={themeV2.background.action("focused")}
|
borderColor={themeV2.background.action.primary.focused}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
{...(store.expanded
|
{...(store.expanded
|
||||||
? { top: dimensions().height * -1 + 1, bottom: 1, left: 2, right: 2, position: "absolute" }
|
? { top: dimensions().height * -1 + 1, bottom: 1, left: 2, right: 2, position: "absolute" }
|
||||||
|
|
@ -554,8 +554,8 @@ function Prompt<const T extends Record<string, string>>(props: {
|
||||||
when={props.header}
|
when={props.header}
|
||||||
fallback={
|
fallback={
|
||||||
<box flexDirection="row" gap={1} paddingLeft={1} flexShrink={0}>
|
<box flexDirection="row" gap={1} paddingLeft={1} flexShrink={0}>
|
||||||
<text fg={themeV2.text.feedback.warning()}>{"△"}</text>
|
<text fg={themeV2.text.feedback.warning.default}>{"△"}</text>
|
||||||
<text fg={themeV2.text()}>{props.title}</text>
|
<text fg={themeV2.text.default}>{props.title}</text>
|
||||||
</box>
|
</box>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
@ -573,7 +573,7 @@ function Prompt<const T extends Record<string, string>>(props: {
|
||||||
paddingLeft={2}
|
paddingLeft={2}
|
||||||
paddingRight={3}
|
paddingRight={3}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
backgroundColor={themeV2.raise(themeV2.background())}
|
backgroundColor={themeV2.raise(themeV2.background.default)}
|
||||||
justifyContent={narrow() ? "flex-start" : "space-between"}
|
justifyContent={narrow() ? "flex-start" : "space-between"}
|
||||||
alignItems={narrow() ? "flex-start" : "center"}
|
alignItems={narrow() ? "flex-start" : "center"}
|
||||||
>
|
>
|
||||||
|
|
@ -602,14 +602,24 @@ function Prompt<const T extends Record<string, string>>(props: {
|
||||||
}))}
|
}))}
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
backgroundColor={themeV2.background.action(option === store.selected ? "focused" : "default")}
|
backgroundColor={
|
||||||
|
option === store.selected
|
||||||
|
? themeV2.background.action.primary.focused
|
||||||
|
: themeV2.background.action.primary.default
|
||||||
|
}
|
||||||
onMouseOver={() => setStore("selected", option)}
|
onMouseOver={() => setStore("selected", option)}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
setStore("selected", option)
|
setStore("selected", option)
|
||||||
props.onSelect(option)
|
props.onSelect(option)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.action(option === store.selected ? "focused" : "default")}>
|
<text
|
||||||
|
fg={
|
||||||
|
option === store.selected
|
||||||
|
? themeV2.text.action.primary.focused
|
||||||
|
: themeV2.text.action.primary.default
|
||||||
|
}
|
||||||
|
>
|
||||||
{props.options[option]}
|
{props.options[option]}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -618,16 +628,15 @@ function Prompt<const T extends Record<string, string>>(props: {
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" gap={2} flexShrink={0}>
|
<box flexDirection="row" gap={2} flexShrink={0}>
|
||||||
<Show when={props.fullscreen}>
|
<Show when={props.fullscreen}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
{shortcuts.get("permission.prompt.fullscreen")}{" "}
|
{shortcuts.get("permission.prompt.fullscreen")} <span style={{ fg: themeV2.text.subdued }}>{hint()}</span>
|
||||||
<span style={{ fg: themeV2.text.subdued() }}>{hint()}</span>
|
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
{"⇆"} <span style={{ fg: themeV2.text.subdued() }}>select</span>
|
{"⇆"} <span style={{ fg: themeV2.text.subdued }}>select</span>
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
enter <span style={{ fg: themeV2.text.subdued() }}>confirm</span>
|
enter <span style={{ fg: themeV2.text.subdued }}>confirm</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
|
||||||
return (
|
return (
|
||||||
<Show when={session()}>
|
<Show when={session()}>
|
||||||
<box
|
<box
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
width={42}
|
width={42}
|
||||||
height="100%"
|
height="100%"
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
|
|
@ -32,8 +32,8 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
|
||||||
scrollAcceleration={scrollAcceleration()}
|
scrollAcceleration={scrollAcceleration()}
|
||||||
verticalScrollbarOptions={{
|
verticalScrollbarOptions={{
|
||||||
trackOptions: {
|
trackOptions: {
|
||||||
backgroundColor: themeV2.background(),
|
backgroundColor: themeV2.background.default,
|
||||||
foregroundColor: themeV2.scrollbar(),
|
foregroundColor: themeV2.scrollbar.default,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
@ -45,11 +45,11 @@ export function Sidebar(props: { sessionID: string; overlay?: boolean }) {
|
||||||
title={session()!.title}
|
title={session()!.title}
|
||||||
>
|
>
|
||||||
<box paddingRight={1}>
|
<box paddingRight={1}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
<b>{session()!.title}</b>
|
<b>{session()!.title}</b>
|
||||||
</text>
|
</text>
|
||||||
<Show when={session()!.location.workspaceID}>
|
<Show when={session()!.location.workspaceID}>
|
||||||
<text fg={themeV2.text.subdued()}>{session()!.location.workspaceID}</text>
|
<text fg={themeV2.text.subdued}>{session()!.location.workspaceID}</text>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
</pluginRuntime.Slot>
|
</pluginRuntime.Slot>
|
||||||
|
|
|
||||||
|
|
@ -61,18 +61,18 @@ export function SubagentFooter() {
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
{...SplitBorder}
|
{...SplitBorder}
|
||||||
border={["left"]}
|
border={["left"]}
|
||||||
borderColor={themeV2.border()}
|
borderColor={themeV2.border.default}
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
>
|
>
|
||||||
<box flexDirection="row" justifyContent="space-between" gap={1}>
|
<box flexDirection="row" justifyContent="space-between" gap={1}>
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
<b>{subagentInfo()}</b>
|
<b>{subagentInfo()}</b>
|
||||||
</text>
|
</text>
|
||||||
<Show when={usage()}>
|
<Show when={usage()}>
|
||||||
{(item) => (
|
{(item) => (
|
||||||
<text fg={themeV2.text.subdued()} wrapMode="none">
|
<text fg={themeV2.text.subdued} wrapMode="none">
|
||||||
{[item().context, item().cost].filter(Boolean).join(" · ")}
|
{[item().context, item().cost].filter(Boolean).join(" · ")}
|
||||||
</text>
|
</text>
|
||||||
)}
|
)}
|
||||||
|
|
@ -83,30 +83,36 @@ export function SubagentFooter() {
|
||||||
onMouseOver={() => setHover("parent")}
|
onMouseOver={() => setHover("parent")}
|
||||||
onMouseOut={() => setHover(null)}
|
onMouseOut={() => setHover(null)}
|
||||||
onMouseUp={() => keymap.dispatch("session.parent")}
|
onMouseUp={() => keymap.dispatch("session.parent")}
|
||||||
backgroundColor={hover() === "parent" ? themeV2.background.action("hovered") : themeV2.background()}
|
backgroundColor={
|
||||||
|
hover() === "parent" ? themeV2.background.action.primary.hovered : themeV2.background.default
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
Parent <span style={{ fg: themeV2.text.subdued() }}>{shortcuts.get("session.parent")}</span>
|
Parent <span style={{ fg: themeV2.text.subdued }}>{shortcuts.get("session.parent")}</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box
|
||||||
onMouseOver={() => setHover("prev")}
|
onMouseOver={() => setHover("prev")}
|
||||||
onMouseOut={() => setHover(null)}
|
onMouseOut={() => setHover(null)}
|
||||||
onMouseUp={() => keymap.dispatch("session.child.previous")}
|
onMouseUp={() => keymap.dispatch("session.child.previous")}
|
||||||
backgroundColor={hover() === "prev" ? themeV2.background.action("hovered") : themeV2.background()}
|
backgroundColor={
|
||||||
|
hover() === "prev" ? themeV2.background.action.primary.hovered : themeV2.background.default
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
Prev <span style={{ fg: themeV2.text.subdued() }}>{shortcuts.get("session.child.previous")}</span>
|
Prev <span style={{ fg: themeV2.text.subdued }}>{shortcuts.get("session.child.previous")}</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box
|
||||||
onMouseOver={() => setHover("next")}
|
onMouseOver={() => setHover("next")}
|
||||||
onMouseOut={() => setHover(null)}
|
onMouseOut={() => setHover(null)}
|
||||||
onMouseUp={() => keymap.dispatch("session.child.next")}
|
onMouseUp={() => keymap.dispatch("session.child.next")}
|
||||||
backgroundColor={hover() === "next" ? themeV2.background.action("hovered") : themeV2.background()}
|
backgroundColor={
|
||||||
|
hover() === "next" ? themeV2.background.action.primary.hovered : themeV2.background.default
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
Next <span style={{ fg: themeV2.text.subdued() }}>{shortcuts.get("session.child.next")}</span>
|
Next <span style={{ fg: themeV2.text.subdued }}>{shortcuts.get("session.child.next")}</span>
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -1,140 +1,40 @@
|
||||||
import type { RGBA } from "@opentui/core"
|
import type { RGBA } from "@opentui/core"
|
||||||
import type { Accessor } from "solid-js"
|
import type { Accessor } from "solid-js"
|
||||||
import type { ActionVariant, Mode, ResolvedActionState, ResolvedThemeView } from "./index"
|
import type { Mode, ResolvedThemeView } from "./index"
|
||||||
import { ActionState, HueStep } from "./schema"
|
|
||||||
|
|
||||||
type StateFlags = Partial<Record<ActionState, boolean>>
|
|
||||||
|
|
||||||
export function createComponentTheme(current: Accessor<ResolvedThemeView>, mode: Accessor<Mode>) {
|
export function createComponentTheme(current: Accessor<ResolvedThemeView>, mode: Accessor<Mode>) {
|
||||||
const textAction = actions((variant, state) => current().text.action[variant][state])
|
|
||||||
const backgroundAction = actions((variant, state) => current().background.action[variant][state])
|
|
||||||
const textFormfield = formfield((state) => current().text.formfield[state])
|
|
||||||
const backgroundFormfield = formfield((state) => current().background.formfield[state])
|
|
||||||
const hue = {
|
|
||||||
gray: (step: HueStep) => current().hue.gray[step],
|
|
||||||
red: (step: HueStep) => current().hue.red[step],
|
|
||||||
orange: (step: HueStep) => current().hue.orange[step],
|
|
||||||
yellow: (step: HueStep) => current().hue.yellow[step],
|
|
||||||
green: (step: HueStep) => current().hue.green[step],
|
|
||||||
cyan: (step: HueStep) => current().hue.cyan[step],
|
|
||||||
blue: (step: HueStep) => current().hue.blue[step],
|
|
||||||
purple: (step: HueStep) => current().hue.purple[step],
|
|
||||||
accent: (step: HueStep) => current().hue.accent[step],
|
|
||||||
interactive: (step: HueStep) => current().hue.interactive[step],
|
|
||||||
neutral: (step: HueStep) => current().hue.neutral[step],
|
|
||||||
}
|
|
||||||
const text = Object.assign(() => current().text.default, {
|
|
||||||
subdued: () => current().text.subdued,
|
|
||||||
action: textAction,
|
|
||||||
formfield: textFormfield,
|
|
||||||
feedback: {
|
|
||||||
error: feedbackText("error"),
|
|
||||||
warning: feedbackText("warning"),
|
|
||||||
success: feedbackText("success"),
|
|
||||||
info: feedbackText("info"),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const background = Object.assign(() => current().background.default, {
|
|
||||||
surface: {
|
|
||||||
offset: () => current().background.surface.offset,
|
|
||||||
overlay: () => current().background.surface.overlay,
|
|
||||||
},
|
|
||||||
action: backgroundAction,
|
|
||||||
formfield: backgroundFormfield,
|
|
||||||
feedback: {
|
|
||||||
error: () => current().background.feedback.error.default,
|
|
||||||
warning: () => current().background.feedback.warning.default,
|
|
||||||
success: () => current().background.feedback.success.default,
|
|
||||||
info: () => current().background.feedback.info.default,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const markdown = Object.assign(() => current().markdown.text, {
|
|
||||||
heading: () => current().markdown.heading,
|
|
||||||
link: () => current().markdown.link,
|
|
||||||
linkText: () => current().markdown.linkText,
|
|
||||||
code: () => current().markdown.code,
|
|
||||||
blockQuote: () => current().markdown.blockQuote,
|
|
||||||
emphasis: () => current().markdown.emphasis,
|
|
||||||
strong: () => current().markdown.strong,
|
|
||||||
horizontalRule: () => current().markdown.horizontalRule,
|
|
||||||
listItem: () => current().markdown.listItem,
|
|
||||||
listEnumeration: () => current().markdown.listEnumeration,
|
|
||||||
image: () => current().markdown.image,
|
|
||||||
imageText: () => current().markdown.imageText,
|
|
||||||
codeBlock: () => current().markdown.codeBlock,
|
|
||||||
})
|
|
||||||
|
|
||||||
function feedbackText(kind: "error" | "warning" | "success" | "info") {
|
|
||||||
return Object.assign(() => current().text.feedback[kind].default, {
|
|
||||||
subdued: () => current().text.feedback[kind].subdued,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hue,
|
get hue() {
|
||||||
categorical: (step: HueStep) => current().categorical.map((scale) => scale[step]),
|
return current().hue
|
||||||
|
},
|
||||||
|
get categorical() {
|
||||||
|
return current().categorical
|
||||||
|
},
|
||||||
|
get text() {
|
||||||
|
return current().text
|
||||||
|
},
|
||||||
|
get background() {
|
||||||
|
return current().background
|
||||||
|
},
|
||||||
|
get border() {
|
||||||
|
return current().border
|
||||||
|
},
|
||||||
|
get scrollbar() {
|
||||||
|
return current().scrollbar
|
||||||
|
},
|
||||||
|
get diff() {
|
||||||
|
return current().diff
|
||||||
|
},
|
||||||
|
get syntax() {
|
||||||
|
return current().syntax
|
||||||
|
},
|
||||||
|
get markdown() {
|
||||||
|
return current().markdown
|
||||||
|
},
|
||||||
source: (color: RGBA) => current().source(color),
|
source: (color: RGBA) => current().source(color),
|
||||||
increase: (color: RGBA, amount = 1) => current().increase(color, amount),
|
increase: (color: RGBA, amount = 1) => current().increase(color, amount),
|
||||||
decrease: (color: RGBA, amount = 1) => current().decrease(color, amount),
|
decrease: (color: RGBA, amount = 1) => current().decrease(color, amount),
|
||||||
raise: (color: RGBA) => (mode() === "light" ? current().increase(color) : current().decrease(color)),
|
raise: (color: RGBA) => (mode() === "light" ? current().increase(color) : current().decrease(color)),
|
||||||
text,
|
|
||||||
background,
|
|
||||||
border: () => current().border.default,
|
|
||||||
scrollbar: () => current().scrollbar.default,
|
|
||||||
diff: {
|
|
||||||
text: {
|
|
||||||
added: () => current().diff.text.added,
|
|
||||||
removed: () => current().diff.text.removed,
|
|
||||||
context: () => current().diff.text.context,
|
|
||||||
hunkHeader: () => current().diff.text.hunkHeader,
|
|
||||||
},
|
|
||||||
background: {
|
|
||||||
added: () => current().diff.background.added,
|
|
||||||
removed: () => current().diff.background.removed,
|
|
||||||
context: () => current().diff.background.context,
|
|
||||||
},
|
|
||||||
highlight: {
|
|
||||||
added: () => current().diff.highlight.added,
|
|
||||||
removed: () => current().diff.highlight.removed,
|
|
||||||
},
|
|
||||||
lineNumber: {
|
|
||||||
text: () => current().diff.lineNumber.text,
|
|
||||||
background: {
|
|
||||||
added: () => current().diff.lineNumber.background.added,
|
|
||||||
removed: () => current().diff.lineNumber.background.removed,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
syntax: {
|
|
||||||
comment: () => current().syntax.comment,
|
|
||||||
keyword: () => current().syntax.keyword,
|
|
||||||
function: () => current().syntax.function,
|
|
||||||
variable: () => current().syntax.variable,
|
|
||||||
string: () => current().syntax.string,
|
|
||||||
number: () => current().syntax.number,
|
|
||||||
type: () => current().syntax.type,
|
|
||||||
operator: () => current().syntax.operator,
|
|
||||||
punctuation: () => current().syntax.punctuation,
|
|
||||||
},
|
|
||||||
markdown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function actions(get: (variant: ActionVariant, state: ResolvedActionState) => RGBA) {
|
|
||||||
const primary = stateful((state) => get("primary", state))
|
|
||||||
return Object.assign(primary, {
|
|
||||||
destructive: stateful((state) => get("destructive", state)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function formfield(get: (state: ResolvedActionState) => RGBA) {
|
|
||||||
return stateful(get)
|
|
||||||
}
|
|
||||||
|
|
||||||
function stateful(get: (state: ResolvedActionState) => RGBA) {
|
|
||||||
return (states: ActionState | "default" | StateFlags = "default") => {
|
|
||||||
if (typeof states === "string") return get(states)
|
|
||||||
return get(ActionState.literals.find((state) => states[state]) ?? "default")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,27 +30,27 @@ export function DialogAlert(props: DialogAlertProps) {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
{props.title}
|
{props.title}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box paddingBottom={1}>
|
<box paddingBottom={1}>
|
||||||
<text fg={themeV2.text.subdued()}>{props.message}</text>
|
<text fg={themeV2.text.subdued}>{props.message}</text>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" justifyContent="flex-end" paddingBottom={1}>
|
<box flexDirection="row" justifyContent="flex-end" paddingBottom={1}>
|
||||||
<box
|
<box
|
||||||
paddingLeft={3}
|
paddingLeft={3}
|
||||||
paddingRight={3}
|
paddingRight={3}
|
||||||
backgroundColor={themeV2.background.action("focused")}
|
backgroundColor={themeV2.background.action.primary.focused}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
props.onConfirm?.()
|
props.onConfirm?.()
|
||||||
dialog.clear()
|
dialog.clear()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.action("focused")}>ok</text>
|
<text fg={themeV2.text.action.primary.focused}>ok</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -57,15 +57,15 @@ export function DialogConfirm(props: DialogConfirmProps) {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
{props.title}
|
{props.title}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box paddingBottom={1}>
|
<box paddingBottom={1}>
|
||||||
<text fg={themeV2.text.subdued()}>{props.message}</text>
|
<text fg={themeV2.text.subdued}>{props.message}</text>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" justifyContent="flex-end" paddingBottom={1}>
|
<box flexDirection="row" justifyContent="flex-end" paddingBottom={1}>
|
||||||
<For each={["cancel", "confirm"] as const}>
|
<For each={["cancel", "confirm"] as const}>
|
||||||
|
|
@ -73,14 +73,14 @@ export function DialogConfirm(props: DialogConfirmProps) {
|
||||||
<box
|
<box
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
backgroundColor={key === store.active ? themeV2.background.action("focused") : undefined}
|
backgroundColor={key === store.active ? themeV2.background.action.primary.focused : undefined}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
if (key === "confirm") props.onConfirm?.()
|
if (key === "confirm") props.onConfirm?.()
|
||||||
if (key === "cancel") props.onCancel?.()
|
if (key === "cancel") props.onCancel?.()
|
||||||
dialog.clear()
|
dialog.clear()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<text fg={key === store.active ? themeV2.text.action("focused") : themeV2.text.subdued()}>
|
<text fg={key === store.active ? themeV2.text.action.primary.focused : themeV2.text.subdued}>
|
||||||
{Locale.titlecase(key === "cancel" ? (props.label ?? key) : key)}
|
{Locale.titlecase(key === "cancel" ? (props.label ?? key) : key)}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -76,32 +76,38 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
Export session
|
Export session
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<text fg={themeV2.text()}>Export as:</text>
|
<text fg={themeV2.text.default}>Export as:</text>
|
||||||
<box flexDirection="row" gap={1}>
|
<box flexDirection="row" gap={1}>
|
||||||
<For each={["markdown", "json"] as const}>
|
<For each={["markdown", "json"] as const}>
|
||||||
{(format) => (
|
{(format) => (
|
||||||
<box
|
<box
|
||||||
paddingLeft={1}
|
paddingLeft={1}
|
||||||
paddingRight={1}
|
paddingRight={1}
|
||||||
backgroundColor={themeV2.background.formfield({
|
backgroundColor={
|
||||||
focused: store.active === format,
|
store.active === format
|
||||||
selected: store.format === format,
|
? themeV2.background.formfield.focused
|
||||||
})}
|
: store.format === format
|
||||||
|
? themeV2.background.formfield.selected
|
||||||
|
: themeV2.background.formfield.default
|
||||||
|
}
|
||||||
onMouseUp={() => selectFormat(format)}
|
onMouseUp={() => selectFormat(format)}
|
||||||
>
|
>
|
||||||
<text
|
<text
|
||||||
fg={themeV2.text.formfield({
|
fg={
|
||||||
focused: store.active === format,
|
store.active === format
|
||||||
selected: store.format === format,
|
? themeV2.text.formfield.focused
|
||||||
})}
|
: store.format === format
|
||||||
|
? themeV2.text.formfield.selected
|
||||||
|
: themeV2.text.formfield.default
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{store.format === format ? "◉" : "○"} {format === "markdown" ? "Markdown" : "JSON"}
|
{store.format === format ? "◉" : "○"} {format === "markdown" ? "Markdown" : "JSON"}
|
||||||
</text>
|
</text>
|
||||||
|
|
@ -114,19 +120,38 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
||||||
<box
|
<box
|
||||||
flexDirection="row"
|
flexDirection="row"
|
||||||
gap={1}
|
gap={1}
|
||||||
backgroundColor={themeV2.background.formfield({
|
backgroundColor={
|
||||||
focused: store.active === "thinking",
|
store.active === "thinking"
|
||||||
selected: store.thinking,
|
? themeV2.background.formfield.focused
|
||||||
})}
|
: store.thinking
|
||||||
|
? themeV2.background.formfield.selected
|
||||||
|
: themeV2.background.formfield.default
|
||||||
|
}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
setStore("active", "thinking")
|
setStore("active", "thinking")
|
||||||
setStore("thinking", !store.thinking)
|
setStore("thinking", !store.thinking)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.formfield({ focused: store.active === "thinking", selected: store.thinking })}>
|
<text
|
||||||
|
fg={
|
||||||
|
store.active === "thinking"
|
||||||
|
? themeV2.text.formfield.focused
|
||||||
|
: store.thinking
|
||||||
|
? themeV2.text.formfield.selected
|
||||||
|
: themeV2.text.formfield.default
|
||||||
|
}
|
||||||
|
>
|
||||||
{store.thinking ? "[x]" : "[ ]"}
|
{store.thinking ? "[x]" : "[ ]"}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.formfield({ focused: store.active === "thinking", selected: store.thinking })}>
|
<text
|
||||||
|
fg={
|
||||||
|
store.active === "thinking"
|
||||||
|
? themeV2.text.formfield.focused
|
||||||
|
: store.thinking
|
||||||
|
? themeV2.text.formfield.selected
|
||||||
|
: themeV2.text.formfield.default
|
||||||
|
}
|
||||||
|
>
|
||||||
Include thinking
|
Include thinking
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -135,19 +160,38 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
||||||
<box
|
<box
|
||||||
flexDirection="row"
|
flexDirection="row"
|
||||||
gap={1}
|
gap={1}
|
||||||
backgroundColor={themeV2.background.formfield({
|
backgroundColor={
|
||||||
focused: store.active === "debug",
|
store.active === "debug"
|
||||||
selected: store.debug,
|
? themeV2.background.formfield.focused
|
||||||
})}
|
: store.debug
|
||||||
|
? themeV2.background.formfield.selected
|
||||||
|
: themeV2.background.formfield.default
|
||||||
|
}
|
||||||
onMouseUp={() => {
|
onMouseUp={() => {
|
||||||
setStore("active", "debug")
|
setStore("active", "debug")
|
||||||
setStore("debug", !store.debug)
|
setStore("debug", !store.debug)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.formfield({ focused: store.active === "debug", selected: store.debug })}>
|
<text
|
||||||
|
fg={
|
||||||
|
store.active === "debug"
|
||||||
|
? themeV2.text.formfield.focused
|
||||||
|
: store.debug
|
||||||
|
? themeV2.text.formfield.selected
|
||||||
|
: themeV2.text.formfield.default
|
||||||
|
}
|
||||||
|
>
|
||||||
{store.debug ? "[x]" : "[ ]"}
|
{store.debug ? "[x]" : "[ ]"}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.formfield({ focused: store.active === "debug", selected: store.debug })}>
|
<text
|
||||||
|
fg={
|
||||||
|
store.active === "debug"
|
||||||
|
? themeV2.text.formfield.focused
|
||||||
|
: store.debug
|
||||||
|
? themeV2.text.formfield.selected
|
||||||
|
: themeV2.text.formfield.default
|
||||||
|
}
|
||||||
|
>
|
||||||
Events (debug)
|
Events (debug)
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -156,18 +200,26 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
||||||
<box
|
<box
|
||||||
paddingLeft={4}
|
paddingLeft={4}
|
||||||
paddingRight={4}
|
paddingRight={4}
|
||||||
backgroundColor={overlayTheme.background()}
|
backgroundColor={overlayTheme.background.default}
|
||||||
onMouseUp={() => confirm("copy")}
|
onMouseUp={() => confirm("copy")}
|
||||||
>
|
>
|
||||||
<text fg={overlayTheme.text()}>Copy</text>
|
<text fg={overlayTheme.text.default}>Copy</text>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box
|
||||||
paddingLeft={4}
|
paddingLeft={4}
|
||||||
paddingRight={4}
|
paddingRight={4}
|
||||||
backgroundColor={themeV2.background.action({ focused: store.active === "export" })}
|
backgroundColor={
|
||||||
|
store.active === "export"
|
||||||
|
? themeV2.background.action.primary.focused
|
||||||
|
: themeV2.background.action.primary.default
|
||||||
|
}
|
||||||
onMouseUp={() => confirm("export")}
|
onMouseUp={() => confirm("export")}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.action({ focused: store.active === "export" })}>Export</text>
|
<text
|
||||||
|
fg={store.active === "export" ? themeV2.text.action.primary.focused : themeV2.text.action.primary.default}
|
||||||
|
>
|
||||||
|
Export
|
||||||
|
</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -27,19 +27,24 @@ export function DialogExportResult(props: { path: string; onClose?: () => void }
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
Session exported
|
Session exported
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={close}>
|
<text fg={themeV2.text.subdued} onMouseUp={close}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box>
|
<box>
|
||||||
<text fg={themeV2.text()}>{props.path}</text>
|
<text fg={themeV2.text.default}>{props.path}</text>
|
||||||
</box>
|
</box>
|
||||||
<box flexDirection="row" justifyContent="flex-end" gap={1} paddingBottom={1}>
|
<box flexDirection="row" justifyContent="flex-end" gap={1} paddingBottom={1}>
|
||||||
<box paddingLeft={3} paddingRight={3} backgroundColor={themeV2.background.action("focused")} onMouseUp={close}>
|
<box
|
||||||
<text fg={themeV2.text.action("focused")}>Close</text>
|
paddingLeft={3}
|
||||||
|
paddingRight={3}
|
||||||
|
backgroundColor={themeV2.background.action.primary.focused}
|
||||||
|
onMouseUp={close}
|
||||||
|
>
|
||||||
|
<text fg={themeV2.text.action.primary.focused}>Close</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,15 @@ export function DialogHelp() {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
Help
|
Help
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc/enter
|
esc/enter
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
<box paddingBottom={1}>
|
<box paddingBottom={1}>
|
||||||
<text fg={themeV2.text.subdued()}>
|
<text fg={themeV2.text.subdued}>
|
||||||
Press {shortcuts.get("command.palette.show")} to see all available actions and commands in any context.
|
Press {shortcuts.get("command.palette.show")} to see all available actions and commands in any context.
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -35,10 +35,10 @@ export function DialogHelp() {
|
||||||
<box
|
<box
|
||||||
paddingLeft={3}
|
paddingLeft={3}
|
||||||
paddingRight={3}
|
paddingRight={3}
|
||||||
backgroundColor={themeV2.background.action("focused")}
|
backgroundColor={themeV2.background.action.primary.focused}
|
||||||
onMouseUp={() => dialog.clear()}
|
onMouseUp={() => dialog.clear()}
|
||||||
>
|
>
|
||||||
<text fg={themeV2.text.action("focused")}>ok</text>
|
<text fg={themeV2.text.action.primary.focused}>ok</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,10 @@ export function DialogPrompt(props: DialogPromptProps) {
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
<text attributes={TextAttributes.BOLD} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} fg={themeV2.text.default}>
|
||||||
{props.title}
|
{props.title}
|
||||||
</text>
|
</text>
|
||||||
<text fg={themeV2.text.subdued()} onMouseUp={() => dialog.clear()}>
|
<text fg={themeV2.text.subdued} onMouseUp={() => dialog.clear()}>
|
||||||
esc
|
esc
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
@ -91,20 +91,20 @@ export function DialogPrompt(props: DialogPromptProps) {
|
||||||
}}
|
}}
|
||||||
initialValue={props.value}
|
initialValue={props.value}
|
||||||
placeholder={props.placeholder ?? "Enter text"}
|
placeholder={props.placeholder ?? "Enter text"}
|
||||||
placeholderColor={themeV2.text.subdued()}
|
placeholderColor={themeV2.text.subdued}
|
||||||
textColor={themeV2.text.formfield({ disabled: props.busy })}
|
textColor={props.busy ? themeV2.text.formfield.disabled : themeV2.text.formfield.default}
|
||||||
focusedTextColor={themeV2.text.formfield({ disabled: props.busy })}
|
focusedTextColor={props.busy ? themeV2.text.formfield.disabled : themeV2.text.formfield.default}
|
||||||
cursorColor={props.busy ? themeV2.background.formfield("disabled") : themeV2.text()}
|
cursorColor={props.busy ? themeV2.background.formfield.disabled : themeV2.text.default}
|
||||||
/>
|
/>
|
||||||
<Show when={props.busy}>
|
<Show when={props.busy}>
|
||||||
<Spinner color={themeV2.text.subdued()}>{props.busyText ?? "Working..."}</Spinner>
|
<Spinner color={themeV2.text.subdued}>{props.busyText ?? "Working..."}</Spinner>
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
<box paddingBottom={1} gap={1} flexDirection="row">
|
<box paddingBottom={1} gap={1} flexDirection="row">
|
||||||
<Show when={!props.busy} fallback={<text fg={themeV2.text.subdued()}>processing...</text>}>
|
<Show when={!props.busy} fallback={<text fg={themeV2.text.subdued}>processing...</text>}>
|
||||||
<Show when={shortcuts.get("dialog.prompt.submit")}>
|
<Show when={shortcuts.get("dialog.prompt.submit")}>
|
||||||
<text fg={themeV2.text()}>
|
<text fg={themeV2.text.default}>
|
||||||
{shortcuts.get("dialog.prompt.submit")} <span style={{ fg: themeV2.text.subdued() }}>submit</span>
|
{shortcuts.get("dialog.prompt.submit")} <span style={{ fg: themeV2.text.subdued }}>submit</span>
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ export function Dialog(
|
||||||
}}
|
}}
|
||||||
width={width()}
|
width={width()}
|
||||||
maxWidth={dimensions().width - 2}
|
maxWidth={dimensions().width - 2}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
|
||||||
|
|
@ -31,17 +31,17 @@ export function Toast() {
|
||||||
paddingRight={2}
|
paddingRight={2}
|
||||||
paddingTop={1}
|
paddingTop={1}
|
||||||
paddingBottom={1}
|
paddingBottom={1}
|
||||||
backgroundColor={themeV2.background()}
|
backgroundColor={themeV2.background.default}
|
||||||
borderColor={themeV2.text.feedback[current().variant]()}
|
borderColor={themeV2.text.feedback[current().variant].default}
|
||||||
border={["left", "right"]}
|
border={["left", "right"]}
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
customBorderChars={SplitBorder.customBorderChars}
|
||||||
>
|
>
|
||||||
<Show when={current().title}>
|
<Show when={current().title}>
|
||||||
<text attributes={TextAttributes.BOLD} marginBottom={1} fg={themeV2.text()}>
|
<text attributes={TextAttributes.BOLD} marginBottom={1} fg={themeV2.text.default}>
|
||||||
{current().title}
|
{current().title}
|
||||||
</text>
|
</text>
|
||||||
</Show>
|
</Show>
|
||||||
<text fg={themeV2.text()} wrapMode="word" width="100%">
|
<text fg={themeV2.text.default} wrapMode="word" width="100%">
|
||||||
{current().message}
|
{current().message}
|
||||||
</text>
|
</text>
|
||||||
</box>
|
</box>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { resolveTheme } from "../../../src/theme/v2/resolve"
|
||||||
import { selectTheme } from "../../../src/theme/v2/select"
|
import { selectTheme } from "../../../src/theme/v2/select"
|
||||||
import type { ContextKey } from "../../../src/theme/v2"
|
import type { ContextKey } from "../../../src/theme/v2"
|
||||||
|
|
||||||
test("provides reactive property, variant, state, and context accessors", () => {
|
test("provides reactive properties, states, contexts, and color operations", () => {
|
||||||
const [resolved, setResolved] = createSignal(resolveTheme(selectTheme(DEFAULT_THEME, "light")))
|
const [resolved, setResolved] = createSignal(resolveTheme(selectTheme(DEFAULT_THEME, "light")))
|
||||||
const [mode, setMode] = createSignal<"light" | "dark">("light")
|
const [mode, setMode] = createSignal<"light" | "dark">("light")
|
||||||
const [context, setContext] = createSignal<ContextKey>()
|
const [context, setContext] = createSignal<ContextKey>()
|
||||||
|
|
@ -16,69 +16,57 @@ test("provides reactive property, variant, state, and context accessors", () =>
|
||||||
return key ? (resolved().contexts[key] ?? resolved()) : resolved()
|
return key ? (resolved().contexts[key] ?? resolved()) : resolved()
|
||||||
}, mode)
|
}, mode)
|
||||||
|
|
||||||
expect(theme.text()).toBe(resolved().text.default)
|
expect(theme.text.default).toBe(resolved().text.default)
|
||||||
expect(theme.hue.accent(500)).toBe(resolved().hue.accent[500])
|
expect(theme.hue.accent[500]).toBe(resolved().hue.accent[500])
|
||||||
expect(theme.hue.interactive(500)).toBe(resolved().hue.interactive[500])
|
expect(theme.hue.interactive[500]).toBe(resolved().hue.interactive[500])
|
||||||
expect(theme.hue.gray(200)).toBe(resolved().hue.gray[200])
|
expect(theme.hue.gray[200]).toBe(resolved().hue.gray[200])
|
||||||
expect(theme.categorical(500)).toEqual(resolved().categorical.map((scale) => scale[500]))
|
expect(theme.categorical.map((scale) => scale[500])).toEqual(resolved().categorical.map((scale) => scale[500]))
|
||||||
expect(theme.increase(theme.background.surface.offset(), 1)).toBe(resolved().hue.neutral[400])
|
expect(theme.increase(theme.background.surface.offset, 1)).toBe(resolved().hue.neutral[400])
|
||||||
expect(theme.raise(theme.background.surface.offset())).toBe(resolved().hue.neutral[400])
|
expect(theme.raise(theme.background.surface.offset)).toBe(resolved().hue.neutral[400])
|
||||||
expect(theme.decrease(theme.hue.red(300), 2)).toBe(resolved().hue.red[100])
|
expect(theme.decrease(theme.hue.red[300], 2)).toBe(resolved().hue.red[100])
|
||||||
expect(theme.increase(theme.hue.red(900), 3)).toBe(resolved().hue.red[900])
|
expect(theme.increase(theme.hue.red[900], 3)).toBe(resolved().hue.red[900])
|
||||||
expect(theme.decrease(theme.hue.red(100), 3)).toBe(resolved().hue.red[100])
|
expect(theme.decrease(theme.hue.red[100], 3)).toBe(resolved().hue.red[100])
|
||||||
expect(theme.source(theme.background.surface.offset())).toEqual({ hue: "neutral", step: 300 })
|
expect(theme.source(theme.background.surface.offset)).toEqual({ hue: "neutral", step: 300 })
|
||||||
const equivalent = RGBA.fromInts(...resolved().hue.green[500].toInts())
|
const equivalent = RGBA.fromInts(...resolved().hue.green[500].toInts())
|
||||||
expect(theme.source(equivalent)).toBeUndefined()
|
expect(theme.source(equivalent)).toBeUndefined()
|
||||||
expect(theme.increase(equivalent, 1)).toBe(equivalent)
|
expect(theme.increase(equivalent, 1)).toBe(equivalent)
|
||||||
const unmatched = RGBA.fromInts(1, 2, 3)
|
const unmatched = RGBA.fromInts(1, 2, 3)
|
||||||
expect(theme.increase(unmatched, 1)).toBe(unmatched)
|
expect(theme.increase(unmatched, 1)).toBe(unmatched)
|
||||||
expect(theme.text.subdued()).toBe(resolved().text.subdued)
|
expect(theme.text.subdued).toBe(resolved().text.subdued)
|
||||||
expect(theme.text.action()).toBe(resolved().text.action.primary.default)
|
expect(theme.text.action.primary.default).toBe(resolved().text.action.primary.default)
|
||||||
expect(theme.text.action("hovered")).toBe(resolved().text.action.primary.hovered)
|
expect(theme.text.action.primary.hovered).toBe(resolved().text.action.primary.hovered)
|
||||||
expect(theme.text.action("pressed")).toBe(resolved().text.action.primary.pressed)
|
expect(theme.text.action.primary.pressed).toBe(resolved().text.action.primary.pressed)
|
||||||
expect(theme.text.action("selected")).toBe(resolved().text.action.primary.selected)
|
expect(theme.text.action.primary.selected).toBe(resolved().text.action.primary.selected)
|
||||||
expect(theme.background.action("selected")).toBe(resolved().background.action.primary.selected)
|
expect(theme.background.action.primary.selected).toBe(resolved().background.action.primary.selected)
|
||||||
expect(theme.background.action("hovered")).toBe(resolved().background.action.primary.hovered)
|
expect(theme.background.action.primary.hovered).toBe(resolved().background.action.primary.hovered)
|
||||||
expect(theme.background.action({ selected: true })).toBe(resolved().background.action.primary.selected)
|
expect(theme.background.action.primary.focused).toBe(resolved().background.action.primary.focused)
|
||||||
expect(theme.background.action({ selected: true, hovered: true })).toBe(resolved().background.action.primary.selected)
|
expect(theme.background.action.primary.pressed).toBe(resolved().background.action.primary.pressed)
|
||||||
expect(theme.background.action({ focused: true, selected: true })).toBe(resolved().background.action.primary.focused)
|
expect(theme.background.action.primary.disabled).toBe(resolved().background.action.primary.disabled)
|
||||||
expect(theme.background.action({ pressed: true, focused: true, selected: true })).toBe(
|
expect(theme.background.action.primary.default).toBe(resolved().background.action.primary.default)
|
||||||
resolved().background.action.primary.pressed,
|
expect(theme.background.action.destructive.disabled).toBe(resolved().background.action.destructive.disabled)
|
||||||
)
|
expect(theme.background.formfield.hovered).toBe(resolved().background.formfield.hovered)
|
||||||
expect(theme.background.action({ disabled: true, pressed: true, focused: true, selected: true, hovered: true })).toBe(
|
expect(theme.background.formfield.selected).toBe(resolved().background.formfield.selected)
|
||||||
resolved().background.action.primary.disabled,
|
expect(theme.background.formfield.focused).toBe(resolved().background.formfield.focused)
|
||||||
)
|
expect(theme.background.formfield.disabled).toBe(resolved().background.formfield.disabled)
|
||||||
expect(theme.background.action({ disabled: false, selected: false })).toBe(
|
expect(theme.background.surface.offset).toBe(resolved().background.surface.offset)
|
||||||
resolved().background.action.primary.default,
|
expect(theme.background.surface.overlay).toBe(resolved().background.surface.overlay)
|
||||||
)
|
expect(theme.scrollbar.default).toBe(resolved().scrollbar.default)
|
||||||
expect(theme.background.action.destructive("disabled")).toBe(resolved().background.action.destructive.disabled)
|
expect(theme.diff.text.added).toBe(resolved().diff.text.added)
|
||||||
expect(theme.background.formfield("hovered")).toBe(resolved().background.formfield.hovered)
|
|
||||||
expect(theme.background.formfield({ selected: true, hovered: true })).toBe(resolved().background.formfield.selected)
|
|
||||||
expect(theme.background.formfield({ focused: true, selected: true, hovered: true })).toBe(
|
|
||||||
resolved().background.formfield.focused,
|
|
||||||
)
|
|
||||||
expect(
|
|
||||||
theme.background.formfield({ disabled: true, pressed: true, focused: true, selected: true, hovered: true }),
|
|
||||||
).toBe(resolved().background.formfield.disabled)
|
|
||||||
expect(theme.background.surface.offset()).toBe(resolved().background.surface.offset)
|
|
||||||
expect(theme.background.surface.overlay()).toBe(resolved().background.surface.overlay)
|
|
||||||
expect(theme.scrollbar()).toBe(resolved().scrollbar.default)
|
|
||||||
expect(theme.diff.text.added()).toBe(resolved().diff.text.added)
|
|
||||||
|
|
||||||
setContext("@context:elevated")
|
setContext("@context:elevated")
|
||||||
expect(theme.categorical(500)).toEqual(resolved().categorical.map((scale) => scale[500]))
|
expect(theme.categorical.map((scale) => scale[500])).toEqual(resolved().categorical.map((scale) => scale[500]))
|
||||||
expect(theme.text()).toBe(resolved().contexts["@context:elevated"]!.text.default)
|
expect(theme.text.default).toBe(resolved().contexts["@context:elevated"]!.text.default)
|
||||||
expect(theme.background.action("focused")).toBe(
|
expect(theme.background.action.primary.focused).toBe(
|
||||||
resolved().contexts["@context:elevated"]!.background.action.primary.focused,
|
resolved().contexts["@context:elevated"]!.background.action.primary.focused,
|
||||||
)
|
)
|
||||||
expect(theme.background.action("hovered")).toBe(resolved().background.surface.overlay)
|
expect(theme.background.action.primary.hovered).toBe(resolved().background.surface.overlay)
|
||||||
expect(theme.background.formfield("selected")).toBe(
|
expect(theme.background.formfield.selected).toBe(
|
||||||
resolved().contexts["@context:elevated"]!.background.formfield.selected,
|
resolved().contexts["@context:elevated"]!.background.formfield.selected,
|
||||||
)
|
)
|
||||||
|
|
||||||
setResolved(resolveTheme(selectTheme(DEFAULT_THEME, "dark")))
|
setResolved(resolveTheme(selectTheme(DEFAULT_THEME, "dark")))
|
||||||
setMode("dark")
|
setMode("dark")
|
||||||
expect(theme.text()).toBe(resolved().contexts["@context:elevated"]!.text.default)
|
expect(theme.text.default).toBe(resolved().contexts["@context:elevated"]!.text.default)
|
||||||
expect(theme.decrease(theme.background.surface.offset(), 1)).toBe(resolved().hue.neutral[600])
|
expect(theme.decrease(theme.background.surface.offset, 1)).toBe(resolved().hue.neutral[600])
|
||||||
expect(theme.raise(theme.background.surface.offset())).toBe(resolved().hue.neutral[600])
|
expect(theme.raise(theme.background.surface.offset)).toBe(resolved().hue.neutral[600])
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue