diff options
| author | Adam <[email protected]> | 2025-12-10 14:48:08 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-12-10 15:17:03 -0600 |
| commit | 190fa4c87aa2b3f954a419f716add1fc29e4011e (patch) | |
| tree | 835e91a7457c4d92fd8d3118d225f12843b80a5b /packages/desktop/src/pages | |
| parent | 91d743ef9a5c346fe17bb857db68dca92a6e9ba1 (diff) | |
| download | opencode-190fa4c87aa2b3f954a419f716add1fc29e4011e.tar.gz opencode-190fa4c87aa2b3f954a419f716add1fc29e4011e.zip | |
wip(desktop): progress
Diffstat (limited to 'packages/desktop/src/pages')
| -rw-r--r-- | packages/desktop/src/pages/home.tsx | 4 | ||||
| -rw-r--r-- | packages/desktop/src/pages/layout.tsx | 90 |
2 files changed, 62 insertions, 32 deletions
diff --git a/packages/desktop/src/pages/home.tsx b/packages/desktop/src/pages/home.tsx index 4aac241e1..205ffd815 100644 --- a/packages/desktop/src/pages/home.tsx +++ b/packages/desktop/src/pages/home.tsx @@ -38,7 +38,7 @@ export default function Home() { <div class="mx-auto mt-55"> <Logo class="w-xl opacity-12" /> <Switch> - <Match when={sync.data.projects.length > 0}> + <Match when={sync.data.project.length > 0}> <div class="mt-20 w-full flex flex-col gap-4"> <div class="flex gap-2 items-center justify-between pl-3"> <div class="text-14-medium text-text-strong">Recent projects</div> @@ -50,7 +50,7 @@ export default function Home() { </div> <ul class="flex flex-col gap-2"> <For - each={sync.data.projects + each={sync.data.project .toSorted((a, b) => (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created)) .slice(0, 5)} > diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 3e0094756..2ea6c4ba0 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -9,6 +9,7 @@ import { Avatar } from "@opencode-ai/ui/avatar" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Button } from "@opencode-ai/ui/button" import { Icon } from "@opencode-ai/ui/icon" +import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { Tooltip } from "@opencode-ai/ui/tooltip" import { Collapsible } from "@opencode-ai/ui/collapsible" @@ -31,6 +32,9 @@ import { import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd" import { SelectDialog } from "@opencode-ai/ui/select-dialog" import { Tag } from "@opencode-ai/ui/tag" +import { IconName } from "@opencode-ai/ui/icons/provider" + +const popularProviders = ["opencode", "anthropic", "github-copilot", "openai", "google", "openrouter", "vercel"] export default function Layout(props: ParentProps) { const [store, setStore] = createStore({ @@ -46,15 +50,18 @@ export default function Layout(props: ParentProps) { const currentDirectory = createMemo(() => base64Decode(params.dir ?? "")) const sessions = createMemo(() => globalSync.child(currentDirectory())[0].session ?? []) const currentSession = createMemo(() => sessions().find((s) => s.id === params.id)) - const providers = createMemo(() => globalSync.data.providers) - const hasProviders = createMemo(() => { - const [projectStore] = globalSync.child(currentDirectory()) - return projectStore.provider.filter((p) => p.id !== "opencode").length > 0 - }) - - createEffect(() => { - console.log(providers()) + const providers = createMemo(() => { + if (currentDirectory()) { + const [projectStore] = globalSync.child(currentDirectory()) + return projectStore.provider + } + return globalSync.data.provider }) + const connectedProviders = createMemo(() => + providers().all.filter( + (p) => providers().connected.includes(p.id) && Object.values(p.models).find((m) => m.cost?.input), + ), + ) function navigateToProject(directory: string | undefined) { if (!directory) return @@ -93,7 +100,9 @@ export default function Layout(props: ParentProps) { } } - async function connectProvider() {} + async function connectProvider() { + layout.dialog.open("provider") + } createEffect(() => { if (!params.dir || !params.id) return @@ -484,7 +493,7 @@ export default function Layout(props: ParentProps) { </div> <div class="flex flex-col gap-1.5 self-stretch items-start shrink-0 px-2 py-3"> <Switch> - <Match when={!hasProviders() && layout.sidebar.opened()}> + <Match when={!connectedProviders().length && layout.sidebar.opened()}> <div class="rounded-md bg-background-stronger shadow-xs-border-base"> <div class="p-3 flex flex-col gap-2"> <div class="text-12-medium text-text-strong">Getting started</div> @@ -493,7 +502,7 @@ export default function Layout(props: ParentProps) { </div> <Tooltip placement="right" value="Connect provider" inactive={layout.sidebar.opened()}> <Button - class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg rounded-t-none shadow-none border-t border-border-weak-base pl-[7px]" + class="flex w-full text-left justify-start text-12-medium text-text-strong stroke-[1.5px] rounded-lg rounded-t-none shadow-none border-t border-border-weak-base pl-2.25 pb-px" size="large" icon="plus-small" onClick={connectProvider} @@ -506,7 +515,7 @@ export default function Layout(props: ParentProps) { <Match when={true}> <Tooltip placement="right" value="Connect provider" inactive={layout.sidebar.opened()}> <Button - class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg" + class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2" variant="ghost" size="large" icon="plus-small" @@ -520,7 +529,7 @@ export default function Layout(props: ParentProps) { <Show when={platform.openDirectoryPickerDialog}> <Tooltip placement="right" value="Open project" inactive={layout.sidebar.opened()}> <Button - class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg" + class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2" variant="ghost" size="large" icon="folder-add-left" @@ -533,7 +542,7 @@ export default function Layout(props: ParentProps) { <Tooltip placement="right" value="Settings" inactive={layout.sidebar.opened()}> <Button disabled - class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg" + class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2" variant="ghost" size="large" icon="settings-gear" @@ -546,7 +555,7 @@ export default function Layout(props: ParentProps) { as={"a"} href="https://opencode.ai/desktop-feedback" target="_blank" - class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg" + class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2" variant="ghost" size="large" icon="bubble-5" @@ -557,32 +566,53 @@ export default function Layout(props: ParentProps) { </div> </div> <main class="size-full overflow-x-hidden flex flex-col items-start">{props.children}</main> - <Show when={true}> + <Show when={layout.dialog.opened() === "provider"}> <SelectDialog defaultOpen title="Connect provider" placeholder="Search providers" + activeIcon="plus-small" key={(x) => x?.id} - items={providers()} + items={providers().all} // 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} - onSelect={(x) => - // local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { recent: true }) - { - return + filterKeys={["id", "name"]} + groupBy={(x) => (popularProviders.includes(x.id) ? "Popular" : "Other")} + sortBy={(a, b) => { + if (popularProviders.includes(a.id) && popularProviders.includes(b.id)) + return popularProviders.indexOf(a.id) - popularProviders.indexOf(b.id) + return a.name.localeCompare(b.name) + }} + sortGroupsBy={(a, b) => { + if (a.category === "Popular" && b.category !== "Popular") return -1 + if (b.category === "Popular" && a.category !== "Popular") return 1 + return 0 + }} + // onSelect={(x) => } + onOpenChange={(open) => { + if (open) { + layout.dialog.open("provider") + } else { + layout.dialog.close("provider") } - } + }} > {(i) => ( - <div class="w-full flex items-center gap-x-2.5"> + <div class="px-1.25 w-full flex items-center gap-x-4"> + <ProviderIcon + id={i.id as IconName} + // TODO: clean this up after we update icon in models.dev + classList={{ + "text-icon-weak-base": true, + "size-4 mx-0.5": i.id === "opencode", + "size-5": i.id !== "opencode", + }} + /> <span>{i.name}</span> - <Show when={!i.cost || i.cost?.input === 0}> - <Tag>Free</Tag> + <Show when={i.id === "opencode"}> + <Tag>Recommended</Tag> </Show> - <Show when={i.latest}> - <Tag>Latest</Tag> + <Show when={i.id === "anthropic"}> + <div class="text-14-regular text-text-weak">Connect with Claude Pro/Max or API key</div> </Show> </div> )} |
