@wzh-/ai-chat-example 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/.vscode/extensions.json +3 -0
  2. package/.vscode/settings.json +6 -0
  3. package/README.md +5 -0
  4. package/auto-imports.d.ts +73 -0
  5. package/components.d.ts +312 -0
  6. package/components.json +21 -0
  7. package/index.html +13 -0
  8. package/package.json +60 -0
  9. package/public/vite.svg +1 -0
  10. package/src/App.vue +68 -0
  11. package/src/components/ChatConversation/ChatConversation.vue +97 -0
  12. package/src/components/ChatConversation/index.ts +1 -0
  13. package/src/components/ChatPromptInputProvider/ChatPromptInputProvider.vue +47 -0
  14. package/src/components/ChatPromptInputProvider/index.ts +1 -0
  15. package/src/components/ai-elements/artifact/Artifact.vue +23 -0
  16. package/src/components/ai-elements/artifact/ArtifactAction.vue +72 -0
  17. package/src/components/ai-elements/artifact/ArtifactActions.vue +19 -0
  18. package/src/components/ai-elements/artifact/ArtifactClose.vue +39 -0
  19. package/src/components/ai-elements/artifact/ArtifactContent.vue +20 -0
  20. package/src/components/ai-elements/artifact/ArtifactDescription.vue +20 -0
  21. package/src/components/ai-elements/artifact/ArtifactHeader.vue +23 -0
  22. package/src/components/ai-elements/artifact/ArtifactTitle.vue +20 -0
  23. package/src/components/ai-elements/artifact/index.ts +8 -0
  24. package/src/components/ai-elements/canvas/Canvas.vue +37 -0
  25. package/src/components/ai-elements/canvas/index.ts +1 -0
  26. package/src/components/ai-elements/chain-of-thought/ChainOfThought.vue +41 -0
  27. package/src/components/ai-elements/chain-of-thought/ChainOfThoughtContent.vue +32 -0
  28. package/src/components/ai-elements/chain-of-thought/ChainOfThoughtHeader.vue +43 -0
  29. package/src/components/ai-elements/chain-of-thought/ChainOfThoughtImage.vue +25 -0
  30. package/src/components/ai-elements/chain-of-thought/ChainOfThoughtSearchResult.vue +24 -0
  31. package/src/components/ai-elements/chain-of-thought/ChainOfThoughtSearchResults.vue +17 -0
  32. package/src/components/ai-elements/chain-of-thought/ChainOfThoughtStep.vue +54 -0
  33. package/src/components/ai-elements/chain-of-thought/context.ts +22 -0
  34. package/src/components/ai-elements/chain-of-thought/index.ts +7 -0
  35. package/src/components/ai-elements/checkpoint/Checkpoint.vue +19 -0
  36. package/src/components/ai-elements/checkpoint/CheckpointIcon.vue +19 -0
  37. package/src/components/ai-elements/checkpoint/CheckpointTrigger.vue +46 -0
  38. package/src/components/ai-elements/checkpoint/index.ts +3 -0
  39. package/src/components/ai-elements/code-block/CodeBlock.vue +84 -0
  40. package/src/components/ai-elements/code-block/CodeBlockCopyButton.vue +84 -0
  41. package/src/components/ai-elements/code-block/context.ts +7 -0
  42. package/src/components/ai-elements/code-block/index.ts +2 -0
  43. package/src/components/ai-elements/code-block/utils.ts +46 -0
  44. package/src/components/ai-elements/confirmation/Confirmation.vue +30 -0
  45. package/src/components/ai-elements/confirmation/ConfirmationAccepted.vue +18 -0
  46. package/src/components/ai-elements/confirmation/ConfirmationAction.vue +9 -0
  47. package/src/components/ai-elements/confirmation/ConfirmationActions.vue +23 -0
  48. package/src/components/ai-elements/confirmation/ConfirmationRejected.vue +18 -0
  49. package/src/components/ai-elements/confirmation/ConfirmationRequest.vue +11 -0
  50. package/src/components/ai-elements/confirmation/ConfirmationTitle.vue +18 -0
  51. package/src/components/ai-elements/confirmation/context.ts +46 -0
  52. package/src/components/ai-elements/confirmation/index.ts +7 -0
  53. package/src/components/ai-elements/connection/Connection.vue +36 -0
  54. package/src/components/ai-elements/connection/index.ts +1 -0
  55. package/src/components/ai-elements/context/Context.vue +29 -0
  56. package/src/components/ai-elements/context/ContextCacheUsage.vue +45 -0
  57. package/src/components/ai-elements/context/ContextContent.vue +20 -0
  58. package/src/components/ai-elements/context/ContextContentBody.vue +14 -0
  59. package/src/components/ai-elements/context/ContextContentFooter.vue +49 -0
  60. package/src/components/ai-elements/context/ContextContentHeader.vue +49 -0
  61. package/src/components/ai-elements/context/ContextIcon.vue +62 -0
  62. package/src/components/ai-elements/context/ContextInputUsage.vue +46 -0
  63. package/src/components/ai-elements/context/ContextOutputUsage.vue +45 -0
  64. package/src/components/ai-elements/context/ContextReasoningUsage.vue +48 -0
  65. package/src/components/ai-elements/context/ContextTrigger.vue +32 -0
  66. package/src/components/ai-elements/context/TokensWithCost.vue +25 -0
  67. package/src/components/ai-elements/context/context.ts +23 -0
  68. package/src/components/ai-elements/context/index.ts +12 -0
  69. package/src/components/ai-elements/controls/Controls.vue +25 -0
  70. package/src/components/ai-elements/controls/index.ts +1 -0
  71. package/src/components/ai-elements/conversation/Conversation.vue +37 -0
  72. package/src/components/ai-elements/conversation/ConversationContent.vue +21 -0
  73. package/src/components/ai-elements/conversation/ConversationEmptyState.vue +40 -0
  74. package/src/components/ai-elements/conversation/ConversationScrollButton.vue +34 -0
  75. package/src/components/ai-elements/conversation/index.ts +4 -0
  76. package/src/components/ai-elements/edge/Animated.vue +91 -0
  77. package/src/components/ai-elements/edge/Temporary.vue +28 -0
  78. package/src/components/ai-elements/edge/index.ts +2 -0
  79. package/src/components/ai-elements/image/Image.vue +29 -0
  80. package/src/components/ai-elements/image/index.ts +1 -0
  81. package/src/components/ai-elements/inline-citation/InlineCitation.vue +14 -0
  82. package/src/components/ai-elements/inline-citation/InlineCitationCard.vue +17 -0
  83. package/src/components/ai-elements/inline-citation/InlineCitationCardBody.vue +15 -0
  84. package/src/components/ai-elements/inline-citation/InlineCitationCardTrigger.vue +35 -0
  85. package/src/components/ai-elements/inline-citation/InlineCitationCarousel.vue +15 -0
  86. package/src/components/ai-elements/inline-citation/InlineCitationCarouselContent.vue +9 -0
  87. package/src/components/ai-elements/inline-citation/InlineCitationCarouselHeader.vue +16 -0
  88. package/src/components/ai-elements/inline-citation/InlineCitationCarouselIndex.vue +46 -0
  89. package/src/components/ai-elements/inline-citation/InlineCitationCarouselItem.vue +15 -0
  90. package/src/components/ai-elements/inline-citation/InlineCitationCarouselNext.vue +23 -0
  91. package/src/components/ai-elements/inline-citation/InlineCitationCarouselPrev.vue +23 -0
  92. package/src/components/ai-elements/inline-citation/InlineCitationQuote.vue +16 -0
  93. package/src/components/ai-elements/inline-citation/InlineCitationSource.vue +26 -0
  94. package/src/components/ai-elements/inline-citation/InlineCitationText.vue +14 -0
  95. package/src/components/ai-elements/inline-citation/index.ts +14 -0
  96. package/src/components/ai-elements/loader/Loader.vue +23 -0
  97. package/src/components/ai-elements/loader/LoaderIcon.vue +38 -0
  98. package/src/components/ai-elements/loader/index.ts +2 -0
  99. package/src/components/ai-elements/message/Message.vue +27 -0
  100. package/src/components/ai-elements/message/MessageAction.vue +45 -0
  101. package/src/components/ai-elements/message/MessageActions.vue +19 -0
  102. package/src/components/ai-elements/message/MessageAttachment.vue +87 -0
  103. package/src/components/ai-elements/message/MessageAttachments.vue +25 -0
  104. package/src/components/ai-elements/message/MessageAvatar.vue +22 -0
  105. package/src/components/ai-elements/message/MessageBranch.vue +66 -0
  106. package/src/components/ai-elements/message/MessageBranchContent.vue +51 -0
  107. package/src/components/ai-elements/message/MessageBranchNext.vue +23 -0
  108. package/src/components/ai-elements/message/MessageBranchPage.vue +28 -0
  109. package/src/components/ai-elements/message/MessageBranchPrevious.vue +23 -0
  110. package/src/components/ai-elements/message/MessageBranchSelector.vue +23 -0
  111. package/src/components/ai-elements/message/MessageContent.vue +26 -0
  112. package/src/components/ai-elements/message/MessageResponse.vue +42 -0
  113. package/src/components/ai-elements/message/MessageToolbar.vue +24 -0
  114. package/src/components/ai-elements/message/context.ts +22 -0
  115. package/src/components/ai-elements/message/index.ts +15 -0
  116. package/src/components/ai-elements/model-selector/ModelSelector.vue +9 -0
  117. package/src/components/ai-elements/model-selector/ModelSelectorContent.vue +29 -0
  118. package/src/components/ai-elements/model-selector/ModelSelectorDialog.vue +9 -0
  119. package/src/components/ai-elements/model-selector/ModelSelectorEmpty.vue +9 -0
  120. package/src/components/ai-elements/model-selector/ModelSelectorGroup.vue +9 -0
  121. package/src/components/ai-elements/model-selector/ModelSelectorInput.vue +18 -0
  122. package/src/components/ai-elements/model-selector/ModelSelectorItem.vue +10 -0
  123. package/src/components/ai-elements/model-selector/ModelSelectorList.vue +9 -0
  124. package/src/components/ai-elements/model-selector/ModelSelectorLogo.vue +22 -0
  125. package/src/components/ai-elements/model-selector/ModelSelectorLogoGroup.vue +24 -0
  126. package/src/components/ai-elements/model-selector/ModelSelectorName.vue +19 -0
  127. package/src/components/ai-elements/model-selector/ModelSelectorSeparator.vue +7 -0
  128. package/src/components/ai-elements/model-selector/ModelSelectorShortcut.vue +9 -0
  129. package/src/components/ai-elements/model-selector/ModelSelectorTrigger.vue +9 -0
  130. package/src/components/ai-elements/model-selector/index.ts +14 -0
  131. package/src/components/ai-elements/node/Node.vue +31 -0
  132. package/src/components/ai-elements/node/NodeAction.vue +9 -0
  133. package/src/components/ai-elements/node/NodeContent.vue +15 -0
  134. package/src/components/ai-elements/node/NodeDescription.vue +9 -0
  135. package/src/components/ai-elements/node/NodeFooter.vue +15 -0
  136. package/src/components/ai-elements/node/NodeHeader.vue +15 -0
  137. package/src/components/ai-elements/node/NodeTitle.vue +9 -0
  138. package/src/components/ai-elements/node/index.ts +7 -0
  139. package/src/components/ai-elements/open-in-chat/OpenIn.vue +20 -0
  140. package/src/components/ai-elements/open-in-chat/OpenInContent.vue +25 -0
  141. package/src/components/ai-elements/open-in-chat/OpenInItemLink.vue +30 -0
  142. package/src/components/ai-elements/open-in-chat/OpenInTrigger.vue +16 -0
  143. package/src/components/ai-elements/open-in-chat/context.ts +20 -0
  144. package/src/components/ai-elements/open-in-chat/index.ts +9 -0
  145. package/src/components/ai-elements/open-in-chat/providers/icons/ChatGPT.vue +13 -0
  146. package/src/components/ai-elements/open-in-chat/providers/icons/Claude.vue +15 -0
  147. package/src/components/ai-elements/open-in-chat/providers/icons/Cursor.vue +13 -0
  148. package/src/components/ai-elements/open-in-chat/providers/icons/Github.vue +8 -0
  149. package/src/components/ai-elements/open-in-chat/providers/icons/Scira.vue +58 -0
  150. package/src/components/ai-elements/open-in-chat/providers/icons/V0.vue +15 -0
  151. package/src/components/ai-elements/open-in-chat/providers/icons/index.ts +6 -0
  152. package/src/components/ai-elements/open-in-chat/providers/index.ts +69 -0
  153. package/src/components/ai-elements/open-in-chat/providers/items/OpenInChatGPT.vue +18 -0
  154. package/src/components/ai-elements/open-in-chat/providers/items/OpenInClaude.vue +18 -0
  155. package/src/components/ai-elements/open-in-chat/providers/items/OpenInCursor.vue +18 -0
  156. package/src/components/ai-elements/open-in-chat/providers/items/OpenInScira.vue +18 -0
  157. package/src/components/ai-elements/open-in-chat/providers/items/OpenInT3.vue +18 -0
  158. package/src/components/ai-elements/open-in-chat/providers/items/OpenInv0.vue +18 -0
  159. package/src/components/ai-elements/panel/Panel.vue +28 -0
  160. package/src/components/ai-elements/panel/index.ts +1 -0
  161. package/src/components/ai-elements/plan/Plan.vue +32 -0
  162. package/src/components/ai-elements/plan/PlanAction.vue +9 -0
  163. package/src/components/ai-elements/plan/PlanContent.vue +12 -0
  164. package/src/components/ai-elements/plan/PlanDescription.vue +25 -0
  165. package/src/components/ai-elements/plan/PlanFooter.vue +9 -0
  166. package/src/components/ai-elements/plan/PlanHeader.vue +18 -0
  167. package/src/components/ai-elements/plan/PlanTitle.vue +16 -0
  168. package/src/components/ai-elements/plan/PlanTrigger.vue +25 -0
  169. package/src/components/ai-elements/plan/context.ts +20 -0
  170. package/src/components/ai-elements/plan/index.ts +8 -0
  171. package/src/components/ai-elements/prompt-input/PromptInput.vue +116 -0
  172. package/src/components/ai-elements/prompt-input/PromptInputActionAddAttachments.vue +22 -0
  173. package/src/components/ai-elements/prompt-input/PromptInputActionMenu.vue +15 -0
  174. package/src/components/ai-elements/prompt-input/PromptInputActionMenuContent.vue +21 -0
  175. package/src/components/ai-elements/prompt-input/PromptInputActionMenuItem.vue +19 -0
  176. package/src/components/ai-elements/prompt-input/PromptInputActionMenuTrigger.vue +22 -0
  177. package/src/components/ai-elements/prompt-input/PromptInputAttachment.vue +94 -0
  178. package/src/components/ai-elements/prompt-input/PromptInputAttachments.vue +22 -0
  179. package/src/components/ai-elements/prompt-input/PromptInputBody.vue +12 -0
  180. package/src/components/ai-elements/prompt-input/PromptInputButton.vue +56 -0
  181. package/src/components/ai-elements/prompt-input/PromptInputCommand.vue +19 -0
  182. package/src/components/ai-elements/prompt-input/PromptInputCommandEmpty.vue +19 -0
  183. package/src/components/ai-elements/prompt-input/PromptInputCommandGroup.vue +19 -0
  184. package/src/components/ai-elements/prompt-input/PromptInputCommandInput.vue +17 -0
  185. package/src/components/ai-elements/prompt-input/PromptInputCommandItem.vue +19 -0
  186. package/src/components/ai-elements/prompt-input/PromptInputCommandList.vue +17 -0
  187. package/src/components/ai-elements/prompt-input/PromptInputCommandSeparator.vue +16 -0
  188. package/src/components/ai-elements/prompt-input/PromptInputFooter.vue +23 -0
  189. package/src/components/ai-elements/prompt-input/PromptInputHeader.vue +23 -0
  190. package/src/components/ai-elements/prompt-input/PromptInputHoverCard.vue +23 -0
  191. package/src/components/ai-elements/prompt-input/PromptInputHoverCardContent.vue +19 -0
  192. package/src/components/ai-elements/prompt-input/PromptInputHoverCardTrigger.vue +15 -0
  193. package/src/components/ai-elements/prompt-input/PromptInputProvider.vue +32 -0
  194. package/src/components/ai-elements/prompt-input/PromptInputSelect.vue +15 -0
  195. package/src/components/ai-elements/prompt-input/PromptInputSelectContent.vue +19 -0
  196. package/src/components/ai-elements/prompt-input/PromptInputSelectItem.vue +19 -0
  197. package/src/components/ai-elements/prompt-input/PromptInputSelectTrigger.vue +26 -0
  198. package/src/components/ai-elements/prompt-input/PromptInputSelectValue.vue +19 -0
  199. package/src/components/ai-elements/prompt-input/PromptInputSpeechButton.vue +137 -0
  200. package/src/components/ai-elements/prompt-input/PromptInputSubmit.vue +60 -0
  201. package/src/components/ai-elements/prompt-input/PromptInputTab.vue +16 -0
  202. package/src/components/ai-elements/prompt-input/PromptInputTabBody.vue +16 -0
  203. package/src/components/ai-elements/prompt-input/PromptInputTabItem.vue +16 -0
  204. package/src/components/ai-elements/prompt-input/PromptInputTabLabel.vue +16 -0
  205. package/src/components/ai-elements/prompt-input/PromptInputTabsList.vue +16 -0
  206. package/src/components/ai-elements/prompt-input/PromptInputTextarea.vue +78 -0
  207. package/src/components/ai-elements/prompt-input/PromptInputTools.vue +12 -0
  208. package/src/components/ai-elements/prompt-input/context.ts +223 -0
  209. package/src/components/ai-elements/prompt-input/index.ts +39 -0
  210. package/src/components/ai-elements/prompt-input/types.ts +28 -0
  211. package/src/components/ai-elements/queue/Queue.vue +21 -0
  212. package/src/components/ai-elements/queue/QueueItem.vue +21 -0
  213. package/src/components/ai-elements/queue/QueueItemAction.vue +25 -0
  214. package/src/components/ai-elements/queue/QueueItemActions.vue +14 -0
  215. package/src/components/ai-elements/queue/QueueItemAttachment.vue +14 -0
  216. package/src/components/ai-elements/queue/QueueItemContent.vue +32 -0
  217. package/src/components/ai-elements/queue/QueueItemDescription.vue +32 -0
  218. package/src/components/ai-elements/queue/QueueItemFile.vue +25 -0
  219. package/src/components/ai-elements/queue/QueueItemImage.vue +18 -0
  220. package/src/components/ai-elements/queue/QueueItemIndicator.vue +30 -0
  221. package/src/components/ai-elements/queue/QueueList.vue +22 -0
  222. package/src/components/ai-elements/queue/QueueSection.vue +26 -0
  223. package/src/components/ai-elements/queue/QueueSectionContent.vue +15 -0
  224. package/src/components/ai-elements/queue/QueueSectionLabel.vue +26 -0
  225. package/src/components/ai-elements/queue/QueueSectionTrigger.vue +25 -0
  226. package/src/components/ai-elements/queue/index.ts +15 -0
  227. package/src/components/ai-elements/reasoning/Reasoning.vue +94 -0
  228. package/src/components/ai-elements/reasoning/ReasoningContent.vue +41 -0
  229. package/src/components/ai-elements/reasoning/ReasoningTrigger.vue +61 -0
  230. package/src/components/ai-elements/reasoning/context.ts +19 -0
  231. package/src/components/ai-elements/reasoning/index.ts +3 -0
  232. package/src/components/ai-elements/shimmer/Shimmer.vue +69 -0
  233. package/src/components/ai-elements/shimmer/index.ts +1 -0
  234. package/src/components/ai-elements/sources/Source.vue +26 -0
  235. package/src/components/ai-elements/sources/Sources.vue +17 -0
  236. package/src/components/ai-elements/sources/SourcesContent.vue +23 -0
  237. package/src/components/ai-elements/sources/SourcesTrigger.vue +24 -0
  238. package/src/components/ai-elements/sources/index.ts +4 -0
  239. package/src/components/ai-elements/suggestion/Suggestion.vue +38 -0
  240. package/src/components/ai-elements/suggestion/Suggestions.vue +20 -0
  241. package/src/components/ai-elements/suggestion/index.ts +2 -0
  242. package/src/components/ai-elements/task/Task.vue +32 -0
  243. package/src/components/ai-elements/task/TaskContent.vue +27 -0
  244. package/src/components/ai-elements/task/TaskItem.vue +16 -0
  245. package/src/components/ai-elements/task/TaskItemFile.vue +18 -0
  246. package/src/components/ai-elements/task/TaskTrigger.vue +33 -0
  247. package/src/components/ai-elements/task/index.ts +5 -0
  248. package/src/components/ai-elements/tool/Tool.vue +18 -0
  249. package/src/components/ai-elements/tool/ToolContent.vue +23 -0
  250. package/src/components/ai-elements/tool/ToolHeader.vue +38 -0
  251. package/src/components/ai-elements/tool/ToolInput.vue +32 -0
  252. package/src/components/ai-elements/tool/ToolOutput.vue +69 -0
  253. package/src/components/ai-elements/tool/ToolStatusBadge.vue +63 -0
  254. package/src/components/ai-elements/tool/index.ts +5 -0
  255. package/src/components/ai-elements/toolbar/Toolbar.vue +32 -0
  256. package/src/components/ai-elements/toolbar/index.ts +1 -0
  257. package/src/components/ai-elements/web-preview/WebPreview.vue +60 -0
  258. package/src/components/ai-elements/web-preview/WebPreviewBody.vue +34 -0
  259. package/src/components/ai-elements/web-preview/WebPreviewConsole.vue +92 -0
  260. package/src/components/ai-elements/web-preview/WebPreviewNavigation.vue +21 -0
  261. package/src/components/ai-elements/web-preview/WebPreviewNavigationButton.vue +45 -0
  262. package/src/components/ai-elements/web-preview/WebPreviewUrl.vue +43 -0
  263. package/src/components/ai-elements/web-preview/context.ts +25 -0
  264. package/src/components/ai-elements/web-preview/index.ts +7 -0
  265. package/src/components/ui/alert/Alert.vue +21 -0
  266. package/src/components/ui/alert/AlertDescription.vue +17 -0
  267. package/src/components/ui/alert/AlertTitle.vue +17 -0
  268. package/src/components/ui/alert/index.ts +24 -0
  269. package/src/components/ui/avatar/Avatar.vue +18 -0
  270. package/src/components/ui/avatar/AvatarFallback.vue +21 -0
  271. package/src/components/ui/avatar/AvatarImage.vue +16 -0
  272. package/src/components/ui/avatar/index.ts +3 -0
  273. package/src/components/ui/badge/Badge.vue +26 -0
  274. package/src/components/ui/badge/index.ts +26 -0
  275. package/src/components/ui/button/Button.vue +29 -0
  276. package/src/components/ui/button/index.ts +38 -0
  277. package/src/components/ui/button-group/ButtonGroup.vue +22 -0
  278. package/src/components/ui/button-group/ButtonGroupSeparator.vue +24 -0
  279. package/src/components/ui/button-group/ButtonGroupText.vue +29 -0
  280. package/src/components/ui/button-group/index.ts +25 -0
  281. package/src/components/ui/card/Card.vue +22 -0
  282. package/src/components/ui/card/CardAction.vue +17 -0
  283. package/src/components/ui/card/CardContent.vue +17 -0
  284. package/src/components/ui/card/CardDescription.vue +17 -0
  285. package/src/components/ui/card/CardFooter.vue +17 -0
  286. package/src/components/ui/card/CardHeader.vue +17 -0
  287. package/src/components/ui/card/CardTitle.vue +17 -0
  288. package/src/components/ui/card/index.ts +7 -0
  289. package/src/components/ui/carousel/Carousel.vue +53 -0
  290. package/src/components/ui/carousel/CarouselContent.vue +33 -0
  291. package/src/components/ui/carousel/CarouselItem.vue +24 -0
  292. package/src/components/ui/carousel/CarouselNext.vue +41 -0
  293. package/src/components/ui/carousel/CarouselPrevious.vue +41 -0
  294. package/src/components/ui/carousel/index.ts +10 -0
  295. package/src/components/ui/carousel/interface.ts +26 -0
  296. package/src/components/ui/carousel/useCarousel.ts +56 -0
  297. package/src/components/ui/collapsible/Collapsible.vue +19 -0
  298. package/src/components/ui/collapsible/CollapsibleContent.vue +15 -0
  299. package/src/components/ui/collapsible/CollapsibleTrigger.vue +15 -0
  300. package/src/components/ui/collapsible/index.ts +3 -0
  301. package/src/components/ui/command/Command.vue +87 -0
  302. package/src/components/ui/command/CommandDialog.vue +31 -0
  303. package/src/components/ui/command/CommandEmpty.vue +27 -0
  304. package/src/components/ui/command/CommandGroup.vue +45 -0
  305. package/src/components/ui/command/CommandInput.vue +39 -0
  306. package/src/components/ui/command/CommandItem.vue +76 -0
  307. package/src/components/ui/command/CommandList.vue +25 -0
  308. package/src/components/ui/command/CommandSeparator.vue +21 -0
  309. package/src/components/ui/command/CommandShortcut.vue +17 -0
  310. package/src/components/ui/command/index.ts +25 -0
  311. package/src/components/ui/dialog/Dialog.vue +19 -0
  312. package/src/components/ui/dialog/DialogClose.vue +15 -0
  313. package/src/components/ui/dialog/DialogContent.vue +53 -0
  314. package/src/components/ui/dialog/DialogDescription.vue +23 -0
  315. package/src/components/ui/dialog/DialogFooter.vue +15 -0
  316. package/src/components/ui/dialog/DialogHeader.vue +17 -0
  317. package/src/components/ui/dialog/DialogOverlay.vue +21 -0
  318. package/src/components/ui/dialog/DialogScrollContent.vue +59 -0
  319. package/src/components/ui/dialog/DialogTitle.vue +23 -0
  320. package/src/components/ui/dialog/DialogTrigger.vue +15 -0
  321. package/src/components/ui/dialog/index.ts +10 -0
  322. package/src/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
  323. package/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +39 -0
  324. package/src/components/ui/dropdown-menu/DropdownMenuContent.vue +39 -0
  325. package/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +15 -0
  326. package/src/components/ui/dropdown-menu/DropdownMenuItem.vue +31 -0
  327. package/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +23 -0
  328. package/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
  329. package/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +40 -0
  330. package/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  331. package/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +17 -0
  332. package/src/components/ui/dropdown-menu/DropdownMenuSub.vue +18 -0
  333. package/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +27 -0
  334. package/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +30 -0
  335. package/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
  336. package/src/components/ui/dropdown-menu/index.ts +16 -0
  337. package/src/components/ui/hover-card/HoverCard.vue +19 -0
  338. package/src/components/ui/hover-card/HoverCardContent.vue +43 -0
  339. package/src/components/ui/hover-card/HoverCardTrigger.vue +15 -0
  340. package/src/components/ui/hover-card/index.ts +3 -0
  341. package/src/components/ui/input/Input.vue +33 -0
  342. package/src/components/ui/input/index.ts +1 -0
  343. package/src/components/ui/input-group/InputGroup.vue +37 -0
  344. package/src/components/ui/input-group/InputGroupAddon.vue +36 -0
  345. package/src/components/ui/input-group/InputGroupButton.vue +21 -0
  346. package/src/components/ui/input-group/InputGroupInput.vue +19 -0
  347. package/src/components/ui/input-group/InputGroupText.vue +19 -0
  348. package/src/components/ui/input-group/InputGroupTextarea.vue +19 -0
  349. package/src/components/ui/input-group/index.ts +59 -0
  350. package/src/components/ui/progress/Progress.vue +38 -0
  351. package/src/components/ui/progress/index.ts +1 -0
  352. package/src/components/ui/scroll-area/ScrollArea.vue +33 -0
  353. package/src/components/ui/scroll-area/ScrollBar.vue +32 -0
  354. package/src/components/ui/scroll-area/index.ts +2 -0
  355. package/src/components/ui/select/Select.vue +19 -0
  356. package/src/components/ui/select/SelectContent.vue +51 -0
  357. package/src/components/ui/select/SelectGroup.vue +15 -0
  358. package/src/components/ui/select/SelectItem.vue +44 -0
  359. package/src/components/ui/select/SelectItemText.vue +15 -0
  360. package/src/components/ui/select/SelectLabel.vue +17 -0
  361. package/src/components/ui/select/SelectScrollDownButton.vue +26 -0
  362. package/src/components/ui/select/SelectScrollUpButton.vue +26 -0
  363. package/src/components/ui/select/SelectSeparator.vue +19 -0
  364. package/src/components/ui/select/SelectTrigger.vue +33 -0
  365. package/src/components/ui/select/SelectValue.vue +15 -0
  366. package/src/components/ui/select/index.ts +11 -0
  367. package/src/components/ui/separator/Separator.vue +29 -0
  368. package/src/components/ui/separator/index.ts +1 -0
  369. package/src/components/ui/textarea/Textarea.vue +28 -0
  370. package/src/components/ui/textarea/index.ts +1 -0
  371. package/src/components/ui/tooltip/Tooltip.vue +19 -0
  372. package/src/components/ui/tooltip/TooltipContent.vue +34 -0
  373. package/src/components/ui/tooltip/TooltipProvider.vue +14 -0
  374. package/src/components/ui/tooltip/TooltipTrigger.vue +15 -0
  375. package/src/components/ui/tooltip/index.ts +4 -0
  376. package/src/composables/useChat.ts +46 -0
  377. package/src/index.ts +3 -0
  378. package/src/lib/utils.ts +7 -0
  379. package/src/main.ts +5 -0
  380. package/src/request/index.ts +41 -0
  381. package/src/style.css +120 -0
  382. package/tsconfig.app.json +25 -0
  383. package/tsconfig.json +13 -0
  384. package/tsconfig.node.json +26 -0
  385. package/vite.config.ts +26 -0
