diff options
| author | Adam <[email protected]> | 2025-12-11 13:02:57 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2025-12-11 13:42:47 -0600 |
| commit | 16b7370d8cac304eb2af800b9c6a584784a0c600 (patch) | |
| tree | 8b181d31ce119d1f8cd8bb47d5268c08edde5ed7 /packages/desktop | |
| parent | 634fd62b25169619ffcbf87beec8777bf5a0d9bd (diff) | |
| download | opencode-16b7370d8cac304eb2af800b9c6a584784a0c600.tar.gz opencode-16b7370d8cac304eb2af800b9c6a584784a0c600.zip | |
wip(desktop): progress
Diffstat (limited to 'packages/desktop')
| -rw-r--r-- | packages/desktop/src/components/prompt-input.tsx | 10 | ||||
| -rw-r--r-- | packages/desktop/src/pages/layout.tsx | 108 |
2 files changed, 81 insertions, 37 deletions
diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx index 7f8568291..2c153ecc3 100644 --- a/packages/desktop/src/components/prompt-input.tsx +++ b/packages/desktop/src/components/prompt-input.tsx @@ -33,7 +33,6 @@ 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" @@ -557,6 +556,14 @@ export const PromptInput: Component<PromptInputProps> = (props) => { if (e.key === "Escape") return listRef?.onKeyDown(e) } + + onMount(() => { + document.addEventListener("keydown", handleKey) + onCleanup(() => { + document.removeEventListener("keydown", handleKey) + }) + }) + return ( <Dialog modal @@ -574,7 +581,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => { <Dialog.CloseButton tabIndex={-1} /> </Dialog.Header> <Dialog.Body> - <Input hidden type="text" class="opacity-0 size-0" autofocus onKeyDown={handleKey} /> <div class="flex flex-col gap-3 px-2.5"> <div class="text-14-medium text-text-base px-2.5">Free models provided by OpenCode</div> <List diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx index 3086ff2fd..3b9972c75 100644 --- a/packages/desktop/src/pages/layout.tsx +++ b/packages/desktop/src/pages/layout.tsx @@ -1,4 +1,4 @@ -import { createEffect, createMemo, For, Match, onMount, ParentProps, Show, Switch, type JSX } from "solid-js" +import { createEffect, createMemo, For, Match, onCleanup, onMount, ParentProps, Show, Switch, type JSX } from "solid-js" import { DateTime } from "luxon" import { A, useNavigate, useParams } from "@solidjs/router" import { useLayout } from "@/context/layout" @@ -38,7 +38,7 @@ import { Dialog } from "@opencode-ai/ui/dialog" import { iife } from "@opencode-ai/util/iife" import { Link } from "@/components/link" import { List, ListRef } from "@opencode-ai/ui/list" -import { Input } from "@opencode-ai/ui/input" +import { TextField } from "@opencode-ai/ui/text-field" import { showToast, Toast } from "@opencode-ai/ui/toast" import { useGlobalSDK } from "@/context/global-sdk" import { Spinner } from "@opencode-ai/ui/spinner" @@ -683,16 +683,37 @@ export default function Layout(props: ParentProps) { } } + let listRef: ListRef | undefined + function handleKey(e: KeyboardEvent) { + if (e.key === "Enter" && e.target instanceof HTMLInputElement) { + return + } + if (e.key === "Escape") return + listRef?.onKeyDown(e) + } + onMount(() => { if (methods().length === 1) { selectMethod(0) } + + document.addEventListener("keydown", handleKey) + onCleanup(() => { + document.removeEventListener("keydown", handleKey) + }) }) - let listRef: ListRef | undefined - function handleKey(e: KeyboardEvent) { - if (e.key === "Escape") return - listRef?.onKeyDown(e) + async function complete() { + await globalSDK.client.global.dispose() + setTimeout(() => { + showToast({ + variant: "success", + icon: "circle-check", + title: `${provider().name} connected`, + description: `${provider().name} models are now available to use.`, + }) + layout.connect.complete() + }, 500) } return ( @@ -753,7 +774,6 @@ export default function Layout(props: ParentProps) { <Match when={store.method === undefined}> <div class="text-14-regular text-text-base">Select login method for {provider().name}.</div> <div class=""> - <Input hidden type="text" class="opacity-0 size-0" autofocus onKeyDown={handleKey} /> <List ref={(ref) => (listRef = ref)} items={methods} @@ -820,16 +840,7 @@ export default function Layout(props: ParentProps) { key: apiKey, }, }) - await globalSDK.client.global.dispose() - setTimeout(() => { - showToast({ - variant: "success", - icon: "circle-check", - title: `${provider().name} connected`, - description: `${provider().name} models are now available to use.`, - }) - layout.connect.complete() - }, 500) + await complete() } return ( @@ -862,7 +873,7 @@ export default function Layout(props: ParentProps) { </Match> </Switch> <form onSubmit={handleSubmit} class="flex flex-col items-start gap-4"> - <Input + <TextField autofocus type="text" label={`${provider().name} API key`} @@ -915,16 +926,7 @@ export default function Layout(props: ParentProps) { code, }) if (!error) { - await globalSDK.client.global.dispose() - setTimeout(() => { - showToast({ - variant: "success", - icon: "circle-check", - title: `${provider().name} connected`, - description: `${provider().name} models are now available to use.`, - }) - layout.connect.complete() - }, 500) + await complete() return } setFormStore("error", "Invalid authorization code") @@ -938,7 +940,7 @@ export default function Layout(props: ParentProps) { OpenCode. </div> <form onSubmit={handleSubmit} class="flex flex-col items-start gap-4"> - <Input + <TextField autofocus type="text" label={`${store.method?.label} authorization code`} @@ -958,12 +960,48 @@ export default function Layout(props: ParentProps) { })} </Match> <Match when={store.authorization?.method === "auto"}> - <div class="flex flex-col gap-6"> - <div class="text-14-regular text-text-base"> - Visit <Link href={store.authorization!.url}>this link</Link> and enter the code below - to connect your account and use {provider().name} models in OpenCode. - </div> - </div> + {iife(() => { + const code = createMemo(() => { + const instructions = store.authorization?.instructions + if (instructions?.includes(":")) { + return instructions?.split(":")[1]?.trim() + } + return instructions + }) + + onMount(async () => { + const result = await globalSDK.client.provider.oauth.callback({ + providerID: providerID(), + method: methodIndex(), + }) + if (result.error) { + // TODO: show error + layout.dialog.close("connect") + return + } + await complete() + }) + + return ( + <div class="flex flex-col gap-6"> + <div class="text-14-regular text-text-base"> + Visit <Link href={store.authorization!.url}>this link</Link> and enter the code + below to connect your account and use {provider().name} models in OpenCode. + </div> + <TextField + label="Confirmation code" + class="font-mono" + value={code()} + readOnly + copyable + /> + <div class="text-14-regular text-text-base flex items-center gap-4"> + <Spinner /> + <span>Waiting for authorization...</span> + </div> + </div> + ) + })} </Match> </Switch> </Match> |
