basic-tool.tsx 3.4 KB

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