+
+
{i.name}
-
- Free
+
+ Recommended
-
- Latest
+
+ Connect with Claude Pro/Max or API key
)}
diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx
index 15a36b2ff..1c593ca87 100644
--- a/packages/enterprise/src/routes/share/[shareID].tsx
+++ b/packages/enterprise/src/routes/share/[shareID].tsx
@@ -212,7 +212,7 @@ export default function () {
v{info().version}
diff --git a/packages/ui/src/components/provider-icon.tsx b/packages/ui/src/components/provider-icon.tsx
index 924dcd25c..d653765a5 100644
--- a/packages/ui/src/components/provider-icon.tsx
+++ b/packages/ui/src/components/provider-icon.tsx
@@ -4,11 +4,11 @@ import sprite from "./provider-icons/sprite.svg"
import type { IconName } from "./provider-icons/types"
export type ProviderIconProps = JSX.SVGElementTags["svg"] & {
- name: IconName
+ id: IconName
}
export const ProviderIcon: Component
= (props) => {
- const [local, rest] = splitProps(props, ["name", "class", "classList"])
+ const [local, rest] = splitProps(props, ["id", "class", "classList"])
return (
)
}
diff --git a/packages/ui/src/components/select-dialog.css b/packages/ui/src/components/select-dialog.css
index cc834f795..f5687ad8e 100644
--- a/packages/ui/src/components/select-dialog.css
+++ b/packages/ui/src/components/select-dialog.css
@@ -11,7 +11,7 @@
display: flex;
height: 40px;
flex-shrink: 0;
- padding: 4px 10px 4px 6px;
+ padding: 4px 10px 4px 16px;
align-items: center;
gap: 12px;
align-self: stretch;
@@ -121,6 +121,9 @@
letter-spacing: var(--letter-spacing-normal);
[data-slot="select-dialog-item-selected-icon"] {
+ color: var(--icon-strong-base);
+ }
+ [data-slot="select-dialog-item-active-icon"] {
display: none;
color: var(--icon-strong-base);
}
@@ -128,12 +131,13 @@
&[data-active="true"] {
border-radius: var(--radius-md);
background: var(--surface-raised-base-hover);
- }
- &[data-selected="true"] {
- [data-slot="select-dialog-item-selected-icon"] {
+ [data-slot="select-dialog-item-active-icon"] {
display: block;
}
}
+ &:active {
+ background: var(--surface-raised-base-active);
+ }
}
}
}
diff --git a/packages/ui/src/components/select-dialog.tsx b/packages/ui/src/components/select-dialog.tsx
index b93993ad4..86f723225 100644
--- a/packages/ui/src/components/select-dialog.tsx
+++ b/packages/ui/src/components/select-dialog.tsx
@@ -2,7 +2,7 @@ import { createEffect, Show, For, type JSX, splitProps, createSignal } from "sol
import { createStore } from "solid-js/store"
import { FilteredListProps, useFilteredList } from "@opencode-ai/ui/hooks"
import { Dialog, DialogProps } from "./dialog"
-import { Icon } from "./icon"
+import { Icon, IconProps } from "./icon"
import { Input } from "./input"
import { IconButton } from "./icon-button"
@@ -16,6 +16,7 @@ interface SelectDialogProps
onSelect?: (value: T | undefined) => void
onKeyEvent?: (event: KeyboardEvent, item: T | undefined) => void
actions?: JSX.Element
+ activeIcon?: IconProps["name"]
}
export function SelectDialog(props: SelectDialogProps) {
@@ -165,7 +166,12 @@ export function SelectDialog(props: SelectDialogProps) {
}}
>
{others.children(item)}
-
+
+
+
+
+ {(icon) => }
+
)}
--
cgit v1.2.3
From 85cfa226c34e41660ddfdcb04543af2e494ae168 Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Wed, 10 Dec 2025 17:17:34 -0600
Subject: wip(desktop): progress
---
packages/desktop/src/components/prompt-input.tsx | 221 +++++++++++++++++------
packages/desktop/src/hooks/use-providers.ts | 31 ++++
packages/desktop/src/pages/layout.tsx | 19 +-
packages/ui/src/components/input.tsx | 10 +-
packages/ui/src/components/list.css | 8 +
packages/ui/src/components/list.tsx | 3 +-
6 files changed, 222 insertions(+), 70 deletions(-)
create mode 100644 packages/desktop/src/hooks/use-providers.ts
(limited to 'packages/desktop/src/pages')
diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx
index 985dbae8e..0672dfc85 100644
--- a/packages/desktop/src/components/prompt-input.tsx
+++ b/packages/desktop/src/components/prompt-input.tsx
@@ -17,6 +17,13 @@ import { Select } from "@opencode-ai/ui/select"
import { Tag } from "@opencode-ai/ui/tag"
import { getDirectory, getFilename } from "@opencode-ai/util/path"
import { useLayout } from "@/context/layout"
+import { popularProviders, useProviders } from "@/hooks/use-providers"
+import { Dialog } from "@opencode-ai/ui/dialog"
+import { List, ListRef } from "@opencode-ai/ui/list"
+import { iife } from "@opencode-ai/util/iife"
+import { Input } from "@opencode-ai/ui/input"
+import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
+import { IconName } from "@opencode-ai/ui/icons/provider"
interface PromptInputProps {
class?: string
@@ -58,6 +65,7 @@ export const PromptInput: Component = (props) => {
const local = useLocal()
const session = useSession()
const layout = useLayout()
+ const providers = useProviders()
let editorRef!: HTMLDivElement
const [store, setStore] = createStore<{
@@ -461,60 +469,167 @@ export const PromptInput: Component = (props) => {
- {
- if (open) {
- layout.dialog.open("model")
- } else {
- layout.dialog.close("model")
- }
- }}
- title="Select model"
- placeholder="Search models"
- emptyMessage="No model results"
- key={(x) => `${x.provider.id}:${x.id}`}
- items={local.model.list()}
- current={local.model.current()}
- filterKeys={["provider.name", "name", "id"]}
- // groupBy={(x) => (local.model.recent().includes(x) ? "Recent" : x.provider.name)}
- groupBy={(x) => x.provider.name}
- sortGroupsBy={(a, b) => {
- const order = ["opencode", "anthropic", "github-copilot", "openai", "google", "openrouter", "vercel"]
- if (a.category === "Recent" && b.category !== "Recent") return -1
- if (b.category === "Recent" && a.category !== "Recent") return 1
- const aProvider = a.items[0].provider.id
- const bProvider = b.items[0].provider.id
- if (order.includes(aProvider) && !order.includes(bProvider)) return -1
- if (!order.includes(aProvider) && order.includes(bProvider)) return 1
- return order.indexOf(aProvider) - order.indexOf(bProvider)
- }}
- onSelect={(x) =>
- local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { recent: true })
- }
- actions={
-
- }
- >
- {(i) => (
-
- {i.name}
-
- Free
-
-
- Latest
-
-
- )}
-
+ {(i) => (
+
+ {i.name}
+
+ Free
+
+
+ Latest
+
+
+ )}
+
+
+
+ {iife(() => {
+ let listRef: ListRef | undefined
+ const handleKey = (e: KeyboardEvent) => {
+ if (e.key === "Escape") return
+ listRef?.onKeyDown(e)
+ }
+ return (
+
+ )
+ })}
+
+