diff options
| author | Adam <[email protected]> | 2026-01-31 07:18:51 -0600 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-01-31 07:18:51 -0600 |
| commit | a552652fcc024752fcd43d9117282307d15c44d1 (patch) | |
| tree | 67631d8dd33f1b4db65ea6d2518c188faf1f066f /packages/app/src | |
| parent | 511c7abacaebb5e007139395078b6a848e5e9ea5 (diff) | |
| download | opencode-a552652fcc024752fcd43d9117282307d15c44d1.tar.gz opencode-a552652fcc024752fcd43d9117282307d15c44d1.zip | |
Revert "feat: Transitions, spacing, scroll fade, prompt area update (#11168)" (#11461)
Co-authored-by: adamelmore <[email protected]>
Diffstat (limited to 'packages/app/src')
| -rw-r--r-- | packages/app/src/components/dialog-select-model.tsx | 7 | ||||
| -rw-r--r-- | packages/app/src/components/prompt-input.tsx | 124 | ||||
| -rw-r--r-- | packages/app/src/components/session-context-usage.tsx | 6 | ||||
| -rw-r--r-- | packages/app/src/components/settings-general.tsx | 10 | ||||
| -rw-r--r-- | packages/app/src/components/settings-keybinds.tsx | 10 |
5 files changed, 53 insertions, 104 deletions
diff --git a/packages/app/src/components/dialog-select-model.tsx b/packages/app/src/components/dialog-select-model.tsx index 4d96c6c5f..4f0dcc3ee 100644 --- a/packages/app/src/components/dialog-select-model.tsx +++ b/packages/app/src/components/dialog-select-model.tsx @@ -90,7 +90,7 @@ const ModelList: Component<{ export function ModelSelectorPopover<T extends ValidComponent = "div">(props: { provider?: string - children?: JSX.Element | ((open: boolean) => JSX.Element) + children?: JSX.Element triggerAs?: T triggerProps?: ComponentProps<T> }) { @@ -182,13 +182,12 @@ export function ModelSelectorPopover<T extends ValidComponent = "div">(props: { as={props.triggerAs ?? "div"} {...(props.triggerProps as any)} > - {typeof props.children === "function" ? props.children(store.open) : props.children} + {props.children} </Kobalte.Trigger> <Kobalte.Portal> <Kobalte.Content - class="w-72 h-80 flex flex-col rounded-md border border-border-base bg-surface-raised-stronger-non-alpha shadow-md z-50 outline-none overflow-hidden" - data-component="model-popover-content" ref={(el) => setStore("content", el)} + class="w-72 h-80 flex flex-col p-2 rounded-md border border-border-base bg-surface-raised-stronger-non-alpha shadow-md z-50 outline-none overflow-hidden" onEscapeKeyDown={(event) => { setStore("dismiss", "escape") setStore("open", false) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 6e614eb1d..5c1d417eb 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -32,9 +32,7 @@ import { useNavigate, useParams } from "@solidjs/router" import { useSync } from "@/context/sync" import { useComments } from "@/context/comments" import { FileIcon } from "@opencode-ai/ui/file-icon" -import { MorphChevron } from "@opencode-ai/ui/morph-chevron" import { Button } from "@opencode-ai/ui/button" -import { CycleLabel } from "@opencode-ai/ui/cycle-label" import { Icon } from "@opencode-ai/ui/icon" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import type { IconName } from "@opencode-ai/ui/icons/provider" @@ -44,7 +42,6 @@ import { Select } from "@opencode-ai/ui/select" import { getDirectory, getFilename, getFilenameTruncated } from "@opencode-ai/util/path" import { useDialog } from "@opencode-ai/ui/context/dialog" import { ImagePreview } from "@opencode-ai/ui/image-preview" -import { ReasoningIcon } from "@opencode-ai/ui/reasoning-icon" import { ModelSelectorPopover } from "@/components/dialog-select-model" import { DialogSelectModelUnpaid } from "@/components/dialog-select-model-unpaid" import { useProviders } from "@/hooks/use-providers" @@ -1255,7 +1252,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { clearInput() client.session .shell({ - sessionID: session?.id || "", + sessionID: session.id, agent, model, command: text, @@ -1278,7 +1275,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { clearInput() client.session .command({ - sessionID: session?.id || "", + sessionID: session.id, command: commandName, arguments: args.join(" "), agent, @@ -1434,13 +1431,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => { const optimisticParts = requestParts.map((part) => ({ ...part, - sessionID: session?.id || "", + sessionID: session.id, messageID, })) as unknown as Part[] const optimisticMessage: Message = { id: messageID, - sessionID: session?.id || "", + sessionID: session.id, role: "user", time: { created: Date.now() }, agent, @@ -1451,9 +1448,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => { if (sessionDirectory === projectDirectory) { sync.set( produce((draft) => { - const messages = draft.message[session?.id || ""] + const messages = draft.message[session.id] if (!messages) { - draft.message[session?.id || ""] = [optimisticMessage] + draft.message[session.id] = [optimisticMessage] } else { const result = Binary.search(messages, messageID, (m) => m.id) messages.splice(result.index, 0, optimisticMessage) @@ -1469,9 +1466,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => { globalSync.child(sessionDirectory)[1]( produce((draft) => { - const messages = draft.message[session?.id || ""] + const messages = draft.message[session.id] if (!messages) { - draft.message[session?.id || ""] = [optimisticMessage] + draft.message[session.id] = [optimisticMessage] } else { const result = Binary.search(messages, messageID, (m) => m.id) messages.splice(result.index, 0, optimisticMessage) @@ -1488,7 +1485,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { if (sessionDirectory === projectDirectory) { sync.set( produce((draft) => { - const messages = draft.message[session?.id || ""] + const messages = draft.message[session.id] if (messages) { const result = Binary.search(messages, messageID, (m) => m.id) if (result.found) messages.splice(result.index, 1) @@ -1501,7 +1498,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { globalSync.child(sessionDirectory)[1]( produce((draft) => { - const messages = draft.message[session?.id || ""] + const messages = draft.message[session.id] if (messages) { const result = Binary.search(messages, messageID, (m) => m.id) if (result.found) messages.splice(result.index, 1) @@ -1522,15 +1519,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => { const worktree = WorktreeState.get(sessionDirectory) if (!worktree || worktree.status !== "pending") return true - if (sessionDirectory === projectDirectory && session?.id) { - sync.set("session_status", session?.id, { type: "busy" }) + if (sessionDirectory === projectDirectory) { + sync.set("session_status", session.id, { type: "busy" }) } const controller = new AbortController() const cleanup = () => { - if (sessionDirectory === projectDirectory && session?.id) { - sync.set("session_status", session?.id, { type: "idle" }) + if (sessionDirectory === projectDirectory) { + sync.set("session_status", session.id, { type: "idle" }) } removeOptimisticMessage() for (const item of commentItems) { @@ -1547,7 +1544,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { restoreInput() } - pending.set(session?.id || "", { abort: controller, cleanup }) + pending.set(session.id, { abort: controller, cleanup }) const abort = new Promise<Awaited<ReturnType<typeof WorktreeState.wait>>>((resolve) => { if (controller.signal.aborted) { @@ -1575,7 +1572,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { if (timer.id === undefined) return clearTimeout(timer.id) }) - pending.delete(session?.id || "") + pending.delete(session.id) if (controller.signal.aborted) return false if (result.status === "failed") throw new Error(result.message) return true @@ -1585,7 +1582,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { const ok = await waitForWorktree() if (!ok) return await client.session.prompt({ - sessionID: session?.id || "", + sessionID: session.id, agent, model, messageID, @@ -1595,9 +1592,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => { } void send().catch((err) => { - pending.delete(session?.id || "") - if (sessionDirectory === projectDirectory && session?.id) { - sync.set("session_status", session?.id, { type: "idle" }) + pending.delete(session.id) + if (sessionDirectory === projectDirectory) { + sync.set("session_status", session.id, { type: "idle" }) } showToast({ title: language.t("prompt.toast.promptSendFailed.title"), @@ -1619,28 +1616,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => { }) } - const currrentModelVariant = createMemo(() => { - const modelVariant = local.model.variant.current() ?? "" - return modelVariant === "xhigh" - ? "xHigh" - : modelVariant.length > 0 - ? modelVariant[0].toUpperCase() + modelVariant.slice(1) - : "Default" - }) - - const reasoningPercentage = createMemo(() => { - const variants = local.model.variant.list() - const current = local.model.variant.current() - const totalEntries = variants.length + 1 - - if (totalEntries <= 2 || current === "Default") { - return 0 - } - - const currentIndex = current ? variants.indexOf(current) + 1 : 0 - return ((currentIndex + 1) / totalEntries) * 100 - }, [local.model.variant]) - return ( <div class="relative size-full _max-h-[320px] flex flex-col gap-3"> <Show when={store.popover}> @@ -1693,7 +1668,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { </> } > - <Icon name="brain" size="normal" class="text-icon-info-active shrink-0" /> + <Icon name="brain" size="small" class="text-icon-info-active shrink-0" /> <span class="text-14-regular text-text-strong whitespace-nowrap"> @{(item as { type: "agent"; name: string }).name} </span> @@ -1754,9 +1729,9 @@ export const PromptInput: Component<PromptInputProps> = (props) => { }} > <Show when={store.dragging}> - <div class="absolute inset-0 z-10 flex items-center justify-center bg-surface-raised-stronger-non-alpha/90 mr-1 pointer-events-none"> + <div class="absolute inset-0 z-10 flex items-center justify-center bg-surface-raised-stronger-non-alpha/90 pointer-events-none"> <div class="flex flex-col items-center gap-2 text-text-weak"> - <Icon name="photo" size={18} class="text-icon-base stroke-1.5" /> + <Icon name="photo" class="size-8" /> <span class="text-14-regular">{language.t("prompt.dropzone.label")}</span> </div> </div> @@ -1795,7 +1770,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { }} > <div class="flex items-center gap-1.5"> - <FileIcon node={{ path: item.path, type: "file" }} class="shrink-0 size-7" /> + <FileIcon node={{ path: item.path, type: "file" }} class="shrink-0 size-3.5" /> <div class="flex items-center text-11-regular min-w-0 font-medium"> <span class="text-text-strong whitespace-nowrap">{getFilenameTruncated(item.path, 14)}</span> <Show when={item.selection}> @@ -1812,7 +1787,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { type="button" icon="close-small" variant="ghost" - class="ml-auto size-7 opacity-0 group-hover:opacity-100 transition-all" + class="ml-auto h-5 w-5 opacity-0 group-hover:opacity-100 transition-all" onClick={(e) => { e.stopPropagation() if (item.commentID) comments.remove(item.path, item.commentID) @@ -1842,7 +1817,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { when={attachment.mime.startsWith("image/")} fallback={ <div class="size-16 rounded-md bg-surface-base flex items-center justify-center border border-border-base"> - <Icon name="folder" size="normal" class="size-6 text-text-base" /> + <Icon name="folder" class="size-6 text-text-weak" /> </div> } > @@ -1916,7 +1891,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { </Show> </div> <div class="relative p-3 flex items-center justify-between"> - <div class="flex items-center justify-start gap-2"> + <div class="flex items-center justify-start gap-0.5"> <Switch> <Match when={store.mode === "shell"}> <div class="flex items-center gap-2 px-2 h-6"> @@ -1947,17 +1922,12 @@ export const PromptInput: Component<PromptInputProps> = (props) => { title={language.t("command.model.choose")} keybind={command.keybind("model.choose")} > - <Button - as="div" - variant="ghost" - class="px-2" - onClick={() => dialog.render(<DialogSelectModelUnpaid />, "select-model")} - > + <Button as="div" variant="ghost" onClick={() => dialog.show(() => <DialogSelectModelUnpaid />)}> <Show when={local.model.current()?.provider?.id}> <ProviderIcon id={local.model.current()!.provider.id as IconName} class="size-4 shrink-0" /> </Show> {local.model.current()?.name ?? language.t("dialog.model.select.title")} - <MorphChevron expanded={dialog.isActive("select-model")} /> + <Icon name="chevron-down" size="small" /> </Button> </TooltipKeybind> } @@ -1968,15 +1938,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => { keybind={command.keybind("model.choose")} > <ModelSelectorPopover triggerAs={Button} triggerProps={{ variant: "ghost" }}> - {(open) => ( - <> - <Show when={local.model.current()?.provider?.id}> - <ProviderIcon id={local.model.current()!.provider.id as IconName} class="size-4 shrink-0" /> - </Show> - {local.model.current()?.name ?? language.t("dialog.model.select.title")} - <MorphChevron expanded={open} class="text-text-weak" /> - </> - )} + <Show when={local.model.current()?.provider?.id}> + <ProviderIcon id={local.model.current()!.provider.id as IconName} class="size-4 shrink-0" /> + </Show> + {local.model.current()?.name ?? language.t("dialog.model.select.title")} + <Icon name="chevron-down" size="small" /> </ModelSelectorPopover> </TooltipKeybind> </Show> @@ -1989,13 +1955,10 @@ export const PromptInput: Component<PromptInputProps> = (props) => { <Button data-action="model-variant-cycle" variant="ghost" - class="text-text-strong text-12-regular" + class="text-text-base _hidden group-hover/prompt-input:inline-block capitalize text-12-regular" onClick={() => local.model.variant.cycle()} > - <Show when={local.model.variant.list().length > 1}> - <ReasoningIcon percentage={reasoningPercentage()} size={16} strokeWidth={1.25} /> - </Show> - <CycleLabel value={currrentModelVariant()} /> + {local.model.variant.current() ?? language.t("common.default")} </Button> </TooltipKeybind> </Show> @@ -2009,7 +1972,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { variant="ghost" onClick={() => permission.toggleAutoAccept(params.id!, sdk.directory)} classList={{ - "_hidden group-hover/prompt-input:flex items-center justify-center": true, + "_hidden group-hover/prompt-input:flex size-6 items-center justify-center": true, "text-text-base": !permission.isAutoAccepting(params.id!, sdk.directory), "hover:bg-surface-success-base": permission.isAutoAccepting(params.id!, sdk.directory), }} @@ -2031,7 +1994,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { </Match> </Switch> </div> - <div class="flex items-center gap-1 absolute right-3 bottom-3"> + <div class="flex items-center gap-3 absolute right-3 bottom-3"> <input ref={fileInputRef} type="file" @@ -2043,19 +2006,18 @@ export const PromptInput: Component<PromptInputProps> = (props) => { e.currentTarget.value = "" }} /> - <div class="flex items-center gap-1.5 mr-1.5"> + <div class="flex items-center gap-2"> <SessionContextUsage /> <Show when={store.mode === "normal"}> <Tooltip placement="top" value={language.t("prompt.action.attachFile")}> <Button type="button" variant="ghost" - size="small" - class="px-1" + class="size-6" onClick={() => fileInputRef.click()} aria-label={language.t("prompt.action.attachFile")} > - <Icon name="photo" class="size-6 text-icon-base" /> + <Icon name="photo" class="size-4.5" /> </Button> </Tooltip> </Show> @@ -2074,7 +2036,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { <Match when={true}> <div class="flex items-center gap-2"> <span>{language.t("prompt.action.send")}</span> - <Icon name="enter" size="normal" class="text-icon-base" /> + <Icon name="enter" size="small" class="text-icon-base" /> </div> </Match> </Switch> @@ -2085,7 +2047,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => { disabled={!prompt.dirty() && !working()} icon={working() ? "stop" : "arrow-up"} variant="primary" - class="h-6 w-5.5" + class="h-6 w-4.5" aria-label={working() ? language.t("prompt.action.stop") : language.t("prompt.action.send")} /> </Tooltip> diff --git a/packages/app/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx index 92b060212..1e37d8f6a 100644 --- a/packages/app/src/components/session-context-usage.tsx +++ b/packages/app/src/components/session-context-usage.tsx @@ -64,8 +64,8 @@ export function SessionContextUsage(props: SessionContextUsageProps) { } const circle = () => ( - <div class="text-icon-base"> - <ProgressCircle size={18} percentage={context()?.percentage ?? 0} /> + <div class="p-1"> + <ProgressCircle size={16} strokeWidth={2} percentage={context()?.percentage ?? 0} /> </div> ) @@ -101,7 +101,7 @@ export function SessionContextUsage(props: SessionContextUsageProps) { <Button type="button" variant="ghost" - class="size-7 text-icon-base" + class="size-6" onClick={openContext} aria-label={language.t("context.usage.view")} > diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index b2fb43536..b26f6ba22 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -10,7 +10,6 @@ import { usePlatform } from "@/context/platform" import { useSettings, monoFontFamily } from "@/context/settings" import { playSound, SOUND_OPTIONS } from "@/utils/sound" import { Link } from "./link" -import { ScrollFade } from "@opencode-ai/ui/scroll-fade" let demoSoundState = { cleanup: undefined as (() => void) | undefined, @@ -131,12 +130,7 @@ export const SettingsGeneral: Component = () => { const soundOptions = [...SOUND_OPTIONS] return ( - <ScrollFade - direction="vertical" - fadeStartSize={0} - fadeEndSize={16} - class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10" - > + <div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10"> <div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-raised-stronger-non-alpha)_calc(100%_-_24px),transparent)]"> <div class="flex flex-col gap-1 pt-6 pb-8"> <h2 class="text-16-medium text-text-strong">{language.t("settings.tab.general")}</h2> @@ -401,7 +395,7 @@ export const SettingsGeneral: Component = () => { </div> </div> </div> - </ScrollFade> + </div> ) } diff --git a/packages/app/src/components/settings-keybinds.tsx b/packages/app/src/components/settings-keybinds.tsx index efd18c8bd..393da0c2a 100644 --- a/packages/app/src/components/settings-keybinds.tsx +++ b/packages/app/src/components/settings-keybinds.tsx @@ -9,7 +9,6 @@ import fuzzysort from "fuzzysort" import { formatKeybind, parseKeybind, useCommand } from "@/context/command" import { useLanguage } from "@/context/language" import { useSettings } from "@/context/settings" -import { ScrollFade } from "@opencode-ai/ui/scroll-fade" const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) const PALETTE_ID = "command.palette" @@ -353,12 +352,7 @@ export const SettingsKeybinds: Component = () => { }) return ( - <ScrollFade - direction="vertical" - fadeStartSize={0} - fadeEndSize={16} - class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10" - > + <div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10"> <div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-raised-stronger-non-alpha)_calc(100%_-_24px),transparent)]"> <div class="flex flex-col gap-4 pt-6 pb-6 max-w-[720px]"> <div class="flex items-center justify-between gap-4"> @@ -435,6 +429,6 @@ export const SettingsKeybinds: Component = () => { </div> </Show> </div> - </ScrollFade> + </div> ) } |
