@hanzo/ui 4.6.0 → 4.7.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 (290) hide show
  1. package/dist/index.d.mts +16 -0
  2. package/dist/index.d.ts +16 -0
  3. package/dist/index.js +9458 -0
  4. package/dist/index.mjs +9449 -0
  5. package/dist/lib/utils.d.mts +2 -0
  6. package/dist/lib/utils.d.ts +2 -0
  7. package/dist/lib/utils.js +47 -0
  8. package/dist/lib/utils.mjs +28 -0
  9. package/dist/src/utils.d.mts +7 -0
  10. package/dist/src/utils.d.ts +7 -0
  11. package/dist/src/utils.js +47 -0
  12. package/dist/src/utils.mjs +28 -0
  13. package/dist/tailwind/index.d.mts +2 -0
  14. package/dist/tailwind/index.d.ts +2 -0
  15. package/dist/tailwind/index.js +2048 -0
  16. package/dist/tailwind/index.mjs +2017 -0
  17. package/dist/types/index.d.mts +12 -0
  18. package/dist/types/index.d.ts +12 -0
  19. package/dist/types/index.js +79 -0
  20. package/dist/types/index.mjs +56 -0
  21. package/package.json +151 -25
  22. package/MCP-INSTRUCTIONS.md +0 -73
  23. package/README-MCP.md +0 -175
  24. package/assets/ai-icons.tsx +0 -207
  25. package/assets/crypto.tsx +0 -33
  26. package/assets/file-type-icon.tsx +0 -66
  27. package/assets/file.tsx +0 -45
  28. package/assets/general.tsx +0 -2318
  29. package/assets/hanzo-logo.svg +0 -9
  30. package/assets/hanzo-logo.tsx +0 -15
  31. package/assets/index.ts +0 -8
  32. package/assets/index.tsx +0 -4
  33. package/assets/llm-provider.tsx +0 -1094
  34. package/blocks/components/accordian-block.tsx +0 -48
  35. package/blocks/components/block-component-props.ts +0 -11
  36. package/blocks/components/bullet-cards-block.tsx +0 -46
  37. package/blocks/components/card-block/index.tsx +0 -171
  38. package/blocks/components/card-block/link-out-button.tsx +0 -20
  39. package/blocks/components/card-block/util.ts +0 -28
  40. package/blocks/components/carte-blanche-block/index.tsx +0 -127
  41. package/blocks/components/carte-blanche-block/variant-content-left.tsx +0 -49
  42. package/blocks/components/content.tsx +0 -70
  43. package/blocks/components/cta-block.tsx +0 -115
  44. package/blocks/components/enh-heading-block.tsx +0 -204
  45. package/blocks/components/grid-block/grid-block-mutator.ts +0 -12
  46. package/blocks/components/grid-block/index.tsx +0 -83
  47. package/blocks/components/grid-block/mutator-registry.ts +0 -10
  48. package/blocks/components/grid-block/table-borders.mutator.ts +0 -47
  49. package/blocks/components/group-block.tsx +0 -83
  50. package/blocks/components/heading-block.tsx +0 -88
  51. package/blocks/components/image-block.tsx +0 -111
  52. package/blocks/components/index.ts +0 -30
  53. package/blocks/components/screenful-block/content.tsx +0 -123
  54. package/blocks/components/screenful-block/index.tsx +0 -107
  55. package/blocks/components/screenful-block/poster-background.tsx +0 -34
  56. package/blocks/components/screenful-block/video-background.tsx +0 -45
  57. package/blocks/components/space-block.tsx +0 -66
  58. package/blocks/components/video-block.tsx +0 -138
  59. package/blocks/def/accordian-block.ts +0 -14
  60. package/blocks/def/block.ts +0 -7
  61. package/blocks/def/bullet-cards-block.ts +0 -22
  62. package/blocks/def/card-block.ts +0 -22
  63. package/blocks/def/carte-blanche-block.ts +0 -21
  64. package/blocks/def/cta-block.ts +0 -19
  65. package/blocks/def/element-block.ts +0 -11
  66. package/blocks/def/enh-heading-block.ts +0 -44
  67. package/blocks/def/grid-block.ts +0 -16
  68. package/blocks/def/group-block.ts +0 -11
  69. package/blocks/def/heading-block.ts +0 -15
  70. package/blocks/def/image-block.ts +0 -31
  71. package/blocks/def/index.ts +0 -35
  72. package/blocks/def/screenful-block.ts +0 -54
  73. package/blocks/def/space-block.ts +0 -64
  74. package/blocks/def/video-block.ts +0 -9
  75. package/blocks/index.ts +0 -2
  76. package/components/index.ts +0 -56
  77. package/dist/button.d.ts +0 -1
  78. package/dist/button.js +0 -1
  79. package/dist/hooks/index.d.ts +0 -7
  80. package/dist/hooks/index.js +0 -7
  81. package/dist/hooks/use-click-away.d.ts +0 -2
  82. package/dist/hooks/use-click-away.js +0 -23
  83. package/dist/hooks/use-combined-refs.d.ts +0 -3
  84. package/dist/hooks/use-combined-refs.js +0 -18
  85. package/dist/hooks/use-copy-clipboard.d.ts +0 -9
  86. package/dist/hooks/use-copy-clipboard.js +0 -21
  87. package/dist/hooks/use-debounce.d.ts +0 -1
  88. package/dist/hooks/use-debounce.js +0 -13
  89. package/dist/hooks/use-fill-ids.d.ts +0 -8
  90. package/dist/hooks/use-fill-ids.js +0 -20
  91. package/dist/hooks/use-map.d.ts +0 -1
  92. package/dist/hooks/use-map.js +0 -20
  93. package/dist/hooks/use-measure.d.ts +0 -8
  94. package/dist/hooks/use-measure.js +0 -25
  95. package/dist/hooks/use-reverse-video-playback.d.ts +0 -1
  96. package/dist/hooks/use-reverse-video-playback.js +0 -41
  97. package/dist/hooks/use-scroll-restoration.d.ts +0 -8
  98. package/dist/hooks/use-scroll-restoration.js +0 -36
  99. package/dist/mcp/enhanced-server.d.ts +0 -29
  100. package/dist/mcp/enhanced-server.js +0 -1128
  101. package/dist/mcp/index.d.ts +0 -28
  102. package/dist/mcp/index.js +0 -436
  103. package/dist/registry/api.d.ts +0 -37
  104. package/dist/registry/api.js +0 -129
  105. package/dist/registry/index.d.ts +0 -353
  106. package/dist/registry/index.js +0 -45
  107. package/dist/utils.d.ts +0 -1
  108. package/dist/utils.js +0 -1
  109. package/environment.d.ts +0 -6
  110. package/helpers/file.ts +0 -33
  111. package/helpers/memoization.ts +0 -40
  112. package/primitives/accordion.tsx +0 -74
  113. package/primitives/action-button.tsx +0 -42
  114. package/primitives/alert-dialog.tsx +0 -185
  115. package/primitives/alert.tsx +0 -74
  116. package/primitives/apply-typography.tsx +0 -55
  117. package/primitives/aspect-ratio.tsx +0 -5
  118. package/primitives/avatar.tsx +0 -57
  119. package/primitives/background-beams.tsx +0 -142
  120. package/primitives/badge.tsx +0 -44
  121. package/primitives/breadcrumb.tsx +0 -130
  122. package/primitives/breakpoint-indicator.tsx +0 -19
  123. package/primitives/button.tsx +0 -82
  124. package/primitives/calendar.tsx +0 -72
  125. package/primitives/card.tsx +0 -97
  126. package/primitives/carousel.tsx +0 -237
  127. package/primitives/chat/chat-input-area.tsx +0 -87
  128. package/primitives/chat/chat-input.tsx +0 -71
  129. package/primitives/chat/files-preview.tsx +0 -330
  130. package/primitives/chat/index.ts +0 -6
  131. package/primitives/chat/json-form.tsx +0 -8
  132. package/primitives/chat/message-list.tsx +0 -307
  133. package/primitives/chat/message.tsx +0 -569
  134. package/primitives/chat/sqlite-preview.tsx +0 -215
  135. package/primitives/checkbox.tsx +0 -31
  136. package/primitives/collapsible.tsx +0 -9
  137. package/primitives/combobox.tsx +0 -239
  138. package/primitives/command.tsx +0 -149
  139. package/primitives/context-menu.tsx +0 -206
  140. package/primitives/copy-to-clipboard-icon.tsx +0 -60
  141. package/primitives/dialog-video-controller.tsx +0 -38
  142. package/primitives/dialog.tsx +0 -123
  143. package/primitives/dot-pattern.tsx +0 -57
  144. package/primitives/dots-loader.tsx +0 -13
  145. package/primitives/drawer.tsx +0 -110
  146. package/primitives/dropdown-menu.tsx +0 -199
  147. package/primitives/error-message.tsx +0 -19
  148. package/primitives/file-uploader.tsx +0 -200
  149. package/primitives/form.tsx +0 -183
  150. package/primitives/hover-card.tsx +0 -28
  151. package/primitives/icons/github.tsx +0 -14
  152. package/primitives/icons/index.ts +0 -18
  153. package/primitives/icons/youtube-logo.tsx +0 -59
  154. package/primitives/index-common.ts +0 -303
  155. package/primitives/index-next.ts +0 -4
  156. package/primitives/input-otp.tsx +0 -65
  157. package/primitives/input.tsx +0 -125
  158. package/primitives/label.tsx +0 -20
  159. package/primitives/list-adaptor.ts +0 -12
  160. package/primitives/list-box.tsx +0 -74
  161. package/primitives/loading-spinner.tsx +0 -33
  162. package/primitives/markdown-preview.tsx +0 -609
  163. package/primitives/mermaid.tsx +0 -196
  164. package/primitives/navigation-menu.tsx +0 -147
  165. package/primitives/next/image.tsx +0 -90
  166. package/primitives/next/index.ts +0 -7
  167. package/primitives/next/inline-icon.tsx +0 -36
  168. package/primitives/next/link-element.tsx +0 -109
  169. package/primitives/next/mdx-link.tsx +0 -22
  170. package/primitives/next/media-stack.tsx +0 -69
  171. package/primitives/next/nav-items.tsx +0 -45
  172. package/primitives/next/youtube-embed.tsx +0 -83
  173. package/primitives/pagination.tsx +0 -117
  174. package/primitives/popover.tsx +0 -32
  175. package/primitives/pretty-json-print.tsx +0 -28
  176. package/primitives/progress.tsx +0 -26
  177. package/primitives/prompt-textarea.tsx +0 -72
  178. package/primitives/qr-code.tsx +0 -112
  179. package/primitives/radio-group.tsx +0 -42
  180. package/primitives/resizable.tsx +0 -47
  181. package/primitives/scroll-area.tsx +0 -57
  182. package/primitives/search-input.tsx +0 -66
  183. package/primitives/select.tsx +0 -122
  184. package/primitives/separator.tsx +0 -25
  185. package/primitives/sheet.tsx +0 -139
  186. package/primitives/skeleton.tsx +0 -17
  187. package/primitives/slider.tsx +0 -62
  188. package/primitives/sonner.tsx +0 -35
  189. package/primitives/step-indicator.tsx +0 -69
  190. package/primitives/stepper.tsx +0 -272
  191. package/primitives/switch.tsx +0 -26
  192. package/primitives/table.tsx +0 -105
  193. package/primitives/tabs.tsx +0 -50
  194. package/primitives/text-area.tsx +0 -26
  195. package/primitives/text-link.tsx +0 -25
  196. package/primitives/textarea.tsx +0 -61
  197. package/primitives/textfield.tsx +0 -75
  198. package/primitives/toast.tsx +0 -30
  199. package/primitives/toggle-group.tsx +0 -63
  200. package/primitives/toggle.tsx +0 -44
  201. package/primitives/tooltip.tsx +0 -47
  202. package/primitives/video-player.tsx +0 -23
  203. package/public/r/accordion.json +0 -11
  204. package/public/r/alert.json +0 -11
  205. package/public/r/avatar.json +0 -11
  206. package/public/r/badge.json +0 -11
  207. package/public/r/button.json +0 -11
  208. package/public/r/card.json +0 -11
  209. package/public/r/checkbox.json +0 -11
  210. package/public/r/default.json +0 -6
  211. package/public/r/dialog.json +0 -11
  212. package/public/r/input.json +0 -11
  213. package/public/r/label.json +0 -11
  214. package/public/r/new-york.json +0 -6
  215. package/public/r/popover.json +0 -11
  216. package/public/r/select.json +0 -11
  217. package/public/r/table.json +0 -11
  218. package/public/r/tabs.json +0 -11
  219. package/public/r/toast.json +0 -11
  220. package/registry.json +0 -184
  221. package/src/button.ts +0 -1
  222. package/src/hooks/index.ts +0 -7
  223. package/src/hooks/use-click-away.ts +0 -31
  224. package/src/hooks/use-combined-refs.ts +0 -22
  225. package/src/hooks/use-copy-clipboard.ts +0 -30
  226. package/src/hooks/use-debounce.ts +0 -17
  227. package/src/hooks/use-fill-ids.ts +0 -25
  228. package/src/hooks/use-map.ts +0 -26
  229. package/src/hooks/use-measure.ts +0 -42
  230. package/src/hooks/use-reverse-video-playback.ts +0 -43
  231. package/src/hooks/use-scroll-restoration.ts +0 -50
  232. package/src/mcp/README.md +0 -141
  233. package/src/mcp/enhanced-server.ts +0 -1208
  234. package/src/mcp/index.ts +0 -518
  235. package/src/mcp/package.json +0 -10
  236. package/src/registry/api.ts +0 -164
  237. package/src/registry/index.ts +0 -60
  238. package/src/registry/package.json +0 -10
  239. package/src/utils.ts +0 -1
  240. package/tailwind/colors.tailwind.js +0 -53
  241. package/tailwind/fontFamily.tailwind.ts +0 -7
  242. package/tailwind/fontSize.tailwind.ts +0 -13
  243. package/tailwind/index.ts +0 -7
  244. package/tailwind/safelist.tailwind.js +0 -26
  245. package/tailwind/screens.tailwind.js +0 -8
  246. package/tailwind/spacing.tailwind.js +0 -65
  247. package/tailwind/tailwind.config.hanzo-preset.d.ts +0 -5
  248. package/tailwind/tailwind.config.hanzo-preset.js +0 -915
  249. package/tailwind/tw-font-desc.ts +0 -15
  250. package/tailwind/typo-plugin/get-plugin-styles.js +0 -679
  251. package/tailwind/typo-plugin/index.d.ts +0 -9
  252. package/tailwind/typo-plugin/index.js +0 -141
  253. package/tailwind/typo-plugin/utils.js +0 -60
  254. package/tailwind/typography-test.mdx +0 -35
  255. package/tailwind/z-index.tailwind.js +0 -71
  256. package/test/test-registry.js +0 -73
  257. package/test-imports.mjs +0 -19
  258. package/tsconfig.json +0 -22
  259. package/types/animation-def.ts +0 -3
  260. package/types/breakpoints.ts +0 -11
  261. package/types/bullet-item.ts +0 -10
  262. package/types/button-def.ts +0 -39
  263. package/types/dimensions.ts +0 -8
  264. package/types/grid-def.ts +0 -56
  265. package/types/image-def.ts +0 -32
  266. package/types/index.ts +0 -29
  267. package/types/link-def.ts +0 -56
  268. package/types/media-stack-def.ts +0 -31
  269. package/types/t-shirt-size.ts +0 -5
  270. package/types/tshirt-dimensions.ts +0 -20
  271. package/types/video-def.ts +0 -25
  272. package/util/blob.ts +0 -28
  273. package/util/copy-to-clipboard.ts +0 -17
  274. package/util/create-shadow-root.ts +0 -22
  275. package/util/date.ts +0 -83
  276. package/util/debounce.ts +0 -11
  277. package/util/file.ts +0 -15
  278. package/util/format-and-abbreviate-as-currency.ts +0 -125
  279. package/util/format-text.ts +0 -33
  280. package/util/format-to-max-char.ts +0 -68
  281. package/util/index-client.ts +0 -3
  282. package/util/index.ts +0 -9
  283. package/util/number-abbreviate.ts +0 -49
  284. package/util/specifier.ts +0 -43
  285. package/util/spread-to-transform.ts +0 -24
  286. package/util/step-animation.ts +0 -90
  287. package/util/timing.ts +0 -3
  288. package/util/toasts.tsx +0 -17
  289. package/util/two-way-map.ts +0 -19
  290. package/utils.ts +0 -9
