| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- import { createEffect, createSignal, 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 && (typeof Node === "undefined" || !(val instanceof Node))
- )
- }
- export interface BasicToolProps {
- icon: IconProps["name"]
- trigger: TriggerTitle | JSX.Element
- children?: JSX.Element
- hideDetails?: boolean
- defaultOpen?: boolean
- forceOpen?: boolean
- locked?: boolean
- onSubtitleClick?: () => void
- }
- export function BasicTool(props: BasicToolProps) {
- const [open, setOpen] = createSignal(props.defaultOpen ?? false)
- createEffect(() => {
- if (props.forceOpen) setOpen(true)
- })
- const handleOpenChange = (value: boolean) => {
- if (props.locked && !value) return
- setOpen(value)
- }
- return (
- <Collapsible open={open()} onOpenChange={handleOpenChange}>
- <Collapsible.Trigger>
- <div data-component="tool-trigger">
- <div data-slot="basic-tool-tool-trigger-content">
- <Icon name={props.icon} size="small" />
- <div data-slot="basic-tool-tool-info">
- <Switch>
- <Match when={isTriggerTitle(props.trigger) && props.trigger}>
- {(trigger) => (
- <div data-slot="basic-tool-tool-info-structured">
- <div data-slot="basic-tool-tool-info-main">
- <span
- data-slot="basic-tool-tool-title"
- classList={{
- [trigger().titleClass ?? ""]: !!trigger().titleClass,
- }}
- >
- {trigger().title}
- </span>
- <Show when={trigger().subtitle}>
- <span
- data-slot="basic-tool-tool-subtitle"
- classList={{
- [trigger().subtitleClass ?? ""]: !!trigger().subtitleClass,
- clickable: !!props.onSubtitleClick,
- }}
- onClick={(e) => {
- if (props.onSubtitleClick) {
- e.stopPropagation()
- props.onSubtitleClick()
- }
- }}
- >
- {trigger().subtitle}
- </span>
- </Show>
- <Show when={trigger().args?.length}>
- <For each={trigger().args}>
- {(arg) => (
- <span
- data-slot="basic-tool-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={props.children && !props.hideDetails && !props.locked}>
- <Collapsible.Arrow />
- </Show>
- </div>
- </Collapsible.Trigger>
- <Show when={props.children && !props.hideDetails}>
- <Collapsible.Content>{props.children}</Collapsible.Content>
- </Show>
- </Collapsible>
- )
- }
- export function GenericTool(props: { tool: string; hideDetails?: boolean }) {
- return <BasicTool icon="mcp" trigger={{ title: props.tool }} hideDetails={props.hideDetails} />
- }
|