@@ -0,0 +1,78 @@
1
+ <script setup lang="ts">
2
+ import { InputGroupTextarea } from "@/components/ui/input-group";
3
+ import { cn } from "@/lib/utils";
4
+ import type { HTMLAttributes } from "vue";
5
+ import { computed, ref } from "vue";
6
+ import { usePromptInput } from "./context";
7
+
8
+ type PromptInputTextareaProps = InstanceType<
9
+ typeof InputGroupTextarea
10
+ >["$props"];
11
+
12
+ interface Props extends /* @vue-ignore */ PromptInputTextareaProps {
13
+ class?: HTMLAttributes["class"];
14
+ }
15
+
16
+ const props = defineProps<Props>();
17
+
18
+ const { textInput, setTextInput, submitForm, addFiles, files, removeFile } =
19
+ usePromptInput();
20
+ const isComposing = ref(false);
21
+
22
+ function handleKeyDown(e: KeyboardEvent) {
23
+ if (e.key === "Enter") {
24
+ if (isComposing.value || e.shiftKey) return;
25
+ e.preventDefault();
26
+ submitForm();
27
+ }
28
+
29
+ // Remove last attachment on backspace if input is empty
30
+ if (
31
+ e.key === "Backspace" &&
32
+ textInput.value === "" &&
33
+ files.value.length > 0
34
+ ) {
35
+ const lastFile = files.value[files.value.length - 1];
36
+ if (lastFile) {
37
+ removeFile(lastFile.id);
38
+ }
39
+ }
40
+ }
41
+
42
+ function handlePaste(e: ClipboardEvent) {
43
+ const items = e.clipboardData?.items;
44
+ if (!items) return;
45
+
46
+ const pastedFiles: File[] = [];
47
+ for (const item of Array.from(items)) {
48
+ if (item.kind === "file") {
49
+ const file = item.getAsFile();
50
+ if (file) pastedFiles.push(file);
51
+ }
52
+ }
53
+
54
+ if (pastedFiles.length > 0) {
55
+ e.preventDefault();
56
+ addFiles(pastedFiles);
57
+ }
58
+ }
59
+
60
+ const modelValue = computed({
61
+ get: () => textInput.value,
62
+ set: (val) => setTextInput(val),
63
+ });
64
+ </script>
65
+
66
+ <template>
67
+ <InputGroupTextarea
68
+ v-model="modelValue"
69
+ placeholder="What would you like to know?"
70
+ name="message"
71
+ :class="cn('field-sizing-content max-h-48 min-h-16', props.class)"
72
+ v-bind="props"
73
+ @keydown="handleKeyDown"
74
+ @paste="handlePaste"
75
+ @compositionstart="isComposing = true"
76
+ @compositionend="isComposing = false"
77
+ />
78
+ </template>
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+
5
+ const props = defineProps<{ class?: HTMLAttributes['class'] }>()
6
+ </script>
7
+
8
+ <template>
9
+ <div :class="cn('flex items-center gap-1', props.class)">
10
+ <slot />
11
+ </div>
12
+ </template>
@@ -0,0 +1,223 @@
1
+ import type { AttachmentFile, PromptInputContext } from "./types";
2
+ import { nanoid } from "nanoid";
3
+ import { inject, onBeforeUnmount, provide, ref } from "vue";
4
+ import { PROMPT_INPUT_KEY } from "./types";
5
+ import request from "@/request";
6
+
7
+ export function usePromptInputProvider(
8
+ props: {
9
+ initialInput?: string;
10
+ maxFiles?: number;
11
+ maxFileSize?: number;
12
+ accept?: string;
13
+ onSubmit?: (message: {
14
+ text: string;
15
+ files: any[];
16
+ }) => void | Promise<void>;
17
+ onError?: (err: { code: string; message: string }) => void;
18
+ },
19
+ uploadImages?: (
20
+ files: File[]
21
+ ) =>
22
+ | { name: string; path: string }[]
23
+ | Promise<{ name: string; path: string }[]>
24
+ ) {
25
+ const textInput = ref(props.initialInput || "");
26
+
27
+ const files = ref<AttachmentFile[]>([]);
28
+ const fileInputRef = ref<HTMLInputElement | null>(null);
29
+ const isLoading = ref(false);
30
+
31
+ // Cleanup object URLs to avoid memory leaks
32
+ onBeforeUnmount(() => {
33
+ files.value.forEach((f) => {
34
+ if (f.url && f.url.startsWith("blob:")) {
35
+ URL.revokeObjectURL(f.url);
36
+ }
37
+ });
38
+ });
39
+
40
+ const setTextInput = (val: string) => {
41
+ textInput.value = val;
42
+ };
43
+
44
+ const matchesAccept = (file: File) => {
45
+ if (!props.accept || props.accept.trim() === "") return true;
46
+ if (props.accept.includes("image/*")) return file.type.startsWith("image/");
47
+ // Add more mime-type checks here if necessary
48
+ return true;
49
+ };
50
+
51
+ const addFiles = async (incoming: File[] | FileList) => {
52
+ const fileList = Array.from(incoming);
53
+
54
+ // Validate Accept
55
+ const accepted = fileList.filter(matchesAccept);
56
+ if (fileList.length && accepted.length === 0) {
57
+ props.onError?.({
58
+ code: "accept",
59
+ message: "No files match the accepted types.",
60
+ });
61
+ return;
62
+ }
63
+
64
+ // Validate Size
65
+ const withinSize = (f: File) =>
66
+ props.maxFileSize ? f.size <= props.maxFileSize : true;
67
+ const sized = accepted.filter(withinSize);
68
+ if (accepted.length > 0 && sized.length === 0) {
69
+ props.onError?.({
70
+ code: "max_file_size",
71
+ message: "All files exceed the maximum size.",
72
+ });
73
+ return;
74
+ }
75
+
76
+ // Validate Count
77
+ const currentCount = files.value.length;
78
+ const capacity = props.maxFiles
79
+ ? Math.max(0, props.maxFiles - currentCount)
80
+ : undefined;
81
+ const capped =
82
+ typeof capacity === "number" ? sized.slice(0, capacity) : sized;
83
+
84
+ if (typeof capacity === "number" && sized.length > capacity) {
85
+ props.onError?.({
86
+ code: "max_files",
87
+ message: "Too many files. Some were not added.",
88
+ });
89
+ }
90
+
91
+ let images: { name: string; path: string }[] = [];
92
+
93
+ if (uploadImages) {
94
+ const res = uploadImages(capped);
95
+ images = await res;
96
+ }
97
+
98
+ const newAttachments: AttachmentFile[] = capped.map((file, index) => ({
99
+ id: nanoid(),
100
+ type: "file",
101
+ // url: URL.createObjectURL(file),
102
+ url: images[index]?.path ?? URL.createObjectURL(file), //转成文件上传
103
+ mediaType: file.type,
104
+ filename: images[index]?.name ?? file.name,
105
+ file,
106
+ }));
107
+
108
+ files.value = [...files.value, ...newAttachments];
109
+ };
110
+
111
+ const removeFile = (id: string) => {
112
+ const file = files.value.find((f) => f.id === id);
113
+ if (file?.url && file.url.startsWith("blob:")) {
114
+ URL.revokeObjectURL(file.url);
115
+ }
116
+ files.value = files.value.filter((f) => f.id !== id);
117
+ };
118
+
119
+ const clearFiles = () => {
120
+ files.value.forEach((f) => {
121
+ if (f.url && f.url.startsWith("blob:")) {
122
+ URL.revokeObjectURL(f.url);
123
+ }
124
+ });
125
+ files.value = [];
126
+ };
127
+
128
+ const clearInput = () => {
129
+ textInput.value = "";
130
+ };
131
+
132
+ const openFileDialog = () => {
133
+ fileInputRef.value?.click();
134
+ };
135
+
136
+ const convertBlobUrlToDataUrl = async (
137
+ url: string
138
+ ): Promise<string | null> => {
139
+ try {
140
+ const response = await fetch(url);
141
+ const blob = await response.blob();
142
+ return new Promise((resolve) => {
143
+ const reader = new FileReader();
144
+ reader.onloadend = () => resolve(reader.result as string);
145
+ reader.onerror = () => resolve(null);
146
+ reader.readAsDataURL(blob);
147
+ });
148
+ } catch {
149
+ return null;
150
+ }
151
+ };
152
+
153
+ const submitForm = async () => {
154
+ if (!props.onSubmit) return;
155
+
156
+ // Process files (convert blobs to base64 if needed for AI SDK)
157
+ const processedFiles = await Promise.all(
158
+ files.value.map(async (item) => {
159
+ if (item.url && item.url.startsWith("blob:")) {
160
+ const dataUrl = await convertBlobUrlToDataUrl(item.url);
161
+ return { ...item, url: dataUrl ?? item.url };
162
+ }
163
+ return item;
164
+ })
165
+ );
166
+
167
+ const message = {
168
+ text: textInput.value,
169
+ files: processedFiles,
170
+ };
171
+
172
+ try {
173
+ isLoading.value = true;
174
+ const result = props.onSubmit(message);
175
+ if (result instanceof Promise) {
176
+ await result;
177
+ }
178
+ clearInput();
179
+ clearFiles();
180
+ } catch (e) {
181
+ if (props.onError) {
182
+ const errorMessage =
183
+ e instanceof Error
184
+ ? e.message
185
+ : String(e) || "An unknown error occurred during submission.";
186
+ props.onError({
187
+ code: "submit_error",
188
+ message: errorMessage,
189
+ });
190
+ }
191
+ console.error("Submission failed:", e);
192
+ } finally {
193
+ isLoading.value = false;
194
+ }
195
+ };
196
+
197
+ const context: PromptInputContext = {
198
+ textInput,
199
+ files,
200
+ fileInputRef,
201
+ isLoading,
202
+ setTextInput,
203
+ addFiles,
204
+ removeFile,
205
+ clearFiles,
206
+ clearInput,
207
+ openFileDialog,
208
+ submitForm,
209
+ };
210
+
211
+ provide(PROMPT_INPUT_KEY, context);
212
+ return context;
213
+ }
214
+
215
+ export function usePromptInput() {
216
+ const context = inject<PromptInputContext>(PROMPT_INPUT_KEY);
217
+ if (!context) {
218
+ throw new Error(
219
+ "usePromptInput must be used within a PromptInput component"
220
+ );
221
+ }
222
+ return context;
223
+ }
@@ -0,0 +1,39 @@
1
+ export * from './context'
2
+ export { default as PromptInput } from './PromptInput.vue'
3
+ export { default as PromptInputActionAddAttachments } from './PromptInputActionAddAttachments.vue'
4
+ export { default as PromptInputActionMenu } from './PromptInputActionMenu.vue'
5
+ export { default as PromptInputActionMenuContent } from './PromptInputActionMenuContent.vue'
6
+ export { default as PromptInputActionMenuItem } from './PromptInputActionMenuItem.vue'
7
+ export { default as PromptInputActionMenuTrigger } from './PromptInputActionMenuTrigger.vue'
8
+ export { default as PromptInputAttachment } from './PromptInputAttachment.vue'
9
+ export { default as PromptInputAttachments } from './PromptInputAttachments.vue'
10
+ export { default as PromptInputBody } from './PromptInputBody.vue'
11
+ export { default as PromptInputButton } from './PromptInputButton.vue'
12
+ export { default as PromptInputCommand } from './PromptInputCommand.vue'
13
+ export { default as PromptInputCommandEmpty } from './PromptInputCommandEmpty.vue'
14
+ export { default as PromptInputCommandGroup } from './PromptInputCommandGroup.vue'
15
+ export { default as PromptInputCommandInput } from './PromptInputCommandInput.vue'
16
+ export { default as PromptInputCommandItem } from './PromptInputCommandItem.vue'
17
+ export { default as PromptInputCommandList } from './PromptInputCommandList.vue'
18
+ export { default as PromptInputCommandSeparator } from './PromptInputCommandSeparator.vue'
19
+ export { default as PromptInputFooter } from './PromptInputFooter.vue'
20
+ export { default as PromptInputHeader } from './PromptInputHeader.vue'
21
+ export { default as PromptInputHoverCard } from './PromptInputHoverCard.vue'
22
+ export { default as PromptInputHoverCardContent } from './PromptInputHoverCardContent.vue'
23
+ export { default as PromptInputHoverCardTrigger } from './PromptInputHoverCardTrigger.vue'
24
+ export { default as PromptInputProvider } from './PromptInputProvider.vue'
25
+ export { default as PromptInputSelect } from './PromptInputSelect.vue'
26
+ export { default as PromptInputSelectContent } from './PromptInputSelectContent.vue'
27
+ export { default as PromptInputSelectItem } from './PromptInputSelectItem.vue'
28
+ export { default as PromptInputSelectTrigger } from './PromptInputSelectTrigger.vue'
29
+ export { default as PromptInputSelectValue } from './PromptInputSelectValue.vue'
30
+ export { default as PromptInputSpeechButton } from './PromptInputSpeechButton.vue'
31
+ export { default as PromptInputSubmit } from './PromptInputSubmit.vue'
32
+ export { default as PromptInputTab } from './PromptInputTab.vue'
33
+ export { default as PromptInputTabBody } from './PromptInputTabBody.vue'
34
+ export { default as PromptInputTabItem } from './PromptInputTabItem.vue'
35
+ export { default as PromptInputTabLabel } from './PromptInputTabLabel.vue'
36
+ export { default as PromptInputTabsList } from './PromptInputTabsList.vue'
37
+ export { default as PromptInputTextarea } from './PromptInputTextarea.vue'
38
+ export { default as PromptInputTools } from './PromptInputTools.vue'
39
+ export * from './types'
@@ -0,0 +1,28 @@
1
+ import type { FileUIPart } from 'ai'
2
+ import type { Ref } from 'vue'
3
+
4
+ export interface PromptInputMessage {
5
+ text: string
6
+ files: FileUIPart[]
7
+ }
8
+
9
+ export interface AttachmentFile extends FileUIPart {
10
+ id: string
11
+ file?: File
12
+ }
13
+
14
+ export interface PromptInputContext {
15
+ textInput: Ref<string>
16
+ files: Ref<AttachmentFile[]>
17
+ isLoading: Ref<boolean>
18
+ fileInputRef: Ref<HTMLInputElement | null>
19
+ setTextInput: (val: string) => void
20
+ addFiles: (files: File[] | FileList) => void
21
+ removeFile: (id: string) => void
22
+ clearFiles: () => void
23
+ clearInput: () => void
24
+ openFileDialog: () => void
25
+ submitForm: () => void
26
+ }
27
+
28
+ export const PROMPT_INPUT_KEY = Symbol('PromptInputContext')
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes['class']
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <div
12
+ :class="
13
+ cn(
14
+ 'flex flex-col gap-2 rounded-xl border border-border bg-background px-3 pt-2 pb-2 shadow-xs',
15
+ props.class,
16
+ )
17
+ "
18
+ >
19
+ <slot />
20
+ </div>
21
+ </template>
@@ -0,0 +1,21 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes['class']
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <li
12
+ :class="
13
+ cn(
14
+ 'group flex flex-col gap-1 rounded-md px-3 py-1 text-sm transition-colors hover:bg-muted',
15
+ props.class,
16
+ )
17
+ "
18
+ >
19
+ <slot />
20
+ </li>
21
+ </template>
@@ -0,0 +1,25 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { Button } from '@/components/ui/button'
4
+ import { cn } from '@/lib/utils'
5
+
6
+ const props = defineProps<{
7
+ class?: HTMLAttributes['class']
8
+ }>()
9
+ </script>
10
+
11
+ <template>
12
+ <Button
13
+ :class="
14
+ cn(
15
+ 'size-auto rounded p-1 text-muted-foreground opacity-0 transition-opacity hover:bg-muted-foreground/10 hover:text-foreground group-hover:opacity-100',
16
+ props.class,
17
+ )
18
+ "
19
+ size="icon"
20
+ type="button"
21
+ variant="ghost"
22
+ >
23
+ <slot />
24
+ </Button>
25
+ </template>
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes['class']
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <div :class="cn('flex gap-1', props.class)">
12
+ <slot />
13
+ </div>
14
+ </template>
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes['class']
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <div :class="cn('mt-1 flex flex-wrap gap-2', props.class)">
12
+ <slot />
13
+ </div>
14
+ </template>
@@ -0,0 +1,32 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+
5
+ interface QueueItemContentProps {
6
+ completed?: boolean
7
+ class?: HTMLAttributes['class']
8
+ }
9
+
10
+ const props = withDefaults(
11
+ defineProps<QueueItemContentProps>(),
12
+ {
13
+ completed: false,
14
+ },
15
+ )
16
+ </script>
17
+
18
+ <template>
19
+ <span
20
+ :class="
21
+ cn(
22
+ 'line-clamp-1 grow break-words',
23
+ props.completed
24
+ ? 'text-muted-foreground/50 line-through'
25
+ : 'text-muted-foreground',
26
+ props.class,
27
+ )
28
+ "
29
+ >
30
+ <slot />
31
+ </span>
32
+ </template>
@@ -0,0 +1,32 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+
5
+ interface QueueItemDescriptionProps {
6
+ completed?: boolean
7
+ class?: HTMLAttributes['class']
8
+ }
9
+
10
+ const props = withDefaults(
11
+ defineProps<QueueItemDescriptionProps>(),
12
+ {
13
+ completed: false,
14
+ },
15
+ )
16
+ </script>
17
+
18
+ <template>
19
+ <div
20
+ :class="
21
+ cn(
22
+ 'ml-6 text-xs',
23
+ props.completed
24
+ ? 'text-muted-foreground/40 line-through'
25
+ : 'text-muted-foreground',
26
+ props.class,
27
+ )
28
+ "
29
+ >
30
+ <slot />
31
+ </div>
32
+ </template>
@@ -0,0 +1,25 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+ import { PaperclipIcon } from 'lucide-vue-next'
5
+
6
+ const props = defineProps<{
7
+ class?: HTMLAttributes['class']
8
+ }>()
9
+ </script>
10
+
11
+ <template>
12
+ <span
13
+ :class="
14
+ cn(
15
+ 'flex items-center gap-1 rounded border bg-muted px-2 py-1 text-xs',
16
+ props.class,
17
+ )
18
+ "
19
+ >
20
+ <PaperclipIcon :size="12" />
21
+ <span class="max-w-[100px] truncate">
22
+ <slot />
23
+ </span>
24
+ </span>
25
+ </template>
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+
5
+ const props = defineProps<{
6
+ class?: HTMLAttributes['class']
7
+ }>()
8
+ </script>
9
+
10
+ <template>
11
+ <img
12
+ alt=""
13
+ :class="cn('h-8 w-8 rounded border object-cover', props.class)"
14
+ height="32"
15
+ width="32"
16
+ v-bind="$attrs"
17
+ >
18
+ </template>
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { cn } from '@/lib/utils'
4
+
5
+ interface QueueItemIndicatorProps {
6
+ completed?: boolean
7
+ class?: HTMLAttributes['class']
8
+ }
9
+
10
+ const props = withDefaults(
11
+ defineProps<QueueItemIndicatorProps>(),
12
+ {
13
+ completed: false,
14
+ },
15
+ )
16
+ </script>
17
+
18
+ <template>
19
+ <span
20
+ :class="
21
+ cn(
22
+ 'mt-0.5 inline-block size-2.5 rounded-full border',
23
+ props.completed
24
+ ? 'border-muted-foreground/20 bg-muted-foreground/10'
25
+ : 'border-muted-foreground/50',
26
+ props.class,
27
+ )
28
+ "
29
+ />
30
+ </template>
@@ -0,0 +1,22 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { ScrollArea } from '@/components/ui/scroll-area'
4
+ import { cn } from '@/lib/utils'
5
+
6
+ const props = defineProps<{
7
+ class?: HTMLAttributes['class']
8
+ }>()
9
+ </script>
10
+
11
+ <template>
12
+ <ScrollArea
13
+ :class="cn('-mb-1 mt-2', props.class)"
14
+ v-bind="$attrs"
15
+ >
16
+ <div class="max-h-40 pr-4">
17
+ <ul>
18
+ <slot />
19
+ </ul>
20
+ </div>
21
+ </ScrollArea>
22
+ </template>
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue'
3
+ import { Collapsible } from '@/components/ui/collapsible'
4
+ import { cn } from '@/lib/utils'
5
+
6
+ interface QueueSectionProps {
7
+ defaultOpen?: boolean
8
+ class?: HTMLAttributes['class']
9
+ }
10
+
11
+ const props = withDefaults(
12
+ defineProps<QueueSectionProps>(),
13
+ {
14
+ defaultOpen: true,
15
+ },
16
+ )
17
+ </script>
18
+
19
+ <template>
20
+ <Collapsible
21
+ :class="cn(props.class)"
22
+ :default-open="props.defaultOpen"
23
+ >
24
+ <slot />
25
+ </Collapsible>
26
+ </template>