basic-tool.tsx 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import { children, For, Match, Show, Switch, type JSX } from "solid-js"
  2. import { Collapsible } from "./collapsible"
  3. import { Icon, IconProps } from "./icon"
  4. export type TriggerTitle = {
  5. title: string
  6. titleClass?: string
  7. subtitle?: string
  8. subtitleClass?: string
  9. args?: string[]
  10. argsClass?: string
  11. action?: JSX.Element
  12. }
  13. const isTriggerTitle = (val: any): val is TriggerTitle => {
  14. return (
  15. typeof val === "object" && val !== null && "title" in val && (typeof Node === "undefined" || !(val instanceof Node))
  16. )
  17. }
  18. export interface BasicToolProps {
  19. icon: IconProps["name"]
  20. trigger: TriggerTitle | JSX.Element
  21. children?: JSX.Element
  22. hideDetails?: boolean
  23. defaultOpen?: boolean
  24. }
  25. export function BasicTool(props: BasicToolProps) {
  26. const resolved = children(() => props.children)
  27. return (
  28. <Collapsible defaultOpen={props.defaultOpen}>
  29. <Collapsible.Trigger>
  30. <div data-component="tool-trigger">
  31. <div data-slot="basic-tool-tool-trigger-content">
  32. <Icon name={props.icon} size="small" />
  33. <div data-slot="basic-tool-tool-info">
  34. <Switch>
  35. <Match when={isTriggerTitle(props.trigger) && props.trigger}>
  36. {(trigger) => (
  37. <div data-slot="basic-tool-tool-info-structured">
  38. <div data-slot="basic-tool-tool-info-main">
  39. <span
  40. data-slot="basic-tool-tool-title"
  41. classList={{
  42. [trigger().titleClass ?? ""]: !!trigger().titleClass,
  43. }}
  44. >
  45. {trigger().title}
  46. </span>
  47. <Show when={trigger().subtitle}>
  48. <span
  49. data-slot="basic-tool-tool-subtitle"
  50. classList={{
  51. [trigger().subtitleClass ?? ""]: !!trigger().subtitleClass,
  52. }}
  53. >
  54. {trigger().subtitle}
  55. </span>
  56. </Show>
  57. <Show when={trigger().args?.length}>
  58. <For each={trigger().args}>
  59. {(arg) => (
  60. <span
  61. data-slot="basic-tool-tool-arg"
  62. classList={{
  63. [trigger().argsClass ?? ""]: !!trigger().argsClass,
  64. }}
  65. >
  66. {arg}
  67. </span>
  68. )}
  69. </For>
  70. </Show>
  71. </div>
  72. <Show when={trigger().action}>{trigger().action}</Show>
  73. </div>
  74. )}
  75. </Match>
  76. <Match when={true}>{props.trigger as JSX.Element}</Match>
  77. </Switch>
  78. </div>
  79. </div>
  80. <Show when={resolved() && !props.hideDetails}>
  81. <Collapsible.Arrow />
  82. </Show>
  83. </div>
  84. </Collapsible.Trigger>
  85. <Show when={resolved() && !props.hideDetails}>
  86. <Collapsible.Content>{resolved()}</Collapsible.Content>
  87. </Show>
  88. </Collapsible>
  89. )
  90. }
  91. export function GenericTool(props: { tool: string; hideDetails?: boolean }) {
  92. return <BasicTool icon="mcp" trigger={{ title: props.tool }} hideDetails={props.hideDetails} />
  93. }