fix(tui): simplify thinking toggle styling (#28487)
This commit is contained in:
@@ -4,6 +4,14 @@
|
|||||||
- Local `main` ref may not exist; use `dev` or `origin/dev` for diffs.
|
- Local `main` ref may not exist; use `dev` or `origin/dev` for diffs.
|
||||||
- Prefer automation: execute requested actions without confirmation unless blocked by missing info or safety/irreversibility.
|
- Prefer automation: execute requested actions without confirmation unless blocked by missing info or safety/irreversibility.
|
||||||
|
|
||||||
|
## Commits and PR Titles
|
||||||
|
|
||||||
|
Use conventional commit-style messages and PR titles: `type(scope): summary`.
|
||||||
|
|
||||||
|
Valid types are `feat`, `fix`, `docs`, `chore`, `refactor`, and `test`. Scopes are optional; use the affected package or area when helpful, e.g. `core`, `opencode`, `tui`, `app`, `desktop`, `sdk`, or `plugin`.
|
||||||
|
|
||||||
|
Examples: `fix(tui): simplify thinking toggle styling`, `docs: update contributing guide`, `chore(sdk): regenerate types`.
|
||||||
|
|
||||||
## Style Guide
|
## Style Guide
|
||||||
|
|
||||||
### General Principles
|
### General Principles
|
||||||
|
|||||||
@@ -411,12 +411,9 @@ function AssistantReasoning(props: {
|
|||||||
<Switch>
|
<Switch>
|
||||||
<Match when={!inMinimal() || expanded()}>
|
<Match when={!inMinimal() || expanded()}>
|
||||||
<box
|
<box
|
||||||
paddingLeft={2}
|
paddingLeft={3}
|
||||||
marginTop={1}
|
marginTop={1}
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
border={["left"]}
|
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
|
||||||
borderColor={theme.backgroundElement}
|
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
onMouseUp={toggle}
|
onMouseUp={toggle}
|
||||||
>
|
>
|
||||||
@@ -425,17 +422,20 @@ function AssistantReasoning(props: {
|
|||||||
drawUnstyledText={false}
|
drawUnstyledText={false}
|
||||||
streaming={true}
|
streaming={true}
|
||||||
syntaxStyle={props.subtleSyntax}
|
syntaxStyle={props.subtleSyntax}
|
||||||
content={(inMinimal() ? "▼ " : "") + "_Thinking:_ " + content()}
|
content={(inMinimal() ? "- " : "") + "_Thinking:_ " + content()}
|
||||||
conceal={true}
|
conceal={true}
|
||||||
fg={theme.textMuted}
|
fg={theme.textMuted}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={isDone()}>
|
<Match when={isDone()}>
|
||||||
<box paddingLeft={3} marginTop={1} flexShrink={0} onMouseUp={toggle}>
|
<box
|
||||||
<text fg={theme.textMuted} wrapMode="none">
|
paddingLeft={3}
|
||||||
{title() ? "▶ Thought: " + title() : "▶ Thought"}
|
marginTop={1}
|
||||||
</text>
|
flexShrink={0}
|
||||||
|
onMouseUp={toggle}
|
||||||
|
>
|
||||||
|
<CollapsedReasoningText title={title()} />
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
@@ -448,6 +448,16 @@ function AssistantReasoning(props: {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CollapsedReasoningText(props: { title: string | null }) {
|
||||||
|
const { theme } = useTheme()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<text fg={theme.warning} wrapMode="none">
|
||||||
|
<span style={{ fg: theme.warning, italic: true }}>{props.title ? "+ Thought · " + props.title : "+ Thought"}</span>
|
||||||
|
</text>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function AssistantTool(props: { part: SessionMessageAssistantTool; sessionID: string }) {
|
function AssistantTool(props: { part: SessionMessageAssistantTool; sessionID: string }) {
|
||||||
const input = createMemo(() => toolInputRecord(props.part.state.input))
|
const input = createMemo(() => toolInputRecord(props.part.state.input))
|
||||||
const toolprops = {
|
const toolprops = {
|
||||||
|
|||||||
@@ -1533,12 +1533,9 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass
|
|||||||
{/* Full markdown block: `show` mode, or `hide` after the user opens it. */}
|
{/* Full markdown block: `show` mode, or `hide` after the user opens it. */}
|
||||||
<box
|
<box
|
||||||
id={"text-" + props.part.id}
|
id={"text-" + props.part.id}
|
||||||
paddingLeft={2}
|
paddingLeft={3}
|
||||||
marginTop={1}
|
marginTop={1}
|
||||||
flexDirection="column"
|
flexDirection="column"
|
||||||
border={["left"]}
|
|
||||||
customBorderChars={SplitBorder.customBorderChars}
|
|
||||||
borderColor={theme.backgroundElement}
|
|
||||||
onMouseUp={toggle}
|
onMouseUp={toggle}
|
||||||
>
|
>
|
||||||
<code
|
<code
|
||||||
@@ -1546,26 +1543,24 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass
|
|||||||
drawUnstyledText={false}
|
drawUnstyledText={false}
|
||||||
streaming={true}
|
streaming={true}
|
||||||
syntaxStyle={subtleSyntax()}
|
syntaxStyle={subtleSyntax()}
|
||||||
content={(inMinimal() ? "▼ " : "") + (isDone() ? "_Thought:_ " : "_Thinking:_ ") + content()}
|
content={(inMinimal() ? "- " : "") + (isDone() ? "_Thought:_ " : "_Thinking:_ ") + content()}
|
||||||
conceal={ctx.conceal()}
|
conceal={ctx.conceal()}
|
||||||
fg={theme.textMuted}
|
fg={theme.textMuted}
|
||||||
/>
|
/>
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={isDone()}>
|
<Match when={isDone()}>
|
||||||
{/* Settled: ▶ at the start as the click-to-expand cue. */}
|
<box
|
||||||
<box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0} onMouseUp={toggle}>
|
id={"text-" + props.part.id}
|
||||||
<text fg={theme.textMuted} wrapMode="none">
|
paddingLeft={3}
|
||||||
{"▶ " +
|
marginTop={1}
|
||||||
(title()
|
flexShrink={0}
|
||||||
? "Thought: " + title() + " · " + Locale.duration(duration())
|
onMouseUp={toggle}
|
||||||
: "Thought for " + Locale.duration(duration()))}
|
>
|
||||||
</text>
|
<CollapsedReasoningText title={title()} duration={duration()} />
|
||||||
</box>
|
</box>
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
{/* Streaming: leading animated spinner, no disclosure arrow yet — it
|
|
||||||
snaps in once reasoning settles, signalling "done, click to expand". */}
|
|
||||||
<box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0} onMouseUp={toggle}>
|
<box id={"text-" + props.part.id} paddingLeft={3} marginTop={1} flexShrink={0} onMouseUp={toggle}>
|
||||||
<Spinner color={theme.textMuted}>{title() ? "Thinking: " + title() : "Thinking"}</Spinner>
|
<Spinner color={theme.textMuted}>{title() ? "Thinking: " + title() : "Thinking"}</Spinner>
|
||||||
</box>
|
</box>
|
||||||
@@ -1575,6 +1570,19 @@ function ReasoningPart(props: { last: boolean; part: ReasoningPart; message: Ass
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CollapsedReasoningText(props: { title: string | null; duration: number }) {
|
||||||
|
const { theme } = useTheme()
|
||||||
|
const duration = () => Locale.duration(props.duration)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<text fg={theme.warning} wrapMode="none">
|
||||||
|
<span style={{ fg: theme.warning, italic: true }}>
|
||||||
|
{props.title ? "+ Thought · " + props.title + " · " + duration() : "+ Thought · " + duration()}
|
||||||
|
</span>
|
||||||
|
</text>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function TextPart(props: { last: boolean; part: TextPart; message: AssistantMessage }) {
|
function TextPart(props: { last: boolean; part: TextPart; message: AssistantMessage }) {
|
||||||
const ctx = use()
|
const ctx = use()
|
||||||
const { theme, syntax } = useTheme()
|
const { theme, syntax } = useTheme()
|
||||||
|
|||||||
Reference in New Issue
Block a user