summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/components/basic-tool.tsx
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-10-30 13:49:29 -0500
committerAdam <[email protected]>2025-10-30 13:49:29 -0500
commitdc6e54503cb400ea2533740c9a92d09c8a50d077 (patch)
tree7abad7c0275fe646395a2f4f44d90e5f4a48dbe0 /packages/ui/src/components/basic-tool.tsx
parent2a0b67d84f048207d20d952cafa10c430451dc70 (diff)
downloadopencode-dc6e54503cb400ea2533740c9a92d09c8a50d077.tar.gz
opencode-dc6e54503cb400ea2533740c9a92d09c8a50d077.zip
wip: desktop work
Diffstat (limited to 'packages/ui/src/components/basic-tool.tsx')
-rw-r--r--packages/ui/src/components/basic-tool.tsx95
1 files changed, 95 insertions, 0 deletions
diff --git a/packages/ui/src/components/basic-tool.tsx b/packages/ui/src/components/basic-tool.tsx
new file mode 100644
index 000000000..43574fbb7
--- /dev/null
+++ b/packages/ui/src/components/basic-tool.tsx
@@ -0,0 +1,95 @@
+import { children, For, Match, Show, Switch, type JSX } from "solid-js"
+import { Collapsible } from "./collapsible"
+import { Icon, IconProps } from "./icon"
+
+export type TriggerTitle = {
+ title: string
+ titleClass?: string
+ subtitle?: string
+ subtitleClass?: string
+ args?: string[]
+ argsClass?: string
+ action?: JSX.Element
+}
+
+const isTriggerTitle = (val: any): val is TriggerTitle => {
+ return typeof val === "object" && val !== null && "title" in val && !(val instanceof Node)
+}
+
+export interface BasicToolProps {
+ icon: IconProps["name"]
+ trigger: TriggerTitle | JSX.Element
+ children?: JSX.Element
+ hideDetails?: boolean
+}
+
+export function BasicTool(props: BasicToolProps) {
+ const resolved = children(() => props.children)
+ return (
+ <Collapsible>
+ <Collapsible.Trigger>
+ <div data-component="tool-trigger">
+ <div data-slot="tool-trigger-content">
+ <Icon name={props.icon} size="small" data-slot="tool-icon" />
+ <div data-slot="tool-info">
+ <Switch>
+ <Match when={isTriggerTitle(props.trigger) && props.trigger}>
+ {(trigger) => (
+ <div data-slot="tool-info-structured">
+ <div data-slot="tool-info-main">
+ <span
+ data-slot="tool-title"
+ classList={{
+ [trigger().titleClass ?? ""]: !!trigger().titleClass,
+ }}
+ >
+ {trigger().title}
+ </span>
+ <Show when={trigger().subtitle}>
+ <span
+ data-slot="tool-subtitle"
+ classList={{
+ [trigger().subtitleClass ?? ""]: !!trigger().subtitleClass,
+ }}
+ >
+ {trigger().subtitle}
+ </span>
+ </Show>
+ <Show when={trigger().args?.length}>
+ <For each={trigger().args}>
+ {(arg) => (
+ <span
+ data-slot="tool-arg"
+ classList={{
+ [trigger().argsClass ?? ""]: !!trigger().argsClass,
+ }}
+ >
+ {arg}
+ </span>
+ )}
+ </For>
+ </Show>
+ </div>
+ <Show when={trigger().action}>{trigger().action}</Show>
+ </div>
+ )}
+ </Match>
+ <Match when={true}>{props.trigger as JSX.Element}</Match>
+ </Switch>
+ </div>
+ </div>
+ <Show when={resolved() && !props.hideDetails}>
+ <Collapsible.Arrow />
+ </Show>
+ </div>
+ </Collapsible.Trigger>
+ <Show when={resolved() && !props.hideDetails}>
+ <Collapsible.Content>{resolved()}</Collapsible.Content>
+ </Show>
+ </Collapsible>
+ )
+}
+
+export function GenericTool(props: { tool: string; hideDetails?: boolean }) {
+ return <BasicTool icon="mcp" trigger={{ title: props.tool }} hideDetails={props.hideDetails} />
+}