diff --git a/packages/app/e2e/performance/timeline/session-tab-switch-probe.ts b/packages/app/e2e/performance/timeline/session-tab-switch-probe.ts index 955da80367d..5dcfc3ac6b3 100644 --- a/packages/app/e2e/performance/timeline/session-tab-switch-probe.ts +++ b/packages/app/e2e/performance/timeline/session-tab-switch-probe.ts @@ -25,7 +25,7 @@ async function installSessionSwitchProbe( let running = true const reviewLevels: Record = { panel: "#review-panel", - tabs: '#review-panel [data-component="tabs"]', + tabs: '#review-panel [data-component="tabs"]', body: '#review-panel [data-slot="session-review-v2-body"]', review: '#review-panel [data-component="session-review-v2"]', preview: '#review-panel [data-slot="session-review-v2-preview"]', diff --git a/packages/app/e2e/regression/session-request-docks.spec.ts b/packages/app/e2e/regression/session-request-docks.spec.ts index 356c0b7d466..b15dfb7a3e9 100644 --- a/packages/app/e2e/regression/session-request-docks.spec.ts +++ b/packages/app/e2e/regression/session-request-docks.spec.ts @@ -52,7 +52,7 @@ test("shows a pending question dock", async ({ page }) => { rejectRequests.push(request.url()) }) - await question.locator('[data-component="icon-button"][data-icon="chevron-down"]').click() + await question.getByRole("button", { name: "Minimize question" }).click() await expect(question).toBeVisible() await expect(question.getByText("Which implementation should be used?")).toBeVisible() await expect(question.getByText("Select one answer")).toBeHidden() @@ -63,7 +63,7 @@ test("shows a pending question dock", async ({ page }) => { await expect(page.locator('[data-component="question-minimized-dock"]')).toHaveCount(0) expect(rejectRequests).toEqual([]) - await question.locator('[data-component="icon-button"][data-icon="chevron-down"]').click() + await question.getByRole("button", { name: "Restore question" }).click() await expect(question).toBeVisible() await expect(question.getByText("Which implementation should be used?")).toBeVisible() await expect(question.getByRole("radio", { name: /Minimal/ })).toBeVisible() diff --git a/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts b/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts index 85485acbfeb..d7c44d96f17 100644 --- a/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts +++ b/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts @@ -131,15 +131,14 @@ test("labels V2 skill tools from IDs and result metadata", async ({ page }) => { "aria-label", "sample-skill", ) - await expect(page.locator(`[data-timeline-part-id="${completed}"] [data-component="text-shimmer"]`)).toHaveAttribute( - "aria-label", - "OpenCode", - ) + await expect( + page.locator(`[data-timeline-part-id="${completed}"] [data-component="text-shimmer"]`), + ).toHaveAttribute("aria-label", "OpenCode") for (const id of [pending, completed]) { const skill = page.locator(`[data-timeline-part-id="${id}"]`) await expect(skill.locator('[data-slot="skill-tool-label"]')).toHaveText("Skill") await expect(skill.locator('[data-slot="skill-tool-separator"]')).toHaveText("·") - await expect(skill.locator('use[href="#opencode-icon-post-skill"]')).toBeVisible() + await expect(skill.locator('use[href="#opencode-v2-icon-post-skill"]')).toBeVisible() } }) diff --git a/packages/app/e2e/smoke/session-timeline.spec.ts b/packages/app/e2e/smoke/session-timeline.spec.ts index f4371a305da..d0fb0922f4f 100644 --- a/packages/app/e2e/smoke/session-timeline.spec.ts +++ b/packages/app/e2e/smoke/session-timeline.spec.ts @@ -477,7 +477,7 @@ async function configureSmokePage(page: Page, directory: string) { } let recordFrame: number | undefined const record = () => { - for (const toast of document.querySelectorAll('[data-component="toast"][data-variant="error"]')) { + for (const toast of document.querySelectorAll(".toast-v2--error")) { const text = toast.textContent?.trim() if (text && !smoke.__timelineSmokeErrorToasts!.includes(text)) smoke.__timelineSmokeErrorToasts!.push(text) } diff --git a/packages/app/src/components/debug-bar.tsx b/packages/app/src/components/debug-bar.tsx index 67cd0da0e92..94447b14608 100644 --- a/packages/app/src/components/debug-bar.tsx +++ b/packages/app/src/components/debug-bar.tsx @@ -3,7 +3,6 @@ import { batch, createEffect, onCleanup, onMount, Show } from "solid-js" import { createStore } from "solid-js/store" import { makeEventListener } from "@solid-primitives/event-listener" import { Tooltip } from "@opencode-ai/ui/tooltip" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" import { useLanguage } from "@/context/language" import { usePlatform } from "@/context/platform" @@ -102,16 +101,8 @@ function Cell(props: { ) - if (props.inline) { - return ( - - {content()} - - ) - } - return ( - + {content()} ) @@ -151,16 +142,8 @@ function ToggleCell(props: { ) - if (props.inline) { - return ( - - {content()} - - ) - } - return ( - + {content()} ) diff --git a/packages/app/src/components/dialog-command-palette-v2.tsx b/packages/app/src/components/dialog-command-palette-v2.tsx index 2756c2094dd..e2b11699f2f 100644 --- a/packages/app/src/components/dialog-command-palette-v2.tsx +++ b/packages/app/src/components/dialog-command-palette-v2.tsx @@ -1,10 +1,10 @@ import { getDirectory, getFilename } from "@opencode-ai/util/path" import { FileIcon } from "@opencode-ai/ui/file-icon" import { ScrollView } from "@opencode-ai/ui/scroll-view" -import { Dialog, DialogBody } from "@opencode-ai/ui/v2/dialog-v2" -import { Icon } from "@opencode-ai/ui/v2/icon" -import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2" -import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { Dialog, DialogBody } from "@opencode-ai/ui/dialog" +import { Icon } from "@opencode-ai/ui/icon" +import { Keybind } from "@opencode-ai/ui/keybind" +import { TextInput } from "@opencode-ai/ui/text-input" import { useDialog } from "@opencode-ai/ui/context/dialog" import { createEffect, createMemo, createResource, createSignal, For, Match, onCleanup, Show, Switch } from "solid-js" import { commandPaletteOptions, formatKeybindParts, useCommand } from "@/context/command" @@ -191,7 +191,7 @@ function CommandPaletteView(props: { - + diff --git a/packages/app/src/components/dialog-connect-provider.stories.tsx b/packages/app/src/components/dialog-connect-provider.stories.tsx index 3aec6c9de33..3247ee2bf64 100644 --- a/packages/app/src/components/dialog-connect-provider.stories.tsx +++ b/packages/app/src/components/dialog-connect-provider.stories.tsx @@ -13,7 +13,7 @@ function ConnectProviderDialogStory() { onMount(open) return ( - ) @@ -29,7 +29,7 @@ function ProviderConnectionDialogStory(props) { onMount(open) return ( - ) diff --git a/packages/app/src/components/dialog-connect-provider.tsx b/packages/app/src/components/dialog-connect-provider.tsx index 71833be4a5d..3e7bcff6307 100644 --- a/packages/app/src/components/dialog-connect-provider.tsx +++ b/packages/app/src/components/dialog-connect-provider.tsx @@ -5,9 +5,8 @@ import { List } from "@opencode-ai/ui/list" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { Spinner } from "@opencode-ai/ui/spinner" import { TextField } from "@opencode-ai/ui/text-field" -import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" -import { DialogBody, DialogHeader, DialogTitle, DialogV2 } from "@opencode-ai/ui/v2/dialog-v2" -import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { DialogBody, DialogHeader, DialogTitle, Dialog } from "@opencode-ai/ui/dialog" +import { TextInput } from "@opencode-ai/ui/text-input" import { showToast } from "@/utils/toast" import { type Component, createMemo, createUniqueId, For, Match, onMount, Show, Switch } from "solid-js" import { createStore } from "solid-js/store" @@ -75,7 +74,7 @@ export const DialogConnectProvider: Component<{ } return ( - @@ -99,7 +98,7 @@ export const DialogConnectProvider: Component<{ - + ) } @@ -168,7 +167,7 @@ function ProviderPicker(props: { directory?: string; onSelect: (provider: string return (
- - @@ -516,7 +515,7 @@ function ProviderConnection(props: {
) @@ -585,7 +584,7 @@ function ProviderConnection(props: {
) diff --git a/packages/app/src/components/dialog-custom-provider.tsx b/packages/app/src/components/dialog-custom-provider.tsx index 4adc8d37f7b..e14995c0dd3 100644 --- a/packages/app/src/components/dialog-custom-provider.tsx +++ b/packages/app/src/components/dialog-custom-provider.tsx @@ -1,6 +1,7 @@ import { Button } from "@opencode-ai/ui/button" import { useDialog } from "@opencode-ai/ui/context/dialog" -import { Dialog } from "@opencode-ai/ui/dialog" +import { Dialog, DialogBody, DialogHeader, DialogTitle } from "@opencode-ai/ui/dialog" +import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" import { useMutation } from "@tanstack/solid-query" @@ -21,20 +22,21 @@ export function DialogCustomProvider(props: Props) { const language = useLanguage() return ( - - } - transition - > - + + + + } + variant="ghost" + onClick={props.onBack} + aria-label={language.t("common.goBack")} + /> + + + + + ) } @@ -238,7 +240,7 @@ export function CustomProviderForm(props: { autofocus?: boolean } = {}) { } variant="ghost" class="mt-1.5" onClick={() => removeModel(i())} @@ -282,7 +284,7 @@ export function CustomProviderForm(props: { autofocus?: boolean } = {}) { } variant="ghost" class="mt-1.5" onClick={() => removeHeader(i())} @@ -301,7 +303,7 @@ export function CustomProviderForm(props: { autofocus?: boolean } = {}) { class="w-auto self-start" type="submit" size="large" - variant="primary" + variant="contrast" disabled={saveMutation.isPending} > {saveMutation.isPending ? language.t("common.saving") : language.t("common.submit")} diff --git a/packages/app/src/components/dialog-edit-project-v2.tsx b/packages/app/src/components/dialog-edit-project-v2.tsx index fc5d958c5f0..2bcb518d435 100644 --- a/packages/app/src/components/dialog-edit-project-v2.tsx +++ b/packages/app/src/components/dialog-edit-project-v2.tsx @@ -1,12 +1,11 @@ -import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" -import { Dialog, DialogFooter } from "@opencode-ai/ui/v2/dialog-v2" -import { Field } from "@opencode-ai/ui/v2/field-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" +import { Button } from "@opencode-ai/ui/button" +import { Dialog, DialogFooter } from "@opencode-ai/ui/dialog" +import { Field } from "@opencode-ai/ui/field" import { Icon } from "@opencode-ai/ui/icon" -import { ProjectAvatar, PROJECT_AVATAR_VARIANTS } from "@opencode-ai/ui/v2/project-avatar-v2" -import { TabsV2 } from "@opencode-ai/ui/v2/tabs-v2" -import { TextareaV2 } from "@opencode-ai/ui/v2/textarea-v2" -import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { ProjectAvatar, PROJECT_AVATAR_VARIANTS } from "@opencode-ai/ui/project-avatar" +import { Tabs } from "@opencode-ai/ui/tabs" +import { Textarea } from "@opencode-ai/ui/textarea" +import { TextInput } from "@opencode-ai/ui/text-input" import { For, Show, createSignal, startTransition } from "solid-js" import { useLanguage } from "@/context/language" import { getProjectAvatarVariant, type LocalProject } from "@/context/layout" @@ -37,46 +36,46 @@ function ProjectSettingsDialog(props: { project: LocalProject; server: ServerCon const Footer = () => ( - + + ) return ( - void startTransition(() => setTab(value))} class="project-settings-v2" > - +
- + {projectName()} - - + + {language.t("project.settings.scripts")} - - + + {language.t("settings.tab.extensions")} - +
-
+ - +
@@ -86,7 +85,7 @@ function ProjectSettingsDialog(props: { project: LocalProject; server: ServerCon {language.t("dialog.project.edit.name")} - - +
- + - +
@@ -200,7 +199,7 @@ function ProjectSettingsDialog(props: { project: LocalProject; server: ServerCon {language.t("dialog.project.edit.worktree.startup")} {language.t("dialog.project.edit.worktree.startup.description")} -
- + - + - - + +
) } diff --git a/packages/app/src/components/dialog-fork.tsx b/packages/app/src/components/dialog-fork.tsx index 2823db5e0f5..4f7e0f290a0 100644 --- a/packages/app/src/components/dialog-fork.tsx +++ b/packages/app/src/components/dialog-fork.tsx @@ -3,7 +3,7 @@ import { useNavigate, useParams } from "@solidjs/router" import { useData } from "@/context/server" import { usePrompt } from "@/context/prompt" import { useDialog } from "@opencode-ai/ui/context/dialog" -import { Dialog } from "@opencode-ai/ui/dialog" +import { Dialog, DialogBody, DialogHeader, DialogTitle } from "@opencode-ai/ui/dialog" import { List } from "@opencode-ai/ui/list" import { showToast } from "@/utils/toast" import { useLanguage } from "@/context/language" @@ -94,23 +94,28 @@ export const DialogFork: Component = () => { } return ( - - x.id} - items={messages} - filterKeys={["text"]} - onSelect={handleSelect} - > - {(item) => ( -
- {item.text} - {item.time} -
- )} -
+ + + {language.t("command.session.fork")} + + + x.id} + items={messages} + filterKeys={["text"]} + onSelect={handleSelect} + > + {(item) => ( +
+ {item.text} + {item.time} +
+ )} +
+
) } diff --git a/packages/app/src/components/dialog-manage-models.tsx b/packages/app/src/components/dialog-manage-models.tsx index 660d5d4f217..398005d6196 100644 --- a/packages/app/src/components/dialog-manage-models.tsx +++ b/packages/app/src/components/dialog-manage-models.tsx @@ -1,15 +1,12 @@ -import { Dialog } from "@opencode-ai/ui/dialog" -import { List } from "@opencode-ai/ui/list" -import { Switch } from "@opencode-ai/ui/switch" -import { Tooltip } from "@opencode-ai/ui/tooltip" import { Button } from "@opencode-ai/ui/button" -import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" -import { Dialog as DialogV2, DialogBody, DialogHeader, DialogTitleGroup } from "@opencode-ai/ui/v2/dialog-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" -import { Switch as SwitchV2 } from "@opencode-ai/ui/v2/switch-v2" +import { Dialog, DialogBody, DialogHeader, DialogTitleGroup } from "@opencode-ai/ui/dialog" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { List } from "@opencode-ai/ui/list" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" +import { Switch } from "@opencode-ai/ui/switch" +import { TextInput } from "@opencode-ai/ui/text-input" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { useFilteredList } from "@opencode-ai/ui/hooks" import { For, Show, type Component } from "solid-js" import { useLocal } from "@/context/local" @@ -44,74 +41,80 @@ export const DialogManageModels: Component = () => { } return ( - + + - } - > - `${x?.provider?.id}:${x?.id}`} - items={local.model.list()} - filterKeys={["provider.name", "name", "id"]} - sortBy={(a, b) => a.name.localeCompare(b.name)} - groupBy={(x) => x.provider.id} - groupHeader={(group) => { - const provider = group.items[0].provider - return ( - <> - {provider.name} - - setProviderVisibility(provider.id, checked)} - hideLabel + + + `${x?.provider?.id}:${x?.id}`} + items={local.model.list()} + filterKeys={["provider.name", "name", "id"]} + sortBy={(a, b) => a.name.localeCompare(b.name)} + groupBy={(x) => x.provider.id} + groupHeader={(group) => { + const provider = group.items[0].provider + return ( + <> + {provider.name} + - {provider.name} - - - - ) - }} - sortGroupsBy={(a, b) => { - const aRank = providerRank(a.items[0].provider.id) - const bRank = providerRank(b.items[0].provider.id) - const aPopular = aRank >= 0 - const bPopular = bRank >= 0 - if (aPopular && !bPopular) return -1 - if (!aPopular && bPopular) return 1 - return aRank - bRank - }} - onSelect={(x) => { - if (!x) return - const key = { modelID: x.id, providerID: x.provider.id } - local.model.setVisibility(key, !local.model.visible(key)) - }} - > - {(i) => ( -
- {i.name} -
e.stopPropagation()}> - { - local.model.setVisibility({ modelID: i.id, providerID: i.provider.id }, checked) - }} - /> + setProviderVisibility(provider.id, checked)} + hideLabel + > + {provider.name} + + + + ) + }} + sortGroupsBy={(a, b) => { + const aRank = providerRank(a.items[0].provider.id) + const bRank = providerRank(b.items[0].provider.id) + const aPopular = aRank >= 0 + const bPopular = bRank >= 0 + if (aPopular && !bPopular) return -1 + if (!aPopular && bPopular) return 1 + return aRank - bRank + }} + onSelect={(x) => { + if (!x) return + const key = { modelID: x.id, providerID: x.provider.id } + local.model.setVisibility(key, !local.model.visible(key)) + }} + > + {(i) => ( +
+ {i.name} +
e.stopPropagation()}> + { + local.model.setVisibility({ modelID: i.id, providerID: i.provider.id }, checked) + }} + /> +
-
- )} - + )} + +
) } @@ -154,20 +157,20 @@ export const DialogManageModelsV2: Component = () => { }) return ( - + - +
- { aria-label={language.t("dialog.model.search.placeholder")} /> - } + icon={} onClick={() => list.clear()} aria-label={language.t("common.clear")} /> @@ -225,14 +228,14 @@ export const DialogManageModelsV2: Component = () => {

{group.items[0].provider.name}

- setProviderVisibility(group.category, checked)} hideLabel > {group.items[0].provider.name} - +
@@ -240,13 +243,13 @@ export const DialogManageModelsV2: Component = () => { {(item) => (
- setModelVisibility(item, checked)} hideLabel > {item.name} - +
)} @@ -260,6 +263,6 @@ export const DialogManageModelsV2: Component = () => {
-
+
) } diff --git a/packages/app/src/components/dialog-release-notes.tsx b/packages/app/src/components/dialog-release-notes.tsx index 3827b9e9e7b..2bd390e4da7 100644 --- a/packages/app/src/components/dialog-release-notes.tsx +++ b/packages/app/src/components/dialog-release-notes.tsx @@ -86,12 +86,12 @@ export function DialogReleaseNotes(props: { highlights: Highlight[] }) { + } > - diff --git a/packages/app/src/components/dialog-select-directory-v2.tsx b/packages/app/src/components/dialog-select-directory-v2.tsx index 07c958058ba..1fc259695fd 100644 --- a/packages/app/src/components/dialog-select-directory-v2.tsx +++ b/packages/app/src/components/dialog-select-directory-v2.tsx @@ -1,8 +1,8 @@ import "@pierre/trees/web-components" import { FileTree } from "@pierre/trees" -import { Dialog, DialogBody, DialogFooter, DialogHeader, DialogTitle } from "@opencode-ai/ui/v2/dialog-v2" -import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" -import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { Dialog, DialogBody, DialogFooter, DialogHeader, DialogTitle } from "@opencode-ai/ui/dialog" +import { Button } from "@opencode-ai/ui/button" +import { TextInput } from "@opencode-ai/ui/text-input" import { useDialog } from "@opencode-ai/ui/context/dialog" import { createEffect, createMemo, createResource, createSignal, For, onCleanup, onMount, Show } from "solid-js" import { useGlobal } from "@/context/global" @@ -28,7 +28,7 @@ import { pickerRoot, } from "./directory-picker-domain" import "./dialog-select-directory-v2.css" -import { DividerV2 } from "@opencode-ai/ui/v2/divider-v2" +import { Divider } from "@opencode-ai/ui/divider" import { getFilename } from "@opencode-ai/util/path" interface DialogSelectDirectoryV2Props { @@ -293,10 +293,10 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) { {props.title ?? language.t("command.project.open")} - +
-
- void navigate(home())}> + + +
0}>
@@ -379,12 +379,12 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
{policy.result(root(), selected(), rootValid())}
- dialog.close()}> + +
) diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx deleted file mode 100644 index a0b610d972b..00000000000 --- a/packages/app/src/components/dialog-select-file.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import { Dialog } from "@opencode-ai/ui/dialog" -import { FileIcon } from "@opencode-ai/ui/file-icon" -import { Icon } from "@opencode-ai/ui/icon" -import { Keybind } from "@opencode-ai/ui/keybind" -import { List } from "@opencode-ai/ui/list" -import { getDirectory, getFilename } from "@opencode-ai/util/path" -import { createMemo, createSignal, lazy, Match, Show, Switch } from "solid-js" -import { formatKeybind } from "@/context/command" -import { useServerSDK } from "@/context/server-sdk" -import { useLanguage } from "@/context/language" -import { usePlatform } from "@/context/platform" -import { useSessionLayout } from "@/pages/session/session-layout" -import { decode64 } from "@/utils/base64" -import { getRelativeTime } from "@/utils/time" -import { - createCommandPaletteFileEntry, - createCommandPaletteFileOpener, - createCommandPaletteModel, - uniqueCommandPaletteEntries, - type CommandPaletteEntry, -} from "./command-palette" -import { DialogCommandPaletteV2 } from "./dialog-command-palette-v2" - -const DialogSelectFileV2 = lazy(() => - import("./dialog-select-directory-v2").then((module) => ({ default: module.DialogSelectDirectoryV2 })), -) -type DialogSelectFileMode = "all" | "files" - -export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFile?: (path: string) => void }) { - const platform = usePlatform() - const filesOnly = () => props.mode === "files" - - if (!filesOnly()) { - return - } - - if (filesOnly() && platform.platform === "desktop") { - return - } - - return -} - -function DialogSelectFileDesktopV2(props: { onOpenFile?: (path: string) => void }) { - const language = useLanguage() - const serverSDK = useServerSDK() - const { params } = useSessionLayout() - const projectDirectory = createMemo(() => decode64(params.dir) ?? "") - const openFile = createCommandPaletteFileOpener(props.onOpenFile) - - return ( - { - if (typeof result !== "string") return - openFile(result) - }} - /> - ) -} - -function DialogSelectFileLegacy(props: { filesOnly: () => boolean; onOpenFile?: (path: string) => void }) { - const palette = createCommandPaletteModel(props) - const [grouped, setGrouped] = createSignal(false) - - const items = async (text: string) => { - const query = text.trim() - setGrouped(query.length > 0) - - if (!query && props.filesOnly()) { - const loaded = palette.file.tree.state("")?.loaded - const pending = loaded ? Promise.resolve() : palette.file.tree.list("") - const next = uniqueCommandPaletteEntries([...palette.recentFileEntries(), ...palette.rootFileEntries()]) - - if (loaded || next.length > 0) { - void pending - return next - } - - await pending - return uniqueCommandPaletteEntries([...palette.recentFileEntries(), ...palette.rootFileEntries()]) - } - - if (!query) return [...palette.preferredCommandEntries(), ...palette.recentFileEntries()] - - if (props.filesOnly()) { - const files = await palette.file.searchFiles(query) - const category = palette.language.t("palette.group.files") - return files.map((path) => createCommandPaletteFileEntry(path, category)) - } - - const [files, nextSessions] = await Promise.all([ - palette.file.searchFiles(query), - Promise.resolve(palette.sessions(query)), - ]) - const category = palette.language.t("palette.group.files") - const entries = files.map((path) => createCommandPaletteFileEntry(path, category)) - return [...palette.commandEntries(), ...nextSessions, ...entries] - } - - return ( - - item.id} - filterKeys={["title", "description", "category"]} - skipFilter={(item) => item.type === "file"} - groupBy={grouped() ? (item) => item.category : () => ""} - onMove={(item: CommandPaletteEntry | undefined) => palette.highlight(item)} - onSelect={(item: CommandPaletteEntry | undefined) => palette.select(item)} - > - {(item) => ( - -
- -
- - {getDirectory(item.path ?? "")} - - {getFilename(item.path ?? "")} -
-
- - } - > - -
-
- {item.title} - - {item.description} - -
- - {formatKeybind(item.keybind ?? "", palette.language.t)} - -
-
- -
-
- -
- - {item.title} - - - - {item.description} - - -
-
- - - {getRelativeTime(new Date(item.updated!).toISOString(), palette.language.t)} - - -
-
-
- )} -
-
- ) -} diff --git a/packages/app/src/components/dialog-select-mcp.tsx b/packages/app/src/components/dialog-select-mcp.tsx index 94d03daa91a..00e25213ad0 100644 --- a/packages/app/src/components/dialog-select-mcp.tsx +++ b/packages/app/src/components/dialog-select-mcp.tsx @@ -1,7 +1,7 @@ import { Component, createMemo, Show } from "solid-js" import { useData } from "@/context/server" import { useWorkspaceLocation } from "@/context/location" -import { Dialog } from "@opencode-ai/ui/dialog" +import { Dialog, DialogBody, DialogHeader, DialogTitleGroup } from "@opencode-ai/ui/dialog" import { List } from "@opencode-ai/ui/list" import { Switch } from "@opencode-ai/ui/switch" import { useLanguage } from "@/context/language" @@ -31,65 +31,71 @@ export const DialogSelectMcp: Component = () => { const totalCount = createMemo(() => items().length) return ( - - x?.name ?? ""} - items={items} - filterKeys={["name", "status"]} - sortBy={(a, b) => a.name.localeCompare(b.name)} - onSelect={(x) => { - if (!x || x.status === "pending" || toggle.isPending) return - toggle.mutate(x.name) - }} - > - {(i) => { - const mcpStatus = () => - data.location.mcp.server.list({ directory: sdk().directory })?.find((server) => server.name === i.name) - ?.status - const status = () => mcpStatus()?.status - const statusLabel = () => { - const key = status() ? statusLabels[status() as keyof typeof statusLabels] : undefined - if (!key) return - return language.t(key) - } - const error = () => { - const s = mcpStatus() - if (s?.status === "failed") return s.error - } - const enabled = () => status() === "connected" - return ( -
-
-
- {i.name} - - {statusLabel()} + + + + + + x?.name ?? ""} + items={items} + filterKeys={["name", "status"]} + sortBy={(a, b) => a.name.localeCompare(b.name)} + onSelect={(x) => { + if (!x || x.status === "pending" || toggle.isPending) return + toggle.mutate(x.name) + }} + > + {(i) => { + const mcpStatus = () => + data.location.mcp.server.list({ directory: sdk().directory })?.find((server) => server.name === i.name) + ?.status + const status = () => mcpStatus()?.status + const statusLabel = () => { + const key = status() ? statusLabels[status() as keyof typeof statusLabels] : undefined + if (!key) return + return language.t(key) + } + const error = () => { + const s = mcpStatus() + if (s?.status === "failed") return s.error + } + const enabled = () => status() === "connected" + return ( +
+
+
+ {i.name} + + {statusLabel()} + +
+ + {error()}
- - {error()} - +
e.stopPropagation()}> + { + if (toggle.isPending) return + toggle.mutate(i.name) + }} + /> +
-
e.stopPropagation()}> - { - if (toggle.isPending) return - toggle.mutate(i.name) - }} - /> -
-
- ) - }} - + ) + }} + +
) } diff --git a/packages/app/src/components/dialog-select-model-unpaid-v2.stories.tsx b/packages/app/src/components/dialog-select-model-unpaid-v2.stories.tsx index bd4beb2ec9b..0c16020eccc 100644 --- a/packages/app/src/components/dialog-select-model-unpaid-v2.stories.tsx +++ b/packages/app/src/components/dialog-select-model-unpaid-v2.stories.tsx @@ -39,7 +39,7 @@ function SelectModelWithoutProviders() { onMount(open) return ( - ) diff --git a/packages/app/src/components/dialog-select-model-unpaid-v2.tsx b/packages/app/src/components/dialog-select-model-unpaid-v2.tsx index e63ee35a800..f130cee1a44 100644 --- a/packages/app/src/components/dialog-select-model-unpaid-v2.tsx +++ b/packages/app/src/components/dialog-select-model-unpaid-v2.tsx @@ -1,8 +1,8 @@ -import { DialogBody, DialogHeader, DialogTitle, DialogV2 } from "@opencode-ai/ui/v2/dialog-v2" -import { Icon } from "@opencode-ai/ui/v2/icon" +import { DialogBody, DialogHeader, DialogTitle, Dialog } from "@opencode-ai/ui/dialog" +import { Badge } from "@opencode-ai/ui/badge" +import { Icon } from "@opencode-ai/ui/icon" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" -import { Tag } from "@opencode-ai/ui/v2/badge-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { useDialog } from "@opencode-ai/ui/context/dialog" import { useTheme } from "@opencode-ai/ui/theme" import { createMemo, onCleanup, onMount, type Component, For, Show } from "solid-js" @@ -66,7 +66,7 @@ export const DialogSelectModelUnpaidV2: Component<{ model?: ModelState }> = (pro }) return ( - = (pro {(item) => ( - = (pro onClick={() => selectModel(item)} > {displayModelName(item.name)} - {language.t("model.tag.free")} + {language.t("model.tag.free")} - {language.t("model.tag.latest")} + {language.t("model.tag.latest")} - +
)} @@ -172,6 +172,6 @@ export const DialogSelectModelUnpaidV2: Component<{ model?: ModelState }> = (pro - + ) } diff --git a/packages/app/src/components/dialog-select-model-unpaid.tsx b/packages/app/src/components/dialog-select-model-unpaid.tsx index 00ca16cb666..d77b8640cc3 100644 --- a/packages/app/src/components/dialog-select-model-unpaid.tsx +++ b/packages/app/src/components/dialog-select-model-unpaid.tsx @@ -1,9 +1,9 @@ import { Button } from "@opencode-ai/ui/button" import { useDialog } from "@opencode-ai/ui/context/dialog" -import { Dialog } from "@opencode-ai/ui/dialog" +import { Dialog, DialogBody, DialogHeader, DialogTitle } from "@opencode-ai/ui/dialog" import { List, type ListRef } from "@opencode-ai/ui/list" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" -import { Tag } from "@opencode-ai/ui/tag" +import { Badge } from "@opencode-ai/ui/badge" import { Tooltip } from "@opencode-ai/ui/tooltip" import { type Component, Show } from "solid-js" import { useLocal } from "@/context/local" @@ -40,108 +40,113 @@ export const DialogSelectModelUnpaid: Component<{ model?: ModelState }> = (props } return ( - -
-
{language.t("dialog.model.unpaid.freeModels.title")}
- (listRef = ref)} - items={model.list} - current={model.current()} - key={(x) => `${x.provider.id}:${x.id}`} - itemWrapper={(item, node) => ( - - } - > - {node} - - )} - onSelect={(x) => { - model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { - recent: true, - }) - dialog.close() - }} - > - {(i) => ( -
- {i.name} - {language.t("model.tag.free")} - - {language.t("model.tag.latest")} - -
- )} -
-
-
-
-
-
{language.t("dialog.model.unpaid.addMore.title")}
-
- p.id} - items={providers.popular} - activeIcon="plus-small" - 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) - }} - onSelect={(x) => { - if (!x) return - connect(x.id) - }} + + + {language.t("dialog.model.select.title")} + + +
+
{language.t("dialog.model.unpaid.freeModels.title")}
+ (listRef = ref)} + items={model.list} + current={model.current()} + key={(x) => `${x.provider.id}:${x.id}`} + itemWrapper={(item, node) => ( + + } > - {(i) => ( -
- - {i.name} - -
{language.t("dialog.provider.opencode.tagline")}
-
- - {language.t("dialog.provider.tag.recommended")} - - - <> + {node} + + )} + onSelect={(x) => { + model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { + recent: true, + }) + dialog.close() + }} + > + {(i) => ( +
+ {i.name} + {language.t("model.tag.free")} + + {language.t("model.tag.latest")} + +
+ )} + +
+
+
+
+
{language.t("dialog.model.unpaid.addMore.title")}
+
+ p.id} + items={providers.popular} + activeIcon="plus-small" + 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) + }} + onSelect={(x) => { + if (!x) return + connect(x.id) + }} + > + {(i) => ( +
+ + {i.name} +
- {language.t("dialog.provider.opencodeGo.tagline")} + {language.t("dialog.provider.opencode.tagline")}
- {language.t("dialog.provider.tag.recommended")} - -
- -
{language.t("dialog.provider.anthropic.note")}
-
-
- )} -
- + + + {language.t("dialog.provider.tag.recommended")} + + + <> +
+ {language.t("dialog.provider.opencodeGo.tagline")} +
+ {language.t("dialog.provider.tag.recommended")} + +
+ +
{language.t("dialog.provider.anthropic.note")}
+
+
+ )} + + +
-
+
) } diff --git a/packages/app/src/components/dialog-select-model.tsx b/packages/app/src/components/dialog-select-model.tsx index d01ac91aa42..4ccca554b19 100644 --- a/packages/app/src/components/dialog-select-model.tsx +++ b/packages/app/src/components/dialog-select-model.tsx @@ -5,16 +5,14 @@ import { useLocal } from "@/context/local" import { useDialog } from "@opencode-ai/ui/context/dialog" import { popularProviders } from "@/hooks/use-providers" import { Button } from "@opencode-ai/ui/button" +import { Badge } from "@opencode-ai/ui/badge" +import { Dialog, DialogBody, DialogHeader, DialogTitle } from "@opencode-ai/ui/dialog" +import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { ScrollView } from "@opencode-ai/ui/scroll-view" -import { Tag } from "@opencode-ai/ui/tag" -import { Dialog } from "@opencode-ai/ui/dialog" import { List } from "@opencode-ai/ui/list" import { Tooltip } from "@opencode-ai/ui/tooltip" -import { Icon } from "@opencode-ai/ui/v2/icon" -import { Tag as TagV2 } from "@opencode-ai/ui/v2/badge-v2" -import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { Menu } from "@opencode-ai/ui/menu" import { ModelTooltip } from "./model-tooltip" import { useLanguage } from "@/context/language" import { decode64 } from "@/utils/base64" @@ -81,6 +79,7 @@ const ModelList: Component<{ }} itemWrapper={(item, node) => ( {i.name} - {language.t("model.tag.free")} + {language.t("model.tag.free")} - {language.t("model.tag.latest")} + {language.t("model.tag.latest")} )} @@ -193,21 +192,19 @@ export function ModelSelectorPopover(props: { class="p-1" action={
- + } variant="ghost" - iconSize="normal" class="size-6" aria-label={language.t("command.provider.connect")} onClick={handleConnectProvider} /> - + } variant="ghost" - iconSize="normal" class="size-6" aria-label={language.t("dialog.model.manage")} onClick={handleManage} @@ -373,10 +370,10 @@ function ModelSelectorPopoverV2View(props: { }) return ( - - - - + + + (contentRef = element)} class="w-[284px] overflow-hidden rounded-md border-0 bg-v2-background-bg-layer-01 !p-0 shadow-[var(--v2-elevation-floating)] focus:outline-none" onPointerDownOutside={dismiss.preventTriggerRestore} @@ -449,14 +446,14 @@ function ModelSelectorPopoverV2View(props: { > {(group) => ( - - + + {group.items[0].provider.name} - - + + {(item) => ( - } > - {item.name} - {language.t("model.tag.free")} + {language.t("model.tag.free")} - {language.t("model.tag.latest")} + {language.t("model.tag.latest")} - - + + )} - - + + )} @@ -502,7 +499,7 @@ function ModelSelectorPopoverV2View(props: {
- { @@ -513,11 +510,11 @@ function ModelSelectorPopoverV2View(props: { > {language.t("dialog.model.manage")} - +
- - - + + + ) } @@ -540,18 +537,19 @@ export const DialogSelectModel: Component<{ provider?: string; model?: ModelStat } return ( - + + {language.t("dialog.model.select.title")} - } - > - dialog.close()} /> - + + + dialog.close()} /> + + ) } diff --git a/packages/app/src/components/dialog-select-server.tsx b/packages/app/src/components/dialog-select-server.tsx index 3fb7b9ca357..5ac209de203 100644 --- a/packages/app/src/components/dialog-select-server.tsx +++ b/packages/app/src/components/dialog-select-server.tsx @@ -1,5 +1,6 @@ import { Button } from "@opencode-ai/ui/button" -import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" +import { Menu } from "@opencode-ai/ui/menu" +import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" import { List } from "@opencode-ai/ui/list" import { TextField } from "@opencode-ai/ui/text-field" @@ -156,49 +157,47 @@ export function ServerConnectionList(props: { />
- - + } variant="ghost" class="shrink-0 size-8 hover:bg-surface-base-hover data-[expanded]:bg-surface-base-active" onClick={(e: MouseEvent) => e.stopPropagation()} onPointerDown={(e: PointerEvent) => e.stopPropagation()} /> - - - + + { if (i.type !== "http") return props.onEdit(i) }} > - {language.t("dialog.server.menu.edit")} - + {language.t("dialog.server.menu.edit")} + - props.domain.defaults.set(key)}> - {language.t("dialog.server.menu.default")} - + props.domain.defaults.set(key)}> + {language.t("dialog.server.menu.default")} + - props.domain.defaults.set(null)}> - - {language.t("dialog.server.menu.defaultRemove")} - - + props.domain.defaults.set(null)}> + {language.t("dialog.server.menu.defaultRemove")} + - - + props.domain.connection.remove(key)} class="text-text-on-critical-base hover:bg-surface-critical-weak" > - {language.t("dialog.server.menu.delete")} - + {language.t("dialog.server.menu.delete")} + - - - + + +
@@ -208,7 +207,7 @@ export function ServerConnectionList(props: {
- + + + + + +
+
+ + +
-
+ ) } diff --git a/packages/app/src/components/file-tree-v2.tsx b/packages/app/src/components/file-tree-v2.tsx index 6fe2dd1bf67..eaa70693fd1 100644 --- a/packages/app/src/components/file-tree-v2.tsx +++ b/packages/app/src/components/file-tree-v2.tsx @@ -1,6 +1,6 @@ import { useFile } from "@/context/file" import { FileIcon } from "@opencode-ai/ui/file-icon" -import "@opencode-ai/ui/v2/file-tree-v2.css" +import "@opencode-ai/ui/file-tree.css" import { createEffect, createMemo, @@ -13,7 +13,7 @@ import { } from "solid-js" import { Dynamic } from "solid-js/web" import type { FileNode } from "@/types" -import { Icon } from "@opencode-ai/ui/v2/icon" +import { Icon } from "@opencode-ai/ui/icon" import { pathToFileUrl, withFileDragImage, type Kind } from "@/components/file-tree" import { createVirtualizer, defaultRangeExtractor } from "@tanstack/solid-virtual" import { diff --git a/packages/app/src/components/project-settings-extensions.tsx b/packages/app/src/components/project-settings-extensions.tsx index 35014b3c925..4c98b0e3204 100644 --- a/packages/app/src/components/project-settings-extensions.tsx +++ b/packages/app/src/components/project-settings-extensions.tsx @@ -1,6 +1,6 @@ import { Icon } from "@opencode-ai/ui/icon" -import { Switch } from "@opencode-ai/ui/v2/switch-v2" -import { TabsV2 } from "@opencode-ai/ui/v2/tabs-v2" +import { Switch } from "@opencode-ai/ui/switch" +import { Tabs } from "@opencode-ai/ui/tabs" import { type Component, For, Show, createEffect, createMemo, createResource, createSignal } from "solid-js" import { useLanguage } from "@/context/language" import { useMcpToggle } from "@/context/mcp" @@ -149,15 +149,15 @@ export const ProjectSettingsExtensions: Component = () => { {language.t("project.settings.extensions.description")}
- - - {language.t("settings.extensions.tab.mcps")} - {language.t("status.popover.tab.plugins")} - {language.t("settings.extensions.tab.skills")} + + + {language.t("settings.extensions.tab.mcps")} + {language.t("status.popover.tab.plugins")} + {language.t("settings.extensions.tab.skills")} {/* TODO: Restore LSP status when V2 exposes it. */} - + - +
{language.t("project.settings.extensions.added")} @@ -168,9 +168,9 @@ export const ProjectSettingsExtensions: Component = () => { {mcpRows(globalMcpNames())}
- + - +
{language.t("project.settings.extensions.added")} @@ -181,9 +181,9 @@ export const ProjectSettingsExtensions: Component = () => { {pluginRows(globalPlugins())}
- + - +
{language.t("project.settings.extensions.added")} @@ -196,8 +196,8 @@ export const ProjectSettingsExtensions: Component = () => { {skillRows(serverSkills())}
- - + +
) } diff --git a/packages/app/src/components/prompt-input-v2.tsx b/packages/app/src/components/prompt-input-v2.tsx index 994070f6d19..1a1620c8797 100644 --- a/packages/app/src/components/prompt-input-v2.tsx +++ b/packages/app/src/components/prompt-input-v2.tsx @@ -1,10 +1,10 @@ import { ImagePreview } from "@opencode-ai/ui/image-preview" import { useDialog } from "@opencode-ai/ui/context/dialog" import { ProviderIcon } from "@opencode-ai/ui/provider-icon" -import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" -import { Icon } from "@opencode-ai/ui/v2/icon" -import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { Keybind } from "@opencode-ai/ui/keybind" +import { Tooltip } from "@opencode-ai/ui/tooltip" import type { ReferenceInfo } from "@opencode-ai/client/promise" import { createEffect, createMemo, on, Show } from "solid-js" import { ModelSelectorPopoverV2 } from "@/components/dialog-select-model" @@ -503,20 +503,20 @@ function PromptInputV2ModelControl(props: { ) return ( - {props.title} - + } > {content()} - + } > ( - {content()} - + )} onClose={props.onClose} /> - + ) } diff --git a/packages/app/src/components/prompt-project-selector.tsx b/packages/app/src/components/prompt-project-selector.tsx index b84afdb56bf..7196c7d420b 100644 --- a/packages/app/src/components/prompt-project-selector.tsx +++ b/packages/app/src/components/prompt-project-selector.tsx @@ -9,10 +9,9 @@ import { type ComponentProps, } from "solid-js" import { createStore } from "solid-js/store" -import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" +import { Menu } from "@opencode-ai/ui/menu" import { Icon } from "@opencode-ai/ui/icon" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" -import { ProjectAvatar } from "@opencode-ai/ui/v2/project-avatar-v2" +import { ProjectAvatar } from "@opencode-ai/ui/project-avatar" import { getProjectAvatarVariant } from "@/context/layout" import { useLanguage } from "@/context/language" import { displayName, getProjectAvatarSource } from "@/pages/layout/helpers" @@ -277,7 +276,8 @@ export function PromptProjectSelector(props: { }) return ( - - - - + + 1} fallback={ - + {(project) => ( )} - + } > {server!.name}
- + project.server?.key === server!.key)} > @@ -389,7 +389,7 @@ export function PromptProjectSelector(props: { )} - +
)} @@ -408,8 +408,8 @@ export function PromptProjectSelector(props: { /> } > - - + props.controller.setActive(props.controller.actionKey())} > - + {props.controller.labels.add()} - - - - + + + {(server) => } - - - + + + - - - + + + ) } @@ -507,7 +506,7 @@ function ProjectItem(props: { }) { const key = () => props.controller.projectKey(props.project) return ( - - {displayName(props.project)} - - - - + {displayName(props.project)} + ) } @@ -552,7 +548,7 @@ function ProjectAction(props: { }) { const key = () => props.controller.actionKey(props.server) return ( - props.onSelect(props.server)} > - + {props.controller.labels.add()} - - + + ) } function ServerAction(props: { server: { key: string; name: string }; onSelect: (server: string) => void }) { return ( - props.onSelect(props.server.key)}> - {props.server.name} - + props.onSelect(props.server.key)}> + {props.server.name} + ) } diff --git a/packages/app/src/components/prompt-workspace-selector.tsx b/packages/app/src/components/prompt-workspace-selector.tsx index fe9ae4f7394..aea043b8205 100644 --- a/packages/app/src/components/prompt-workspace-selector.tsx +++ b/packages/app/src/components/prompt-workspace-selector.tsx @@ -1,7 +1,7 @@ import { createMemo, createSignal, For, Show } from "solid-js" -import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" -import { Icon } from "@opencode-ai/ui/v2/icon" +import { Menu } from "@opencode-ai/ui/menu" +import { Tooltip } from "@opencode-ai/ui/tooltip" +import { Icon } from "@opencode-ai/ui/icon" import { getFilename } from "@opencode-ai/util/path" import { useLanguage } from "@/context/language" import { sameDirectory } from "@/utils/workspace" @@ -58,7 +58,7 @@ export function PromptWorkspaceSelector(props: { return ( <> - - - + @@ -92,14 +92,14 @@ export function PromptWorkspaceSelector(props: { /> - - - - - {language.t("session.new.workspace.runIn")} - select("main")}> + + + + + {language.t("session.new.workspace.runIn")} + select("main")}> - {language.t("session.new.workspace.local")} - +
- - select("create")}> + + select("create")}> - {language.t("workspace.new")} - +
- - + + 0} fallback={ <> - - (pending = { type: "viewAll" })}> + + (pending = { type: "viewAll" })}> {language.t("common.viewAll")} - + } > - - + searchInput?.focus()) }} > - { if ( event.key === "ArrowRight" || @@ -181,9 +181,9 @@ export function PromptWorkspaceSelector(props: { {language.t("session.new.workspace.existing").replace(/(…|\.{3})$/, "")} - - - + + + = 10}>
@@ -211,27 +211,27 @@ export function PromptWorkspaceSelector(props: { {(workspace) => ( - select(workspace)}> + select(workspace)}> {getFilename(workspace)} - + )} - - (pending = { type: "viewAll" })}> + + (pending = { type: "viewAll" })}> {language.t("common.viewAll")} - - - - + + + + - - - - + + + + ) @@ -255,7 +255,7 @@ export function PromptGitStatus(props: { branch?: string; noGit?: boolean; from? return ( {(value) => ( - {value()}
- + )}
) diff --git a/packages/app/src/components/server/server-row-menu.tsx b/packages/app/src/components/server/server-row-menu.tsx index bf4eb2a7fc9..674da9f2445 100644 --- a/packages/app/src/components/server/server-row-menu.tsx +++ b/packages/app/src/components/server/server-row-menu.tsx @@ -1,6 +1,6 @@ -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Menu } from "@opencode-ai/ui/menu" import { type Component, Show } from "solid-js" import type { ServerActionsController } from "@/components/server/server-management-controller" import { useLanguage } from "@/context/language" @@ -59,19 +59,19 @@ export const ServerRowMenuView: Component<{ const builtin = () => ServerConnection.builtin(props.server) const httpServer = () => (props.server.type === "http" ? props.server : undefined) return ( - - + } + icon={} aria-label={props.labels.more} /> - - - - {props.labels.server} - + + + {props.labels.server} + { const server = httpServer() @@ -79,20 +79,20 @@ export const ServerRowMenuView: Component<{ }} > {props.labels.edit} - + - {props.labels.default} + {props.labels.default} - {props.labels.defaultRemove} + {props.labels.defaultRemove} - - {props.labels.delete} + + {props.labels.delete} - - - - + + +
+ ) } diff --git a/packages/app/src/components/server/server-row.tsx b/packages/app/src/components/server/server-row.tsx index 8bcf4db51ff..578c6959d30 100644 --- a/packages/app/src/components/server/server-row.tsx +++ b/packages/app/src/components/server/server-row.tsx @@ -64,6 +64,7 @@ export function ServerRow(props: ServerRowProps) { return ( ["placement"] + placement?: ComponentProps["placement"] } function ContextTooltipRow(props: { name: JSX.Element; value: JSX.Element }) { @@ -111,24 +110,21 @@ export function SessionContextUsage(props: SessionContextUsageProps) { const circle = () => (
) const circleV2 = () => (
- +
) @@ -145,11 +141,11 @@ export function SessionContextUsage(props: SessionContextUsageProps) { return ( - + {circle()} - +
) } diff --git a/packages/app/src/components/session-workspace-menu.tsx b/packages/app/src/components/session-workspace-menu.tsx index 7791ac261ab..c49207af049 100644 --- a/packages/app/src/components/session-workspace-menu.tsx +++ b/packages/app/src/components/session-workspace-menu.tsx @@ -1,5 +1,5 @@ -import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" -import { Icon } from "@opencode-ai/ui/v2/icon" +import { Menu } from "@opencode-ai/ui/menu" +import { Icon } from "@opencode-ai/ui/icon" import { getDirectory, getFilename } from "@opencode-ai/util/path" import { createStore } from "solid-js/store" import { createSignal, For, Show, type ComponentProps, type JSX } from "solid-js" @@ -17,7 +17,7 @@ export function SessionWorkspaceMenu(props: { sessionID: string project: Project directory: string - placement?: ComponentProps["placement"] + placement?: ComponentProps["placement"] gutter?: number class?: string contentClass?: string @@ -71,57 +71,57 @@ export function SessionWorkspaceMenu(props: { } return ( - - + {props.children} - - - - - {language.t("workspace.move.menu.title")} + + + + + {language.t("workspace.move.menu.title")} - void move(props.project.worktree)}> + void move(props.project.worktree)}> {language.t("session.new.workspace.local")} - + - void move("create")}> + void move("create")}> {language.t("workspace.new")} - + 0}> - - + + {language.t("session.new.workspace.existing").replace(/(…|\.{3})$/, "")} - - - + + + {(workspace) => ( - void move(workspace)}> + void move(workspace)}> {getFilename(workspace)} - + )} - - - + + + - - - openWorkspaces()}> + + + openWorkspaces()}> {language.t("common.viewAll")} - - - - + + + + ) } diff --git a/packages/app/src/components/session/open-in-app-v2.tsx b/packages/app/src/components/session/open-in-app-v2.tsx index e26ff2e0eab..79337673745 100644 --- a/packages/app/src/components/session/open-in-app-v2.tsx +++ b/packages/app/src/components/session/open-in-app-v2.tsx @@ -2,10 +2,9 @@ import { For, Show } from "solid-js" import { AppIcon } from "@opencode-ai/ui/app-icon" import { Icon } from "@opencode-ai/ui/icon" import { Spinner } from "@opencode-ai/ui/spinner" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" -import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" -import { SplitButtonV2, SplitButtonV2Action, SplitButtonV2MenuTrigger } from "@opencode-ai/ui/v2/split-button-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { Menu } from "@opencode-ai/ui/menu" +import { SplitButton, SplitButtonAction, SplitButtonMenuTrigger } from "@opencode-ai/ui/split-button" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { useLanguage } from "@/context/language" import { type OpenApp, useOpenInApp } from "@/components/session/open-in-app" @@ -15,13 +14,13 @@ export function OpenInAppV2(props: { directory: () => string }) { return ( - event.stopPropagation()}> - event.stopPropagation()}> + - event.stopPropagation()} onClick={(event) => { event.stopPropagation() @@ -34,28 +33,28 @@ export function OpenInAppV2(props: { directory: () => string }) { }> - - - + + state.setMenu("open", open)} > - event.stopPropagation()} > - - - - - - {language.t("session.header.openIn")} - + + + + + {language.t("session.header.openIn")} + { state.selectApp(value as OpenApp) @@ -63,7 +62,7 @@ export function OpenInAppV2(props: { directory: () => string }) { > {(option) => ( - { @@ -74,13 +73,13 @@ export function OpenInAppV2(props: { directory: () => string }) { > {option.label} - + )} - - - - + + + { state.setMenu("open", false) state.copyPath() @@ -88,11 +87,11 @@ export function OpenInAppV2(props: { directory: () => string }) { > {language.t("session.header.open.copyPath")} - - - - - + + + + + ) } diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index 2719f4c9faa..4f7b8a5ae0a 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -1,4 +1,3 @@ -import { Tooltip } from "@opencode-ai/ui/tooltip" import { createMemo, Show } from "solid-js" import { createMediaQuery } from "@solid-primitives/media" import { Portal } from "solid-js/web" @@ -7,10 +6,10 @@ import { useLanguage } from "@/context/language" import { useSettings } from "@/context/settings" import { useSessionLayout } from "@/pages/session/session-layout" import { StatusPopoverV2 } from "../status-popover" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" -import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Icon } from "@opencode-ai/ui/icon" +import { Keybind } from "@opencode-ai/ui/keybind" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { reviewTooltipKeybind } from "../command-tooltip-keybind" import { useTitlebarRightMount } from "../titlebar" @@ -60,24 +59,24 @@ function SessionHeaderV2Actions(props: { state: SessionHeaderV2ActionsState }) { return (
- + - {props.state.reviewLabel} 0}> - + } > - } + icon={} /> - +
) diff --git a/packages/app/src/components/session/session-sortable-tab-v2.tsx b/packages/app/src/components/session/session-sortable-tab-v2.tsx index a78c286cf03..edf1e55ecdb 100644 --- a/packages/app/src/components/session/session-sortable-tab-v2.tsx +++ b/packages/app/src/components/session/session-sortable-tab-v2.tsx @@ -1,9 +1,8 @@ import { createMemo, Show } from "solid-js" import type { JSX } from "solid-js" import { useSortable } from "@dnd-kit/solid/sortable" -import { IconButton } from "@opencode-ai/ui/icon-button" -import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { Keybind } from "@opencode-ai/ui/keybind" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { Tabs } from "@opencode-ai/ui/tabs" import { useFile } from "@/context/file" import { useLanguage } from "@/context/language" @@ -40,31 +39,29 @@ export function SortableTabV2(props: {
props.onTabClose(props.tab)} + onDblClick={() => props.onTabDoubleClick?.(props.tab)} closeButton={ - {language.t("common.closeTab")} 0}> - + } placement="bottom" gutter={10} > - props.onTabClose(props.tab)} aria-label={language.t("common.closeTab")} /> - + } hideCloseButton - onMiddleClick={() => props.onTabClose(props.tab)} - onDblClick={() => props.onTabDoubleClick?.(props.tab)} > {(value) => value()} diff --git a/packages/app/src/components/session/session-sortable-terminal-tab-v2.tsx b/packages/app/src/components/session/session-sortable-terminal-tab-v2.tsx index 2e66923bdd0..dc63bf08a51 100644 --- a/packages/app/src/components/session/session-sortable-terminal-tab-v2.tsx +++ b/packages/app/src/components/session/session-sortable-terminal-tab-v2.tsx @@ -2,9 +2,8 @@ import type { JSX } from "solid-js" import { Show, createEffect, onCleanup } from "solid-js" import { createStore } from "solid-js/store" import { useSortable } from "@dnd-kit/solid/sortable" -import { IconButton } from "@opencode-ai/ui/icon-button" import { Tabs } from "@opencode-ai/ui/tabs" -import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" +import { Menu } from "@opencode-ai/ui/menu" import { isDefaultTitle as isDefaultTerminalTitle } from "@/context/terminal-title" import { useTerminal, type LocalPTY } from "@/context/terminal" import { useLanguage } from "@/context/language" @@ -116,8 +115,8 @@ export function SortableTerminalTabV2(props: { terminal: LocalPTY; index: number return (
- - + + { @@ -131,20 +130,11 @@ export function SortableTerminalTabV2(props: { terminal: LocalPTY; index: number if (e.detail > 0) return focus() }} + onMiddleClick={close} closeButton={ - { - e.stopPropagation() - close() - }} - aria-label={language.t("terminal.close")} - /> + } hideCloseButton - onMiddleClick={close} >
- - - + + { if (!editRequested) return e.preventDefault() @@ -179,11 +169,11 @@ export function SortableTerminalTabV2(props: { terminal: LocalPTY; index: number requestAnimationFrame(() => edit()) }} > - (editRequested = true)}>{language.t("common.rename")} - {language.t("common.close")} - - - + (editRequested = true)}>{language.t("common.rename")} + {language.t("common.close")} + + +
) } diff --git a/packages/app/src/components/settings-keybinds.tsx b/packages/app/src/components/settings-keybinds.tsx index 3a504164368..aa08a8f0acf 100644 --- a/packages/app/src/components/settings-keybinds.tsx +++ b/packages/app/src/components/settings-keybinds.tsx @@ -1,9 +1,9 @@ import { For, Show, createMemo, lazy, onCleanup } from "solid-js" import { createStore } from "solid-js/store" import { makeEventListener } from "@solid-primitives/event-listener" -import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { Button } from "@opencode-ai/ui/button" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { TextInput } from "@opencode-ai/ui/text-input" import { showToast } from "@/utils/toast" import fuzzysort from "fuzzysort" import { DEFAULT_PALETTE_KEYBIND, formatKeybind, parseKeybind, useCommand } from "@/context/command" @@ -11,7 +11,7 @@ import { useLanguage } from "@/context/language" import { useSettings } from "@/context/settings" import { SettingsListV2 } from "./settings-v2/parts/list" -const IconV2 = lazy(() => import("@opencode-ai/ui/v2/icon").then((module) => ({ default: module.Icon }))) +const Icon = lazy(() => import("@opencode-ai/ui/icon").then((module) => ({ default: module.Icon }))) const IS_MAC = typeof navigator === "object" && /(Mac|iPod|iPhone|iPad)/.test(navigator.platform) const PALETTE_ID = "command.palette" @@ -387,12 +387,12 @@ function SettingsKeybindsV2View(props: {

{language.t("settings.shortcuts.title")}

{language.t("settings.shortcuts.description")} - + )} @@ -226,14 +226,14 @@ export const SettingsProvidersV2: Component<{
{language.t("provider.custom.title")} - {language.t("settings.providers.tag.custom")} + {language.t("settings.providers.tag.custom")}

{language.t("settings.providers.custom.description")}

- {language.t("common.connect")} - + diff --git a/packages/app/src/components/settings-v2/servers.tsx b/packages/app/src/components/settings-v2/servers.tsx index 748c477f9ec..4fb8c0b97bb 100644 --- a/packages/app/src/components/settings-v2/servers.tsx +++ b/packages/app/src/components/settings-v2/servers.tsx @@ -1,7 +1,7 @@ -import { Tag } from "@opencode-ai/ui/v2/badge-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { TextInputV2 } from "@opencode-ai/ui/v2/text-input-v2" +import { Badge } from "@opencode-ai/ui/badge" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { TextInput } from "@opencode-ai/ui/text-input" import { useDialog } from "@opencode-ai/ui/context/dialog" import fuzzysort from "fuzzysort" import { type Component, For, Show, createMemo } from "solid-js" @@ -61,7 +61,7 @@ export const SettingsServersV2: Component = () => {
- {language.t("dialog.server.status.default")} + {language.t("dialog.server.status.default")}
diff --git a/packages/app/src/components/settings-v2/settings-v2.css b/packages/app/src/components/settings-v2/settings-v2.css index 1aa382803a7..880c13ba9ba 100644 --- a/packages/app/src/components/settings-v2/settings-v2.css +++ b/packages/app/src/components/settings-v2/settings-v2.css @@ -1,5 +1,5 @@ -@import "@opencode-ai/ui/v2/text-input-v2.css"; -@import "@opencode-ai/ui/v2/button-v2.css"; +@import "@opencode-ai/ui/text-input.css"; +@import "@opencode-ai/ui/button.css"; [data-component="tabs-v2"][data-variant="settings"] { height: 100%; diff --git a/packages/app/src/components/settings-v2/workspaces.tsx b/packages/app/src/components/settings-v2/workspaces.tsx index edcc6dbc4fb..60776d61a12 100644 --- a/packages/app/src/components/settings-v2/workspaces.tsx +++ b/packages/app/src/components/settings-v2/workspaces.tsx @@ -3,12 +3,12 @@ import { For, Show, createMemo } from "solid-js" import { createStore } from "solid-js/store" import type { SessionInfo } from "@opencode-ai/client/promise" import { useQuery } from "@tanstack/solid-query" -import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" -import { Dialog, DialogFooter, DialogHeader, DialogTitleGroup } from "@opencode-ai/ui/v2/dialog-v2" -import { Icon } from "@opencode-ai/ui/v2/icon" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { Button } from "@opencode-ai/ui/button" +import { Dialog, DialogFooter, DialogHeader, DialogTitleGroup } from "@opencode-ai/ui/dialog" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Menu } from "@opencode-ai/ui/menu" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { useDialog } from "@opencode-ai/ui/context/dialog" import { getFilename } from "@opencode-ai/util/path" import { useLanguage } from "@/context/language" @@ -273,33 +273,33 @@ export const SettingsWorkspacesV2: Component<{ activeDirectory?: string }> = (pr
1}> - - + + {projectOptions().find((option) => option.id === selectedProject())?.label} - - - + + + {(option) => ( - setStore("project", option.id)}> + setStore("project", option.id)}> {option.label} - + )} - - - + + + 0}> - - + = (pr disabled={!!store.transaction} icon={} /> - - - + + + {language.t("settings.workspaces.deleteAll")} - - - - + + + +
@@ -335,7 +335,7 @@ export const SettingsWorkspacesV2: Component<{ activeDirectory?: string }> = (pr
- = (pr > {workspace.directory} - +
{sessionCount(workspace)}
{(value) => ( - + {value()} - + )} - - dialog.close()}> + + ) @@ -486,17 +483,17 @@ function DialogDeleteWorkspace(props: { /> - dialog.close()}> + ) diff --git a/packages/app/src/components/status-popover-body.tsx b/packages/app/src/components/status-popover-body.tsx index d17acb0ab05..79a1f4a0414 100644 --- a/packages/app/src/components/status-popover-body.tsx +++ b/packages/app/src/components/status-popover-body.tsx @@ -48,10 +48,9 @@ export function StatusPopoverBody(props: { shown: boolean }) { @@ -111,6 +110,7 @@ export function StatusPopoverBody(props: { shown: boolean }) {
event.stopPropagation()}> { diff --git a/packages/app/src/components/status-popover.tsx b/packages/app/src/components/status-popover.tsx index 8c3b2e134ce..3950d0a4828 100644 --- a/packages/app/src/components/status-popover.tsx +++ b/packages/app/src/components/status-popover.tsx @@ -1,7 +1,6 @@ import { Button } from "@opencode-ai/ui/button" import { Icon } from "@opencode-ai/ui/icon" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" import { Popover } from "@opencode-ai/ui/popover" import { Suspense, createMemo, createSignal, lazy, Show, type JSX } from "solid-js" import { useLanguage } from "@/context/language" @@ -157,7 +156,7 @@ function StatusPopoverView(props: { state: StatusPopoverState }) { - +
diff --git a/packages/app/src/components/titlebar-tab-nav.tsx b/packages/app/src/components/titlebar-tab-nav.tsx index a64aec6687f..51d0644f496 100644 --- a/packages/app/src/components/titlebar-tab-nav.tsx +++ b/packages/app/src/components/titlebar-tab-nav.tsx @@ -2,8 +2,8 @@ import { createEffect, createMemo, createSignal, onCleanup, Show, type Ref } fro import { makeEventListener } from "@solid-primitives/event-listener" import { createResizeObserver } from "@solid-primitives/resize-observer" import { createMutation } from "@tanstack/solid-query" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Icon } from "@opencode-ai/ui/icon" import { useGlobal, useServerCtx } from "@/context/global" import { useLanguage } from "@/context/language" import { ServerConnection, serverName, useServers } from "@/context/servers" @@ -281,7 +281,7 @@ export function TabNavItem(props: {
- } + icon={} />
@@ -377,7 +377,7 @@ export function DraftTabItem(props: { class="flex h-full min-w-0 flex-1 flex-row items-center gap-1.5 text-[13px] font-medium text-v2-text-text-faint group-data-[active='true']:text-v2-text-text-base [-webkit-user-drag:none]" > - +
- { @@ -400,7 +400,7 @@ export function DraftTabItem(props: { }} class="hover-reveal relative z-10 group-hover:opacity-100 group-data-[active=true]:opacity-100 group-data-[editing=true]:opacity-100" onClick={closeTab} - icon={} + icon={} aria-label={language.t("common.closeTab")} />
diff --git a/packages/app/src/components/titlebar.tsx b/packages/app/src/components/titlebar.tsx index 796ccd88aee..f52393e3706 100644 --- a/packages/app/src/components/titlebar.tsx +++ b/packages/app/src/components/titlebar.tsx @@ -12,10 +12,10 @@ import { } from "solid-js" import { createStore } from "solid-js/store" import { useLocation, useNavigate } from "@solidjs/router" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" -import { KeybindV2 } from "@opencode-ai/ui/v2/keybind-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Icon } from "@opencode-ai/ui/icon" +import { Keybind } from "@opencode-ai/ui/keybind" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { LayoutRoute, useLayout } from "@/context/layout" import { usePlatform } from "@/context/platform" @@ -330,28 +330,28 @@ export function Titlebar(props: { update?: TitlebarUpdate; debugTools?: { visibl - {language.t("home.title")} - + } class="shrink-0" > - } + icon={} state={layout.route().type === "home" ? "pressed" : undefined} onClick={toggleHome} aria-label={language.t("home.title")} aria-pressed={layout.route().type === "home"} /> - + tabsStoreActions.reorder(keys)} /> - {language.t("command.session.new")} - + } > - } + icon={} onClick={openNewTab} aria-label={language.t("command.session.new")} /> - +
diff --git a/packages/app/src/components/windows-app-menu.tsx b/packages/app/src/components/windows-app-menu.tsx index e6d89dde422..a33aa94ef6e 100644 --- a/packages/app/src/components/windows-app-menu.tsx +++ b/packages/app/src/components/windows-app-menu.tsx @@ -1,8 +1,7 @@ -import { For, Show, type JSX } from "solid-js" -import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu" +import { For, type JSX } from "solid-js" +import { Menu } from "@opencode-ai/ui/menu" import { Icon } from "@opencode-ai/ui/icon" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" import { useCommand } from "@/context/command" import { DESKTOP_MENU, desktopMenuVisible, type DesktopMenuAction, type DesktopMenuEntry } from "@/desktop-menu" @@ -47,32 +46,32 @@ export function WindowsAppMenu(props: { } return ( - +
- } + icon={} aria-label={language.t("desktop.menu.ariaLabel")} onPointerDown={rememberFocus} onKeyDown={rememberFocus} />
- - - - OpenCode + + + + OpenCode desktopMenuVisible(menu, "windows"))}> {(menu) => ( desktopMenuVisible(entry, "windows"))}> {(entry) => { // Static menu data: an early return keeps the union narrowing a Show fallback would lose. - if (entry.type === "separator") return + if (entry.type === "separator") return return ( )} - - - - + + + +
) } function DesktopMenuSubmenu(props: { label: string; children: JSX.Element }) { return ( - - - {props.label} - - - - - - {props.children} - - + + {props.label} + + {props.children} + + ) } function DesktopMenuItem(props: { label: string; keybind?: string; disabled?: boolean; onSelect: () => void }) { return ( - - {props.label} - - {props.keybind} - - + + {props.label} + ) } diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx index 4fb52c067e8..442392b09d8 100644 --- a/packages/app/src/context/layout.tsx +++ b/packages/app/src/context/layout.tsx @@ -11,7 +11,7 @@ import { decode64 } from "@/utils/base64" import { same } from "@/utils/same" import { createScrollPersistence, type SessionScroll } from "./layout-scroll" import { createPathHelpers } from "./file/path" -import type { ProjectAvatarVariant } from "@opencode-ai/ui/v2/project-avatar-v2" +import type { ProjectAvatarVariant } from "@opencode-ai/ui/project-avatar" import { SessionStateKey } from "@/utils/server-scope" import { createSessionKeyReader, ensureSessionKey, pruneSessionKeys } from "./layout-helpers" import { requireServerKey } from "@/utils/session-route" diff --git a/packages/app/src/index.css b/packages/app/src/index.css index 5ccd718e6cb..357e47bd937 100644 --- a/packages/app/src/index.css +++ b/packages/app/src/index.css @@ -1,6 +1,6 @@ @import "@opencode-ai/ui/styles/tailwind"; @import "@opencode-ai/session-ui/styles"; -@import "@opencode-ai/ui/v2/styles/tailwind.css"; +@import "@opencode-ai/ui/styles/tokens"; @import "tw-animate-css"; @font-face { @@ -30,23 +30,22 @@ container-name: getting-started; } - [data-component="dropdown-menu-content"].desktop-app-menu, - [data-component="dropdown-menu-sub-content"].desktop-app-menu { + [data-component="menu-v2-content"].desktop-app-menu { min-width: 160px; padding: 2px; } - [data-component="dropdown-menu-content"].desktop-app-menu { + [data-component="menu-v2-content"].desktop-app-menu:not(.desktop-app-menu-sub) { width: 160px; } - [data-component="dropdown-menu-sub-content"].desktop-app-menu { + [data-component="menu-v2-content"].desktop-app-menu-sub { width: max-content; min-width: 240px; max-width: min(320px, calc(100vw - 24px)); } - [data-component="dropdown-menu-content"].desktop-app-menu [data-slot="dropdown-menu-group-label"] { + [data-component="menu-v2-content"].desktop-app-menu [data-slot="menu-v2-group-label"] { display: flex; align-items: center; height: 28px; @@ -57,10 +56,7 @@ color: var(--text-weak); } - [data-component="dropdown-menu-content"].desktop-app-menu [data-slot="dropdown-menu-item"], - [data-component="dropdown-menu-content"].desktop-app-menu [data-slot="dropdown-menu-sub-trigger"], - [data-component="dropdown-menu-sub-content"].desktop-app-menu [data-slot="dropdown-menu-item"], - [data-component="dropdown-menu-sub-content"].desktop-app-menu [data-slot="dropdown-menu-sub-trigger"] { + [data-component="menu-v2-content"].desktop-app-menu [data-component="menu-v2-item"] { min-height: 28px; padding: 0 12px; gap: 8px; @@ -68,12 +64,11 @@ line-height: 1; } - [data-component="dropdown-menu-content"].desktop-app-menu [data-slot="dropdown-menu-item-label"], - [data-component="dropdown-menu-sub-content"].desktop-app-menu [data-slot="dropdown-menu-item-label"] { + [data-component="menu-v2-content"].desktop-app-menu [data-slot="menu-v2-item-content"] { white-space: nowrap; } - [data-slot="desktop-app-menu-keybind"] { + [data-component="menu-v2-content"].desktop-app-menu [data-slot="menu-v2-item-shortcut"] { margin-left: auto; color: var(--text-weak); font-size: var(--font-size-x-small); @@ -81,19 +76,13 @@ white-space: nowrap; } - [data-slot="desktop-app-menu-chevron"] { - display: flex; - margin-left: auto; - color: var(--icon-base); - } - [data-component="getting-started-actions"] { display: flex; flex-direction: column; gap: 0.75rem; /* gap-3 */ } - [data-component="getting-started-actions"] > [data-component="button"] { + [data-component="getting-started-actions"] > [data-component="button-v2"] { width: 100%; } @@ -103,7 +92,7 @@ align-items: center; } - [data-component="getting-started-actions"] > [data-component="button"] { + [data-component="getting-started-actions"] > [data-component="button-v2"] { width: auto; } } diff --git a/packages/app/src/pages/home/home-projects-view.tsx b/packages/app/src/pages/home/home-projects-view.tsx index a4e99b877a1..bed8a27b83b 100644 --- a/packages/app/src/pages/home/home-projects-view.tsx +++ b/packages/app/src/pages/home/home-projects-view.tsx @@ -6,11 +6,11 @@ import { AutoScroller, Feedback, PointerActivationConstraints } from "@dnd-kit/d import { RestrictToVerticalAxis } from "@dnd-kit/abstract/modifiers" import { RestrictToElement } from "@dnd-kit/dom/modifiers" import { ScrollView } from "@opencode-ai/ui/scroll-view" -import { ProjectAvatar } from "@opencode-ai/ui/v2/project-avatar-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { MenuV2 } from "@opencode-ai/ui/v2/menu-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { ProjectAvatar } from "@opencode-ai/ui/project-avatar" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Menu } from "@opencode-ai/ui/menu" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { getProjectAvatarVariant, type HomeProjectSelection, type LocalProject } from "@/context/layout" import { ServerConnection } from "@/context/servers" import { useLanguage } from "@/context/language" @@ -82,18 +82,18 @@ export function HomeProjectsView(props: HomeProjectsViewProps) {
{props.language.t("home.projects")}
0)}> - - + } + icon={} disabled={props.serverHealth(props.servers[0])?.healthy === false} onClick={() => props.onChooseProject(props.servers[0])} aria-label={props.language.t("home.project.add")} /> - +
@@ -161,7 +161,7 @@ export function HomeUtilityNav(props: { class="text-v2-text-text-faint [&>[data-slot=icon-svg]]:text-v2-icon-icon-muted" onClick={props.onOpenSettings} > - + {props.language.t("sidebar.settings")} - + {props.language.t("sidebar.help")}
@@ -234,7 +234,7 @@ function HomeServerRow(props: { }} onPointerDown={(event) => event.preventDefault()} > - props.onSetContextMenuOpen(contextMenuID(), open)} /> - - + } + icon={} aria-label={props.language.t("home.project.add")} disabled={props.health?.healthy === false} onClick={() => props.onChooseProject(props.server)} /> - +
) @@ -394,7 +394,7 @@ function HomeProjectEmpty( disabled={unreachable()} onClick={() => props.onChooseProject(props.server)} > - + {props.language.t("home.project.add")} 0}> @@ -423,7 +423,7 @@ function HomeRecentlyClosedRow( return worktree } return ( - + {displayName(props.project)} - + ) } @@ -523,55 +523,55 @@ function HomeProjectRow( `} data-menu={props.contextMenuOpen(contextMenuID())} > - props.onSetContextMenuOpen(contextMenuID(), open)} > - } + icon={} aria-label={props.language.t("common.moreOptions")} /> - - - props.onOpenProjectNewSession(props.server, props.project.worktree)}> + + + props.onOpenProjectNewSession(props.server, props.project.worktree)}> {props.language.t("command.session.new")} - - props.onEditProject(props.server, props.project)}> + + props.onEditProject(props.server, props.project)}> {props.language.t("dialog.project.edit.title")} - + - props.onRevealProject(props.server, props.project)}> + props.onRevealProject(props.server, props.project)}> {props.language.t( fileManagerApp(platform.platform === "desktop" ? (platform.os ?? "unknown") : "unknown") .actionLabel, )} - + - props.onClearNotifications(props.server, props.project)} > {props.language.t("sidebar.project.clearNotifications")} - - - props.onCloseProject(props.server, props.project.worktree)}> + + + props.onCloseProject(props.server, props.project.worktree)}> {props.language.t("common.close")} - - - - - + + + + } + icon={} aria-label={props.language.t("command.session.new")} onClick={() => props.onOpenProjectNewSession(props.server, props.project.worktree)} /> diff --git a/packages/app/src/pages/home/home-sessions-view.tsx b/packages/app/src/pages/home/home-sessions-view.tsx index 1d6133ba81a..1b3c64b15eb 100644 --- a/packages/app/src/pages/home/home-sessions-view.tsx +++ b/packages/app/src/pages/home/home-sessions-view.tsx @@ -2,10 +2,10 @@ import type { SessionInfo } from "@opencode-ai/client/promise" import { createMemo, For, Show, Suspense } from "solid-js" import { Spinner } from "@opencode-ai/ui/spinner" import { ScrollView } from "@opencode-ai/ui/scroll-view" -import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" -import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon" -import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" +import { Button } from "@opencode-ai/ui/button" +import { Icon } from "@opencode-ai/ui/icon" +import { IconButton } from "@opencode-ai/ui/icon-button" +import { Tooltip } from "@opencode-ai/ui/tooltip" import { useLanguage } from "@/context/language" import { ServerConnection } from "@/context/servers" import { SessionTabAvatarView } from "@/pages/layout/session-tab-avatar" @@ -83,7 +83,7 @@ export function HomeSessionsView(props: HomeSessionsViewProps) { 0 && props.canCreateSession}>
- {props.language.t("command.session.new")} - +
@@ -273,7 +273,7 @@ function HomeSessionSearch(props: HomeSessionsViewProps) { duration-[120ms] ease-in-out hover:bg-v2-background-bg-layer-02 focus-within:bg-v2-background-bg-layer-02 `} > - + - } + icon={} aria-label={props.searchPlaceholder} onClick={() => { props.onSearchClose() @@ -458,12 +458,12 @@ function HomeSessionRow(props: HomeSessionsViewProps & { record: HomeSessionReco group-hover/session:opacity-100 focus-within:opacity-100 `} > - - + } + icon={} aria-label={props.language.t("common.archive")} onClick={(event) => { event.preventDefault() @@ -471,7 +471,7 @@ function HomeSessionRow(props: HomeSessionsViewProps & { record: HomeSessionReco void props.onArchiveSession(props.record.session) }} /> - + @@ -525,9 +525,9 @@ function HomeSessionsEmpty(props: { onNewSession?: () => void; language: ReturnT

{(onNewSession) => ( - + )} diff --git a/packages/app/src/pages/layout/session-tab-avatar.tsx b/packages/app/src/pages/layout/session-tab-avatar.tsx index 8a8ef28a5a3..2e1b820bd4e 100644 --- a/packages/app/src/pages/layout/session-tab-avatar.tsx +++ b/packages/app/src/pages/layout/session-tab-avatar.tsx @@ -1,9 +1,8 @@ -import type { LocalProject } from "@/context/layout" -import { getProjectAvatarVariant } from "@/context/layout" +import { getProjectAvatarVariant, type LocalProject } from "@/context/layout" import type { ServerConnection } from "@/context/servers" import { displayName, getProjectAvatarSource } from "@/pages/layout/helpers" import { useSessionTabAvatarState } from "@/pages/layout/project-avatar-state" -import { ProjectAvatar } from "@opencode-ai/ui/v2/project-avatar-v2" +import { ProjectAvatar } from "@opencode-ai/ui/project-avatar" import { SessionProgressIndicatorV2 } from "@opencode-ai/session-ui/v2/session-progress-indicator-v2" import { Show } from "solid-js" diff --git a/packages/app/src/pages/new-session/new-session-view.tsx b/packages/app/src/pages/new-session/new-session-view.tsx index 86f523642d8..6cd73f4ae1b 100644 --- a/packages/app/src/pages/new-session/new-session-view.tsx +++ b/packages/app/src/pages/new-session/new-session-view.tsx @@ -1,8 +1,7 @@ import { useDialog } from "@opencode-ai/ui/context/dialog" import { Tooltip } from "@opencode-ai/ui/tooltip" -import { Icon } from "@opencode-ai/ui/v2/icon" -import { TooltipV2 } from "@opencode-ai/ui/v2/tooltip-v2" -import { WordmarkV2 } from "@opencode-ai/ui/v2/wordmark-v2" +import { Icon } from "@opencode-ai/ui/icon" +import { Wordmark } from "@opencode-ai/ui/wordmark" import { Show, createMemo, createSignal } from "solid-js" import { createStore } from "solid-js/store" import { Portal } from "solid-js/web" @@ -47,7 +46,7 @@ export function NewSessionView(props: { >
- +
@@ -96,7 +95,7 @@ export function NewSessionStatus(props: { mount: HTMLElement | null; visible: bo {(mount) => ( - + @@ -153,7 +152,7 @@ function ProviderTip() { - - +
diff --git a/packages/app/src/pages/new-session/use-new-session-commands.tsx b/packages/app/src/pages/new-session/use-new-session-commands.tsx index a0d835f97f5..342dc7a0856 100644 --- a/packages/app/src/pages/new-session/use-new-session-commands.tsx +++ b/packages/app/src/pages/new-session/use-new-session-commands.tsx @@ -21,8 +21,8 @@ export function useNewSessionCommands(input: { title: language.t("command.palette"), hidden: true, onSelect: async () => { - const { DialogSelectFile } = await import("@/components/dialog-select-file") - void dialog.show(() => ) + const { DialogCommandPaletteV2 } = await import("@/components/dialog-command-palette-v2") + void dialog.show(() => ) }, }, { diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 0b3405996a7..1f7402427bf 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -30,10 +30,9 @@ import { createStore } from "solid-js/store" import type { SessionReviewLineComment } from "@opencode-ai/session-ui/session-review" import { ResizeHandle } from "@opencode-ai/ui/resize-handle" import { Select } from "@opencode-ai/ui/select" -import { SelectV2 } from "@opencode-ai/ui/v2/select-v2" import { isScrollKeyTarget, scrollKey, scrollKeyOwner } from "@opencode-ai/ui/scroll-view" import { Tabs } from "@opencode-ai/ui/tabs" -import { ButtonV2 } from "@opencode-ai/ui/v2/button-v2" +import { Button } from "@opencode-ai/ui/button" import { createAutoScroll } from "@opencode-ai/ui/hooks" import { previewSelectedLines } from "@opencode-ai/session-ui/pierre/selection-bridge" import { showToast } from "@/utils/toast" @@ -195,9 +194,9 @@ function SessionErrorFallback(props: { error: unknown; sessionID?: string; serve
)}
- + ) @@ -1039,25 +1038,6 @@ export default function Page() { return ( + + {local.icon || ( )} - - + +
- + + - {local.description} + {local.description} - +
- + ) } diff --git a/packages/ui/src/v2/components/field-v2.css b/packages/ui/src/forms/field/field.css similarity index 100% rename from packages/ui/src/v2/components/field-v2.css rename to packages/ui/src/forms/field/field.css diff --git a/packages/ui/src/v2/components/field-v2.stories.tsx b/packages/ui/src/forms/field/field.stories.tsx similarity index 80% rename from packages/ui/src/v2/components/field-v2.stories.tsx rename to packages/ui/src/forms/field/field.stories.tsx index 2bc5fd252ae..5b065dd830b 100644 --- a/packages/ui/src/v2/components/field-v2.stories.tsx +++ b/packages/ui/src/forms/field/field.stories.tsx @@ -1,12 +1,12 @@ // @ts-nocheck import { createSignal } from "solid-js" -import { Field } from "./field-v2" -import { InlineInputV2 } from "./inline-input-v2" -import { TextInputV2 } from "./text-input-v2" -import { TextareaV2 } from "./textarea-v2" +import { Field } from "./field" +import { InlineInput } from "@opencode-ai/ui/inline-input" +import { TextInput } from "@opencode-ai/ui/text-input" +import { Textarea } from "@opencode-ai/ui/textarea" const docs = `### Overview -Composable field layout for TextInput, Textarea, and InlineInput v2. +Composable field layout for TextInput, Textarea, and InlineInput. ### Usage \`\`\`tsx @@ -14,7 +14,7 @@ Composable field layout for TextInput, Textarea, and InlineInput v2. Label Prefix - + Suffix @@ -30,8 +30,8 @@ Omit \`Field.Control\` and place the input directly inside \`Field\` — a11y pr ` export default { - title: "UI V2/Field", - id: "components-field-v2", + title: "UI/Field", + id: "ui-field", subcomponents: { Label: Field.Label, Prefix: Field.Prefix, @@ -57,7 +57,7 @@ export const TextInputExample = { Label Prefix - + Suffix @@ -71,7 +71,7 @@ export const TextInputDirectChild = { Label Prefix - + Suffix @@ -84,7 +84,7 @@ export const TextareaExample = { Label Prefix - +