@@ -1,87 +0,0 @@
1
- import { useTranslation } from '@hanzo_network/hanzo-i18n';
2
- import * as React from 'react';
3
-
4
- import { useCombinedRefs } from '../../hooks/use-combined-refs';
5
- import { cn } from '../src/utils';
6
- import { ChatInput } from './chat-input';
7
-
8
- type ChatInputAreaProps = {
9
- value: string;
10
- onChange: (value: string) => void;
11
- onKeyDown?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
12
- onPaste?: (e: React.ClipboardEvent<HTMLTextAreaElement>) => void;
13
- onSubmit: () => void;
14
- disabled?: boolean;
15
- autoFocus?: boolean;
16
- isLoading?: boolean;
17
- placeholder?: string;
18
- topAddons?: React.ReactNode;
19
- bottomAddons?: React.ReactNode;
20
- textareaClassName?: string;
21
- className?: string;
22
- alternateElement?: React.ReactNode;
23
- ref?: React.RefObject<HTMLTextAreaElement | null>;
24
- };
25
- export const ChatInputArea = ({
26
- value,
27
- onChange,
28
- onPaste,
29
- onKeyDown,
30
- autoFocus,
31
- onSubmit,
32
- disabled,
33
- isLoading,
34
- placeholder,
35
- topAddons,
36
- bottomAddons,
37
- textareaClassName,
38
- alternateElement,
39
- className,
40
- ref,
41
- }: ChatInputAreaProps) => {
42
- const { t } = useTranslation();
43
- const textareaRef = useCombinedRefs<HTMLTextAreaElement>(
44
- ref as React.RefObject<HTMLTextAreaElement>,
45
- );
46
-
47
- return (
48
- <div
49
- className={cn(
50
- 'bg-bg-secondary flex w-full max-w-full flex-col rounded-xl text-sm aria-disabled:cursor-not-allowed aria-disabled:opacity-50',
51
- 'shadow-border-input focus-within:shadow-border-input-focus overflow-hidden shadow-[0_0_0_1px_currentColor] transition-shadow',
52
- className,
53
- )}
54
- >
55
- {topAddons}
56
- <div
57
- aria-disabled={disabled}
58
- className="flex cursor-text flex-col aria-disabled:cursor-not-allowed"
59
- onClick={(e) => {
60
- if (e.target === e.currentTarget) {
61
- textareaRef?.current?.focus();
62
- }
63
- }}
64
- >
65
- {alternateElement ? (
66
- alternateElement
67
- ) : (
68
- <ChatInput
69
- autoFocus={autoFocus}
70
- className={textareaClassName}
71
- disabled={disabled || isLoading}
72
- onChange={(e) => onChange(e.target.value)}
73
- onKeyDown={onKeyDown}
74
- onPaste={onPaste}
75
- onSend={onSubmit}
76
- placeholder={placeholder ?? t('chat.sendMessagePlaceholder')}
77
- ref={textareaRef}
78
- value={value}
79
- />
80
- )}
81
- {bottomAddons}
82
- </div>
83
- </div>
84
- );
85
- };
86
-
87
- ChatInputArea.displayName = 'ChatInputArea';
@@ -1,71 +0,0 @@
1
- import * as React from 'react';
2
-
3
- import { cn } from '../src/utils';
4
-
5
- export interface ChatInputProps
6
- extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
7
- onSend?: () => void;
8
- ref: React.RefObject<HTMLTextAreaElement | null>;
9
- }
10
-
11
- export const useAutoResizeTextarea = (
12
- ref: React.RefObject<HTMLTextAreaElement | null>,
13
- value: string | number | readonly string[] | undefined,
14
- autoResize = true, //later to unify
15
- ) => {
16
- const textAreaRef = React.useRef<HTMLTextAreaElement>(null);
17
-
18
- React.useImperativeHandle(ref, () => textAreaRef.current!);
19
-
20
- React.useEffect(() => {
21
- const ref = textAreaRef?.current;
22
-
23
- const updateTextareaHeight = () => {
24
- if (ref && autoResize) {
25
- ref.style.height = 'auto';
26
- ref.style.height = ref?.scrollHeight + 'px';
27
- }
28
- };
29
-
30
- updateTextareaHeight();
31
-
32
- ref?.addEventListener('input', updateTextareaHeight);
33
- return () => ref?.removeEventListener('input', updateTextareaHeight);
34
- // eslint-disable-next-line react-hooks/exhaustive-deps
35
- }, [value]);
36
-
37
- return { textAreaRef };
38
- };
39
-
40
- const ChatInputBase = ({
41
- className,
42
- onSend,
43
- onKeyDown,
44
- ref,
45
- ...props
46
- }: ChatInputProps) => {
47
- const { textAreaRef } = useAutoResizeTextarea(ref, props.value);
48
-
49
- return (
50
- <textarea
51
- className={cn(
52
- 'placeholder:!text-text-placeholder flex max-h-[40vh] min-h-[80px] w-full resize-none overflow-y-auto border-none bg-transparent px-3 py-2 text-base leading-normal break-words focus:outline-hidden focus-visible:ring-0 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
53
- className,
54
- )}
55
- id="chat-input"
56
- onKeyDown={(event) => {
57
- onKeyDown?.(event);
58
- if (event.key === 'Enter' && !event.shiftKey) {
59
- event.preventDefault();
60
- onSend?.();
61
- }
62
- }}
63
- ref={textAreaRef}
64
- spellCheck={false}
65
- {...props}
66
- />
67
- );
68
- };
69
-
70
- ChatInputBase.displayName = 'ChatInput';
71
- export const ChatInput = React.memo(ChatInputBase);
@@ -1,330 +0,0 @@
1
- import { DialogClose } from '@radix-ui/react-dialog';
2
- import {
3
- type Attachment,
4
- FileTypeSupported,
5
- } from '@hanzo_network/hanzo-node-state/v2/queries/getChatConversation/types';
6
- import { save } from '@tauri-apps/plugin-dialog';
7
- import * as fs from '@tauri-apps/plugin-fs';
8
- import { BaseDirectory } from '@tauri-apps/plugin-fs';
9
- import { partial } from 'filesize';
10
- import { AnimatePresence, motion } from 'framer-motion';
11
- import { CircleSlashIcon, XIcon } from 'lucide-react';
12
- import React, { useState } from 'react';
13
- import { toast } from 'sonner';
14
-
15
- import { fileIconMap, FileTypeIcon, PaperClipIcon } from '../../assets';
16
- import { getFileExt } from '../../helpers/file';
17
- import { cn } from '../../src/utils';
18
- import { Avatar, AvatarFallback, AvatarImage } from '../avatar';
19
- import { Button } from '../button';
20
- import { Dialog, DialogContent } from '../dialog';
21
- import {
22
- Tooltip,
23
- TooltipContent,
24
- TooltipPortal,
25
- TooltipTrigger,
26
- } from '../tooltip';
27
- import { SqlitePreview } from './sqlite-preview';
28
-
29
- export type FileListProps = {
30
- files: Attachment[];
31
- className?: string;
32
- };
33
-
34
- export const isImageFile = (file: string) => {
35
- return file.match(/\.(jpg|jpeg|png|gif)$/i);
36
- };
37
-
38
- const size = partial({ standard: 'jedec' });
39
-
40
- const ImagePreview = ({
41
- name,
42
- size,
43
- url,
44
- onFullscreen,
45
- }: Pick<Attachment, 'name' | 'size' | 'url'> & {
46
- onFullscreen: (open: boolean) => void;
47
- }) => (
48
- <button
49
- className="border-divider hover:bg-bg-secondary flex h-14 w-full max-w-[210px] min-w-[210px] shrink-0 cursor-pointer items-center gap-2 rounded-md border py-1.5 pr-1.5 pl-2 text-left"
50
- onClick={() => onFullscreen(true)}
51
- >
52
- <Avatar className="bg-bg-quaternary text-text-default flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-xs transition-colors">
53
- <AvatarImage
54
- alt={name}
55
- className="border-divider aspect-square h-full w-full rounded-xs border object-cover"
56
- src={url}
57
- />
58
- <AvatarFallback>
59
- <CircleSlashIcon className="text-text-secondary h-4 w-4" />
60
- </AvatarFallback>
61
- </Avatar>
62
- <FileInfo fileName={name} fileSize={size} />
63
- </button>
64
- );
65
-
66
- const FileInfo = ({
67
- fileSize,
68
- fileName,
69
- }: {
70
- fileSize?: number;
71
- fileName: string;
72
- }) => (
73
- <div className="text-text-secondary text-em-sm grid flex-1 -translate-x-px gap-1 py-0.5 leading-none">
74
- <div className="text-text-default truncate overflow-hidden font-medium">
75
- {decodeURIComponent(fileName.split('/').at(-1) ?? '')}
76
- </div>
77
- {fileSize && (
78
- <div className="text-text-secondary line-clamp-1 aspect-auto font-normal">
79
- {size(fileSize)}
80
- </div>
81
- )}
82
- </div>
83
- );
84
-
85
- type FileContentViewerProps = Pick<
86
- Attachment,
87
- 'name' | 'url' | 'content' | 'type'
88
- >;
89
-
90
- export const FileContentViewer: React.FC<FileContentViewerProps> = ({
91
- name,
92
- content,
93
- url,
94
- type,
95
- }) => {
96
- switch (type) {
97
- case FileTypeSupported.Text: {
98
- return (
99
- <pre className="bg-bg-dark h-full overflow-auto p-4 pt-10 font-mono text-xs break-words whitespace-pre-wrap">
100
- {content}
101
- </pre>
102
- );
103
- }
104
- case FileTypeSupported.Image: {
105
- return (
106
- <div className="flex h-full w-full items-center justify-center">
107
- <img
108
- alt={name}
109
- className="max-h-full max-w-full object-contain"
110
- src={url}
111
- />
112
- </div>
113
- );
114
- }
115
- case FileTypeSupported.Video: {
116
- return (
117
- <div className="flex h-full w-full items-center justify-center">
118
- <video className="max-h-full max-w-full" controls src={url}>
119
- Your browser does not support the video tag.
120
- </video>
121
- </div>
122
- );
123
- }
124
- case FileTypeSupported.Audio: {
125
- return (
126
- <div className="flex h-full w-full items-center justify-center">
127
- <audio className="w-full" controls src={url}>
128
- Your browser does not support the audio tag.
129
- </audio>
130
- </div>
131
- );
132
- }
133
- case FileTypeSupported.Html: {
134
- return (
135
- <div className="flex h-full w-full items-center justify-center">
136
- <iframe
137
- className="h-full w-full bg-gray-100"
138
- sandbox="allow-same-origin"
139
- src={url}
140
- title={name}
141
- />
142
- </div>
143
- );
144
- }
145
- case FileTypeSupported.SqliteDatabase: {
146
- return <SqlitePreview url={url || ''} />;
147
- }
148
- default:
149
- return (
150
- <div className="text-text-secondary flex h-full flex-col items-center justify-center gap-6">
151
- <span>Preview not available for this file type</span>
152
- </div>
153
- );
154
- }
155
- };
156
-
157
- const FullscreenDialog = ({
158
- open,
159
- name,
160
- type,
161
- url,
162
- content,
163
- setOpen,
164
- onDownload,
165
- }: Pick<Attachment, 'name' | 'url' | 'content' | 'type'> & {
166
- open: boolean;
167
- setOpen: (open: boolean) => void;
168
- onDownload?: () => void;
169
- }) => (
170
- <Dialog onOpenChange={setOpen} open={open}>
171
- <DialogContent className="flex size-full max-h-[99vh] max-w-[99vw] flex-col gap-2 bg-transparent p-1 py-8">
172
- <div className="flex w-full items-center justify-between gap-16 px-10">
173
- <div className="text-text-default max-w-3xl truncate text-left text-sm">
174
- {name}
175
- </div>
176
- <div className="flex items-center gap-4">
177
- <Button onClick={onDownload} size="xs" variant="outline">
178
- Download
179
- </Button>
180
- <DialogClose>
181
- <XIcon className="text-text-secondary h-6 w-6" />
182
- <span className="sr-only">Close</span>
183
- </DialogClose>
184
- </div>
185
- </div>
186
- <div className="text-text-default flex size-full flex-col overflow-hidden rounded-l-xl p-10">
187
- <FileContentViewer
188
- content={content}
189
- name={name}
190
- type={type}
191
- url={url}
192
- />
193
- </div>
194
- </DialogContent>
195
- </Dialog>
196
- );
197
- const FileButton = ({
198
- name,
199
- size,
200
- onFullscreen,
201
- }: Pick<Attachment, 'name' | 'size'> & {
202
- onFullscreen: (open: boolean) => void;
203
- }) => (
204
- <button
205
- className="border-divider hover:bg-bg-secondary flex h-14 w-full max-w-[210px] min-w-[210px] shrink-0 cursor-pointer items-center gap-2 rounded-md border py-1.5 pr-1.5 pl-2 text-left"
206
- onClick={() => onFullscreen(true)}
207
- >
208
- <span className="bg-bg-quaternary text-text-default flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-xs transition-colors">
209
- {fileIconMap[getFileExt(name)] ? (
210
- <FileTypeIcon
211
- className="text-text-secondary h-5 w-5"
212
- type={getFileExt(name)}
213
- />
214
- ) : (
215
- <PaperClipIcon className="text-text-secondary h-4 w-4" />
216
- )}
217
- </span>
218
- <FileInfo fileName={name} fileSize={size} />
219
- </button>
220
- );
221
-
222
- export const FilePreview = ({
223
- name,
224
- url,
225
- size,
226
- content,
227
- blob,
228
- type,
229
- }: Attachment) => {
230
- const [open, setOpen] = useState(false);
231
-
232
- const fileName = decodeURIComponent(name).split('/').at(-1) ?? '';
233
-
234
- const children = isImageFile(name) ? (
235
- <ImagePreview name={name} onFullscreen={setOpen} size={size} url={url} />
236
- ) : (
237
- <FileButton name={name} onFullscreen={setOpen} size={size} />
238
- );
239
-
240
- return (
241
- <Tooltip>
242
- <TooltipTrigger asChild>
243
- <div>{children}</div>
244
- </TooltipTrigger>
245
- <TooltipPortal>
246
- <TooltipContent className="container break-words" side="top">
247
- <p>{fileName}</p>
248
- </TooltipContent>
249
- </TooltipPortal>
250
- <FullscreenDialog
251
- content={content}
252
- name={fileName}
253
- onDownload={async () => {
254
- const currentFile =
255
- blob ??
256
- new Blob([content || url || ''], {
257
- type: 'application/octet-stream',
258
- });
259
- const arrayBuffer = await currentFile.arrayBuffer();
260
- const currentContent = new Uint8Array(arrayBuffer);
261
- const savePath = await save({
262
- defaultPath: fileName,
263
- filters: [
264
- {
265
- name: 'File',
266
- extensions: [getFileExt(name)],
267
- },
268
- ],
269
- });
270
- if (!savePath) {
271
- toast.info('File saving cancelled');
272
- return;
273
- }
274
-
275
- await fs.writeFile(savePath, currentContent, {
276
- baseDir: BaseDirectory.Download,
277
- });
278
-
279
- toast.success(`${fileName} downloaded successfully`);
280
- }}
281
- open={open}
282
- setOpen={setOpen}
283
- type={type}
284
- url={url}
285
- />
286
- </Tooltip>
287
- );
288
- };
289
-
290
- const animations = {
291
- initial: { scale: 0.97, opacity: 0, y: 10 },
292
- animate: {
293
- scale: 1,
294
- opacity: 1,
295
- y: 0,
296
- transition: {
297
- type: 'spring',
298
- stiffness: 200,
299
- damping: 20,
300
- mass: 0.8,
301
- velocity: 1,
302
- duration: 0.6,
303
- },
304
- },
305
- exit: {
306
- scale: 0.97,
307
- opacity: 0,
308
- y: -10,
309
- transition: {
310
- type: 'spring',
311
- stiffness: 150,
312
- damping: 15,
313
- duration: 0.4,
314
- },
315
- },
316
- };
317
-
318
- export const FileList = ({ files, className }: FileListProps) => {
319
- return (
320
- <ul className={cn('flex flex-wrap gap-3', className)}>
321
- <AnimatePresence>
322
- {files?.map((file, index) => (
323
- <motion.li {...animations} key={index}>
324
- <FilePreview {...file} />
325
- </motion.li>
326
- ))}
327
- </AnimatePresence>
328
- </ul>
329
- );
330
- };
@@ -1,6 +0,0 @@
1
- export * from './message';
2
- export * from './message-list';
3
- export * from './files-preview';
4
- export * from './chat-input-area';
5
- export * from './chat-input';
6
- export * from './sqlite-preview';
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
-
3
- // Temporary stub for JsonForm - will be replaced with actual implementation
4
- const JsonForm: React.FC<any> = (props) => {
5
- return <div>JsonForm Component - To be implemented</div>;
6
- };
7
-
8
- export default JsonForm;