mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-30 17:14:40 +08:00
refactor(vscode): replace thinking cycle button with popover dropdown
Replaces the single cycle button with a ThinkingSelector popover component matching the ModeSwitcher pattern. Lists all available variants plus a Default option to disable thinking.
This commit is contained in:
@@ -13,6 +13,7 @@ import { useLanguage } from "../../context/language"
|
||||
import { useVSCode } from "../../context/vscode"
|
||||
import { ModelSelector } from "./ModelSelector"
|
||||
import { ModeSwitcher } from "./ModeSwitcher"
|
||||
import { ThinkingSelector } from "./ThinkingSelector"
|
||||
import { useFileMention } from "../../hooks/useFileMention"
|
||||
import { useImageAttachments } from "../../hooks/useImageAttachments"
|
||||
import { fileName, dirName, buildHighlightSegments } from "./prompt-input-utils"
|
||||
@@ -314,18 +315,7 @@ export const PromptInput: Component = () => {
|
||||
<div class="prompt-input-hint-selectors">
|
||||
<ModeSwitcher />
|
||||
<ModelSelector />
|
||||
<Show when={session.variantList().length > 0}>
|
||||
<Tooltip value={language.t("command.model.variant.cycle")} placement="top">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="small"
|
||||
onClick={() => session.cycleVariant()}
|
||||
aria-label={language.t("command.model.variant.cycle")}
|
||||
>
|
||||
{session.currentVariant() ?? language.t("common.default")}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Show>
|
||||
<ThinkingSelector />
|
||||
</div>
|
||||
<div class="prompt-input-hint-actions">
|
||||
<Show
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* ThinkingSelector component
|
||||
* Popover-based dropdown for choosing a thinking effort variant.
|
||||
* Only rendered when the selected model supports reasoning variants.
|
||||
*/
|
||||
|
||||
import { Component, createSignal, For, Show } from "solid-js"
|
||||
import { Popover } from "@kilocode/kilo-ui/popover"
|
||||
import { Button } from "@kilocode/kilo-ui/button"
|
||||
import { useSession } from "../../context/session"
|
||||
import { useLanguage } from "../../context/language"
|
||||
|
||||
export const ThinkingSelector: Component = () => {
|
||||
const session = useSession()
|
||||
const language = useLanguage()
|
||||
const [open, setOpen] = createSignal(false)
|
||||
|
||||
const variants = () => session.variantList()
|
||||
const current = () => session.currentVariant()
|
||||
|
||||
function pick(value: string | undefined) {
|
||||
session.selectVariant(value)
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
const triggerLabel = () => {
|
||||
const v = current()
|
||||
return v ? v.charAt(0).toUpperCase() + v.slice(1) : language.t("common.default")
|
||||
}
|
||||
|
||||
return (
|
||||
<Show when={variants().length > 0}>
|
||||
<Popover
|
||||
placement="top-start"
|
||||
open={open()}
|
||||
onOpenChange={setOpen}
|
||||
triggerAs={Button}
|
||||
triggerProps={{ variant: "ghost", size: "small" }}
|
||||
trigger={
|
||||
<>
|
||||
<span class="thinking-selector-trigger-label">{triggerLabel()}</span>
|
||||
<svg width="10" height="10" viewBox="0 0 16 16" fill="currentColor" style={{ "flex-shrink": "0" }}>
|
||||
<path d="M8 4l4 5H4l4-5z" />
|
||||
</svg>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div class="thinking-selector-list" role="listbox">
|
||||
<div
|
||||
class={`thinking-selector-item${!current() ? " selected" : ""}`}
|
||||
role="option"
|
||||
aria-selected={!current()}
|
||||
onClick={() => pick(undefined)}
|
||||
>
|
||||
<span class="thinking-selector-item-name" style={{ "font-style": "italic" }}>
|
||||
{language.t("common.default")}
|
||||
</span>
|
||||
</div>
|
||||
<For each={variants()}>
|
||||
{(v) => (
|
||||
<div
|
||||
class={`thinking-selector-item${current() === v ? " selected" : ""}`}
|
||||
role="option"
|
||||
aria-selected={current() === v}
|
||||
onClick={() => pick(v)}
|
||||
>
|
||||
<span class="thinking-selector-item-name">{v.charAt(0).toUpperCase() + v.slice(1)}</span>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Popover>
|
||||
</Show>
|
||||
)
|
||||
}
|
||||
@@ -109,7 +109,7 @@ interface SessionContextValue {
|
||||
// Thinking variant for the selected model
|
||||
variantList: () => string[]
|
||||
currentVariant: () => string | undefined
|
||||
cycleVariant: () => void
|
||||
selectVariant: (value: string | undefined) => void
|
||||
|
||||
// Actions
|
||||
sendMessage: (text: string, providerID?: string, modelID?: string, files?: FileAttachment[]) => void
|
||||
@@ -296,21 +296,12 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const cycleVariant = () => {
|
||||
const selectVariant = (value: string | undefined) => {
|
||||
const sel = selected()
|
||||
if (!sel) return
|
||||
const list = variantList()
|
||||
if (list.length === 0) return
|
||||
const key = variantKey(sel)
|
||||
const current = store.variantSelections[key]
|
||||
const next = (() => {
|
||||
if (!current || !list.includes(current)) return list[0]
|
||||
const idx = list.indexOf(current)
|
||||
if (idx === list.length - 1) return undefined
|
||||
return list[idx + 1]
|
||||
})()
|
||||
setStore("variantSelections", key, next)
|
||||
vscode.postMessage({ type: "persistVariant", key, value: next })
|
||||
setStore("variantSelections", key, value)
|
||||
vscode.postMessage({ type: "persistVariant", key, value })
|
||||
}
|
||||
|
||||
// Load persisted variants from extension globalState
|
||||
@@ -926,7 +917,7 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
allParts,
|
||||
variantList,
|
||||
currentVariant,
|
||||
cycleVariant,
|
||||
selectVariant,
|
||||
sendMessage,
|
||||
abort,
|
||||
compact,
|
||||
|
||||
@@ -576,6 +576,42 @@
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Thinking Selector (uses kilo-ui Popover)
|
||||
============================================ */
|
||||
|
||||
.thinking-selector-trigger-label {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.thinking-selector-list {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.thinking-selector-item {
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.thinking-selector-item:hover {
|
||||
background: var(--surface-interactive-hover, var(--vscode-list-hoverBackground));
|
||||
}
|
||||
|
||||
.thinking-selector-item.selected {
|
||||
background: var(
|
||||
--surface-interactive-active,
|
||||
var(--vscode-list-activeSelectionBackground, var(--vscode-list-hoverBackground))
|
||||
);
|
||||
}
|
||||
|
||||
.thinking-selector-item-name {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Mode Switcher (uses kilo-ui Popover)
|
||||
============================================ */
|
||||
|
||||
Reference in New Issue
Block a user