doclific 0.2.0 → 0.2.2

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 (220) hide show
  1. package/LICENSE +17 -0
  2. package/dist/bin/doclific.js +36 -8
  3. package/package.json +11 -4
  4. package/readme.md +77 -0
  5. package/.gitattributes +0 -2
  6. package/.prettierignore +0 -5
  7. package/.prettierrc +0 -9
  8. package/.vscode/settings.json +0 -13
  9. package/frontend/components.json +0 -24
  10. package/frontend/eslint.config.js +0 -23
  11. package/frontend/index.html +0 -25
  12. package/frontend/package-lock.json +0 -15754
  13. package/frontend/public/logo.svg +0 -1
  14. package/frontend/src/App.tsx +0 -21
  15. package/frontend/src/components/app-sidebar.tsx +0 -393
  16. package/frontend/src/components/editor/editor-base-kit.tsx +0 -43
  17. package/frontend/src/components/editor/editor-kit.tsx +0 -93
  18. package/frontend/src/components/editor/plugins/align-base-kit.tsx +0 -16
  19. package/frontend/src/components/editor/plugins/align-kit.tsx +0 -18
  20. package/frontend/src/components/editor/plugins/autoformat-kit.tsx +0 -236
  21. package/frontend/src/components/editor/plugins/basic-blocks-base-kit.tsx +0 -35
  22. package/frontend/src/components/editor/plugins/basic-blocks-kit.tsx +0 -88
  23. package/frontend/src/components/editor/plugins/basic-marks-base-kit.tsx +0 -27
  24. package/frontend/src/components/editor/plugins/basic-marks-kit.tsx +0 -41
  25. package/frontend/src/components/editor/plugins/basic-nodes-kit.tsx +0 -6
  26. package/frontend/src/components/editor/plugins/block-menu-kit.tsx +0 -14
  27. package/frontend/src/components/editor/plugins/block-placeholder-kit.tsx +0 -17
  28. package/frontend/src/components/editor/plugins/block-selection-kit.tsx +0 -32
  29. package/frontend/src/components/editor/plugins/callout-base-kit.tsx +0 -7
  30. package/frontend/src/components/editor/plugins/callout-kit.tsx +0 -7
  31. package/frontend/src/components/editor/plugins/code-block-base-kit.tsx +0 -23
  32. package/frontend/src/components/editor/plugins/code-block-kit.tsx +0 -26
  33. package/frontend/src/components/editor/plugins/codebase-kit.tsx +0 -23
  34. package/frontend/src/components/editor/plugins/column-base-kit.tsx +0 -11
  35. package/frontend/src/components/editor/plugins/column-kit.tsx +0 -10
  36. package/frontend/src/components/editor/plugins/comment-base-kit.tsx +0 -7
  37. package/frontend/src/components/editor/plugins/comment-kit.tsx +0 -97
  38. package/frontend/src/components/editor/plugins/cursor-overlay-kit.tsx +0 -13
  39. package/frontend/src/components/editor/plugins/date-base-kit.tsx +0 -5
  40. package/frontend/src/components/editor/plugins/date-kit.tsx +0 -7
  41. package/frontend/src/components/editor/plugins/discussion-kit.tsx +0 -148
  42. package/frontend/src/components/editor/plugins/dnd-kit.tsx +0 -28
  43. package/frontend/src/components/editor/plugins/docx-kit.tsx +0 -6
  44. package/frontend/src/components/editor/plugins/emoji-kit.tsx +0 -13
  45. package/frontend/src/components/editor/plugins/excalidraw-kit.tsx +0 -9
  46. package/frontend/src/components/editor/plugins/exit-break-kit.tsx +0 -12
  47. package/frontend/src/components/editor/plugins/floating-toolbar-kit.tsx +0 -19
  48. package/frontend/src/components/editor/plugins/font-base-kit.tsx +0 -20
  49. package/frontend/src/components/editor/plugins/font-kit.tsx +0 -29
  50. package/frontend/src/components/editor/plugins/indent-base-kit.tsx +0 -19
  51. package/frontend/src/components/editor/plugins/indent-kit.tsx +0 -22
  52. package/frontend/src/components/editor/plugins/line-height-base-kit.tsx +0 -14
  53. package/frontend/src/components/editor/plugins/line-height-kit.tsx +0 -16
  54. package/frontend/src/components/editor/plugins/link-base-kit.tsx +0 -5
  55. package/frontend/src/components/editor/plugins/link-kit.tsx +0 -15
  56. package/frontend/src/components/editor/plugins/list-base-kit.tsx +0 -23
  57. package/frontend/src/components/editor/plugins/list-kit.tsx +0 -26
  58. package/frontend/src/components/editor/plugins/markdown-kit.tsx +0 -46
  59. package/frontend/src/components/editor/plugins/math-base-kit.tsx +0 -11
  60. package/frontend/src/components/editor/plugins/math-kit.tsx +0 -13
  61. package/frontend/src/components/editor/plugins/media-base-kit.tsx +0 -31
  62. package/frontend/src/components/editor/plugins/media-kit.tsx +0 -43
  63. package/frontend/src/components/editor/plugins/mention-base-kit.tsx +0 -7
  64. package/frontend/src/components/editor/plugins/mention-kit.tsx +0 -15
  65. package/frontend/src/components/editor/plugins/slash-kit.tsx +0 -18
  66. package/frontend/src/components/editor/plugins/suggestion-base-kit.tsx +0 -7
  67. package/frontend/src/components/editor/plugins/suggestion-kit.tsx +0 -90
  68. package/frontend/src/components/editor/plugins/table-base-kit.tsx +0 -20
  69. package/frontend/src/components/editor/plugins/table-kit.tsx +0 -22
  70. package/frontend/src/components/editor/plugins/toc-base-kit.tsx +0 -5
  71. package/frontend/src/components/editor/plugins/toc-kit.tsx +0 -14
  72. package/frontend/src/components/editor/plugins/toggle-base-kit.tsx +0 -7
  73. package/frontend/src/components/editor/plugins/toggle-kit.tsx +0 -11
  74. package/frontend/src/components/editor/transforms.ts +0 -194
  75. package/frontend/src/components/markdown-to-slate-demo.tsx +0 -50
  76. package/frontend/src/components/mode-toggle.tsx +0 -15
  77. package/frontend/src/components/theme-provider.tsx +0 -73
  78. package/frontend/src/components/ui/alert-dialog.tsx +0 -155
  79. package/frontend/src/components/ui/align-toolbar-button.tsx +0 -84
  80. package/frontend/src/components/ui/avatar.tsx +0 -51
  81. package/frontend/src/components/ui/block-context-menu.tsx +0 -199
  82. package/frontend/src/components/ui/block-discussion.tsx +0 -365
  83. package/frontend/src/components/ui/block-draggable.tsx +0 -512
  84. package/frontend/src/components/ui/block-list-static.tsx +0 -80
  85. package/frontend/src/components/ui/block-list.tsx +0 -87
  86. package/frontend/src/components/ui/block-selection.tsx +0 -42
  87. package/frontend/src/components/ui/block-suggestion.tsx +0 -473
  88. package/frontend/src/components/ui/blockquote-node-static.tsx +0 -11
  89. package/frontend/src/components/ui/blockquote-node.tsx +0 -13
  90. package/frontend/src/components/ui/button.tsx +0 -62
  91. package/frontend/src/components/ui/calendar.tsx +0 -218
  92. package/frontend/src/components/ui/callout-node-static.tsx +0 -36
  93. package/frontend/src/components/ui/callout-node.tsx +0 -63
  94. package/frontend/src/components/ui/caption.tsx +0 -63
  95. package/frontend/src/components/ui/checkbox.tsx +0 -30
  96. package/frontend/src/components/ui/code-block-node-static.tsx +0 -35
  97. package/frontend/src/components/ui/code-block-node.tsx +0 -287
  98. package/frontend/src/components/ui/code-node-static.tsx +0 -15
  99. package/frontend/src/components/ui/code-node.tsx +0 -17
  100. package/frontend/src/components/ui/codebase-snippet-node.tsx +0 -237
  101. package/frontend/src/components/ui/column-node-static.tsx +0 -29
  102. package/frontend/src/components/ui/column-node.tsx +0 -317
  103. package/frontend/src/components/ui/command.tsx +0 -182
  104. package/frontend/src/components/ui/comment-node-static.tsx +0 -15
  105. package/frontend/src/components/ui/comment-node.tsx +0 -45
  106. package/frontend/src/components/ui/comment-toolbar-button.tsx +0 -24
  107. package/frontend/src/components/ui/comment.tsx +0 -618
  108. package/frontend/src/components/ui/context-menu.tsx +0 -250
  109. package/frontend/src/components/ui/cursor-overlay.tsx +0 -66
  110. package/frontend/src/components/ui/date-node-static.tsx +0 -45
  111. package/frontend/src/components/ui/date-node.tsx +0 -93
  112. package/frontend/src/components/ui/dialog.tsx +0 -143
  113. package/frontend/src/components/ui/dropdown-menu.tsx +0 -255
  114. package/frontend/src/components/ui/dynamic-icon.tsx +0 -12
  115. package/frontend/src/components/ui/editor-static.tsx +0 -53
  116. package/frontend/src/components/ui/editor.tsx +0 -130
  117. package/frontend/src/components/ui/emoji-node.tsx +0 -69
  118. package/frontend/src/components/ui/emoji-toolbar-button.tsx +0 -628
  119. package/frontend/src/components/ui/equation-node-static.tsx +0 -98
  120. package/frontend/src/components/ui/equation-node.tsx +0 -235
  121. package/frontend/src/components/ui/equation-toolbar-button.tsx +0 -25
  122. package/frontend/src/components/ui/excalidraw-node.tsx +0 -36
  123. package/frontend/src/components/ui/export-toolbar-button.tsx +0 -174
  124. package/frontend/src/components/ui/file-selector.tsx +0 -339
  125. package/frontend/src/components/ui/floating-toolbar-buttons.tsx +0 -73
  126. package/frontend/src/components/ui/floating-toolbar.tsx +0 -85
  127. package/frontend/src/components/ui/font-color-toolbar-button.tsx +0 -831
  128. package/frontend/src/components/ui/font-size-toolbar-button.tsx +0 -152
  129. package/frontend/src/components/ui/heading-node-static.tsx +0 -68
  130. package/frontend/src/components/ui/heading-node.tsx +0 -58
  131. package/frontend/src/components/ui/highlight-node-static.tsx +0 -11
  132. package/frontend/src/components/ui/highlight-node.tsx +0 -13
  133. package/frontend/src/components/ui/history-toolbar-button.tsx +0 -50
  134. package/frontend/src/components/ui/hr-node-static.tsx +0 -20
  135. package/frontend/src/components/ui/hr-node.tsx +0 -33
  136. package/frontend/src/components/ui/import-toolbar-button.tsx +0 -97
  137. package/frontend/src/components/ui/indent-toolbar-button.tsx +0 -30
  138. package/frontend/src/components/ui/inline-combobox.tsx +0 -414
  139. package/frontend/src/components/ui/input.tsx +0 -21
  140. package/frontend/src/components/ui/insert-toolbar-button.tsx +0 -254
  141. package/frontend/src/components/ui/kbd-node-static.tsx +0 -15
  142. package/frontend/src/components/ui/kbd-node.tsx +0 -17
  143. package/frontend/src/components/ui/layout-header.tsx +0 -35
  144. package/frontend/src/components/ui/line-height-toolbar-button.tsx +0 -68
  145. package/frontend/src/components/ui/link-node-static.tsx +0 -21
  146. package/frontend/src/components/ui/link-node.tsx +0 -39
  147. package/frontend/src/components/ui/link-toolbar-button.tsx +0 -22
  148. package/frontend/src/components/ui/link-toolbar.tsx +0 -206
  149. package/frontend/src/components/ui/list-toolbar-button.tsx +0 -204
  150. package/frontend/src/components/ui/mark-toolbar-button.tsx +0 -19
  151. package/frontend/src/components/ui/media-audio-node-static.tsx +0 -17
  152. package/frontend/src/components/ui/media-audio-node.tsx +0 -39
  153. package/frontend/src/components/ui/media-embed-node.tsx +0 -136
  154. package/frontend/src/components/ui/media-file-node-static.tsx +0 -29
  155. package/frontend/src/components/ui/media-file-node.tsx +0 -47
  156. package/frontend/src/components/ui/media-image-node-static.tsx +0 -39
  157. package/frontend/src/components/ui/media-image-node.tsx +0 -80
  158. package/frontend/src/components/ui/media-placeholder-node.tsx +0 -249
  159. package/frontend/src/components/ui/media-preview-dialog.tsx +0 -152
  160. package/frontend/src/components/ui/media-toolbar-button.tsx +0 -225
  161. package/frontend/src/components/ui/media-toolbar.tsx +0 -115
  162. package/frontend/src/components/ui/media-upload-toast.tsx +0 -66
  163. package/frontend/src/components/ui/media-video-node-static.tsx +0 -30
  164. package/frontend/src/components/ui/media-video-node.tsx +0 -121
  165. package/frontend/src/components/ui/mention-node-static.tsx +0 -36
  166. package/frontend/src/components/ui/mention-node.tsx +0 -194
  167. package/frontend/src/components/ui/mode-toolbar-button.tsx +0 -123
  168. package/frontend/src/components/ui/more-toolbar-button.tsx +0 -80
  169. package/frontend/src/components/ui/paragraph-node-static.tsx +0 -13
  170. package/frontend/src/components/ui/paragraph-node.tsx +0 -15
  171. package/frontend/src/components/ui/popover.tsx +0 -46
  172. package/frontend/src/components/ui/resize-handle.tsx +0 -87
  173. package/frontend/src/components/ui/separator.tsx +0 -28
  174. package/frontend/src/components/ui/sheet.tsx +0 -139
  175. package/frontend/src/components/ui/sidebar.tsx +0 -726
  176. package/frontend/src/components/ui/skeleton.tsx +0 -13
  177. package/frontend/src/components/ui/slash-node.tsx +0 -233
  178. package/frontend/src/components/ui/sonner.tsx +0 -38
  179. package/frontend/src/components/ui/suggestion-node-static.tsx +0 -35
  180. package/frontend/src/components/ui/suggestion-node.tsx +0 -162
  181. package/frontend/src/components/ui/suggestion-toolbar-button.tsx +0 -25
  182. package/frontend/src/components/ui/table-icons.tsx +0 -862
  183. package/frontend/src/components/ui/table-node-static.tsx +0 -98
  184. package/frontend/src/components/ui/table-node.tsx +0 -656
  185. package/frontend/src/components/ui/table-toolbar-button.tsx +0 -264
  186. package/frontend/src/components/ui/toc-node-static.tsx +0 -92
  187. package/frontend/src/components/ui/toc-node.tsx +0 -55
  188. package/frontend/src/components/ui/toggle-node-static.tsx +0 -18
  189. package/frontend/src/components/ui/toggle-node.tsx +0 -36
  190. package/frontend/src/components/ui/toggle-toolbar-button.tsx +0 -22
  191. package/frontend/src/components/ui/toolbar.tsx +0 -387
  192. package/frontend/src/components/ui/tooltip.tsx +0 -59
  193. package/frontend/src/components/ui/turn-into-toolbar-button.tsx +0 -188
  194. package/frontend/src/hooks/use-debounce.ts +0 -18
  195. package/frontend/src/hooks/use-is-touch-device.ts +0 -24
  196. package/frontend/src/hooks/use-mobile.ts +0 -19
  197. package/frontend/src/hooks/use-mounted.ts +0 -11
  198. package/frontend/src/hooks/use-upload-file.ts +0 -128
  199. package/frontend/src/index.css +0 -128
  200. package/frontend/src/layout.tsx +0 -42
  201. package/frontend/src/lib/markdown-joiner-transform.ts +0 -239
  202. package/frontend/src/lib/orpc.ts +0 -13
  203. package/frontend/src/lib/uploadthing.ts +0 -19
  204. package/frontend/src/lib/utils.ts +0 -6
  205. package/frontend/src/main.tsx +0 -13
  206. package/frontend/src/pages/editor.tsx +0 -44
  207. package/frontend/src/types/docs.d.ts +0 -6
  208. package/frontend/src/types/global.d.ts +0 -9
  209. package/frontend/src/types/router.d.ts +0 -4
  210. package/frontend/tsconfig.app.json +0 -33
  211. package/frontend/tsconfig.json +0 -10
  212. package/frontend/tsconfig.node.json +0 -26
  213. package/frontend/vite.config.ts +0 -14
  214. package/src/bin/doclific.ts +0 -47
  215. package/src/core/codebase.ts +0 -39
  216. package/src/core/docs.ts +0 -90
  217. package/src/core/git.ts +0 -48
  218. package/src/server/index.ts +0 -55
  219. package/src/server/router.ts +0 -65
  220. package/tsconfig.json +0 -15
@@ -1,152 +0,0 @@
1
- 'use client';
2
-
3
- import {
4
- PreviewImage,
5
- useImagePreview,
6
- useImagePreviewValue,
7
- useScaleInput,
8
- } from '@platejs/media/react';
9
- import { cva } from 'class-variance-authority';
10
- import { ArrowLeft, ArrowRight, Download, Minus, Plus, X } from 'lucide-react';
11
- import { useEditorRef } from 'platejs/react';
12
-
13
- import { cn } from '@/lib/utils';
14
-
15
- const buttonVariants = cva('rounded bg-[rgba(0,0,0,0.5)] px-1', {
16
- defaultVariants: {
17
- variant: 'default',
18
- },
19
- variants: {
20
- variant: {
21
- default: 'text-white',
22
- disabled: 'cursor-not-allowed text-gray-400',
23
- },
24
- },
25
- });
26
-
27
- const SCROLL_SPEED = 4;
28
-
29
- export function MediaPreviewDialog() {
30
- const editor = useEditorRef();
31
- const isOpen = useImagePreviewValue('isOpen', editor.id);
32
- const scale = useImagePreviewValue('scale');
33
- const isEditingScale = useImagePreviewValue('isEditingScale');
34
- const {
35
- closeProps,
36
- currentUrlIndex,
37
- maskLayerProps,
38
- nextDisabled,
39
- nextProps,
40
- prevDisabled,
41
- prevProps,
42
- scaleTextProps,
43
- zommOutProps,
44
- zoomInDisabled,
45
- zoomInProps,
46
- zoomOutDisabled,
47
- } = useImagePreview({ scrollSpeed: SCROLL_SPEED });
48
-
49
- return (
50
- <div
51
- className={cn(
52
- 'fixed top-0 left-0 z-50 h-screen w-screen select-none',
53
- !isOpen && 'hidden'
54
- )}
55
- onContextMenu={(e) => e.stopPropagation()}
56
- {...maskLayerProps}
57
- >
58
- <div className="absolute inset-0 size-full bg-black opacity-30" />
59
- <div className="absolute inset-0 size-full bg-black opacity-30" />
60
- <div className="absolute inset-0 flex items-center justify-center">
61
- <div className="relative flex max-h-screen w-full items-center">
62
- <PreviewImage
63
- className={cn(
64
- 'mx-auto block max-h-[calc(100vh-4rem)] w-auto object-contain transition-transform'
65
- )}
66
- />
67
- <div
68
- className="-translate-x-1/2 absolute bottom-0 left-1/2 z-40 flex w-fit justify-center gap-4 p-2 text-center text-white"
69
- onClick={(e) => e.stopPropagation()}
70
- >
71
- <div className="flex gap-1">
72
- <button
73
- {...prevProps}
74
- className={cn(
75
- buttonVariants({
76
- variant: prevDisabled ? 'disabled' : 'default',
77
- })
78
- )}
79
- type="button"
80
- >
81
- <ArrowLeft />
82
- </button>
83
- {(currentUrlIndex ?? 0) + 1}
84
- <button
85
- {...nextProps}
86
- className={cn(
87
- buttonVariants({
88
- variant: nextDisabled ? 'disabled' : 'default',
89
- })
90
- )}
91
- type="button"
92
- >
93
- <ArrowRight />
94
- </button>
95
- </div>
96
- <div className="flex">
97
- <button
98
- className={cn(
99
- buttonVariants({
100
- variant: zoomOutDisabled ? 'disabled' : 'default',
101
- })
102
- )}
103
- {...zommOutProps}
104
- type="button"
105
- >
106
- <Minus className="size-4" />
107
- </button>
108
- <div className="mx-px">
109
- {isEditingScale ? (
110
- <>
111
- <ScaleInput className="w-10 rounded px-1 text-slate-500 outline" />{' '}
112
- <span>%</span>
113
- </>
114
- ) : (
115
- <span {...scaleTextProps}>{`${scale * 100}%`}</span>
116
- )}
117
- </div>
118
- <button
119
- className={cn(
120
- buttonVariants({
121
- variant: zoomInDisabled ? 'disabled' : 'default',
122
- })
123
- )}
124
- {...zoomInProps}
125
- type="button"
126
- >
127
- <Plus className="size-4" />
128
- </button>
129
- </div>
130
- {/* TODO: downLoad the image */}
131
- <button className={cn(buttonVariants())} type="button">
132
- <Download className="size-4" />
133
- </button>
134
- <button
135
- {...closeProps}
136
- className={cn(buttonVariants())}
137
- type="button"
138
- >
139
- <X className="size-4" />
140
- </button>
141
- </div>
142
- </div>
143
- </div>
144
- </div>
145
- );
146
- }
147
-
148
- function ScaleInput(props: React.ComponentProps<'input'>) {
149
- const { props: scaleInputProps, ref } = useScaleInput();
150
-
151
- return <input {...scaleInputProps} {...props} ref={ref} />;
152
- }
@@ -1,225 +0,0 @@
1
- import React from 'react';
2
-
3
- import type { DropdownMenuProps } from '@radix-ui/react-dropdown-menu';
4
-
5
- import { PlaceholderPlugin } from '@platejs/media/react';
6
- import {
7
- AudioLinesIcon,
8
- FileUpIcon,
9
- FilmIcon,
10
- ImageIcon,
11
- LinkIcon,
12
- } from 'lucide-react';
13
- import { isUrl, KEYS } from 'platejs';
14
- import { useEditorRef } from 'platejs/react';
15
- import { toast } from 'sonner';
16
- import { useFilePicker } from 'use-file-picker';
17
-
18
- import {
19
- AlertDialog,
20
- AlertDialogAction,
21
- AlertDialogCancel,
22
- AlertDialogContent,
23
- AlertDialogDescription,
24
- AlertDialogFooter,
25
- AlertDialogHeader,
26
- AlertDialogTitle,
27
- } from '@/components/ui/alert-dialog';
28
- import {
29
- DropdownMenu,
30
- DropdownMenuContent,
31
- DropdownMenuGroup,
32
- DropdownMenuItem,
33
- DropdownMenuTrigger,
34
- } from '@/components/ui/dropdown-menu';
35
- import { Input } from '@/components/ui/input';
36
-
37
- import {
38
- ToolbarSplitButton,
39
- ToolbarSplitButtonPrimary,
40
- ToolbarSplitButtonSecondary,
41
- } from './toolbar';
42
-
43
- const MEDIA_CONFIG: Record<
44
- string,
45
- {
46
- accept: string[];
47
- icon: React.ReactNode;
48
- title: string;
49
- tooltip: string;
50
- }
51
- > = {
52
- [KEYS.audio]: {
53
- accept: ['audio/*'],
54
- icon: <AudioLinesIcon className="size-4" />,
55
- title: 'Insert Audio',
56
- tooltip: 'Audio',
57
- },
58
- [KEYS.file]: {
59
- accept: ['*'],
60
- icon: <FileUpIcon className="size-4" />,
61
- title: 'Insert File',
62
- tooltip: 'File',
63
- },
64
- [KEYS.img]: {
65
- accept: ['image/*'],
66
- icon: <ImageIcon className="size-4" />,
67
- title: 'Insert Image',
68
- tooltip: 'Image',
69
- },
70
- [KEYS.video]: {
71
- accept: ['video/*'],
72
- icon: <FilmIcon className="size-4" />,
73
- title: 'Insert Video',
74
- tooltip: 'Video',
75
- },
76
- };
77
-
78
- export function MediaToolbarButton({
79
- nodeType,
80
- ...props
81
- }: DropdownMenuProps & { nodeType: string }) {
82
- const currentConfig = MEDIA_CONFIG[nodeType];
83
-
84
- const editor = useEditorRef();
85
- const [open, setOpen] = React.useState(false);
86
- const [dialogOpen, setDialogOpen] = React.useState(false);
87
-
88
- const { openFilePicker } = useFilePicker({
89
- accept: currentConfig.accept,
90
- multiple: true,
91
- onFilesSelected: ({ plainFiles: updatedFiles }) => {
92
- editor.getTransforms(PlaceholderPlugin).insert.media(updatedFiles);
93
- },
94
- });
95
-
96
- return (
97
- <>
98
- <ToolbarSplitButton
99
- onClick={() => {
100
- openFilePicker();
101
- }}
102
- onKeyDown={(e) => {
103
- if (e.key === 'ArrowDown') {
104
- e.preventDefault();
105
- setOpen(true);
106
- }
107
- }}
108
- pressed={open}
109
- >
110
- <ToolbarSplitButtonPrimary>
111
- {currentConfig.icon}
112
- </ToolbarSplitButtonPrimary>
113
-
114
- <DropdownMenu
115
- open={open}
116
- onOpenChange={setOpen}
117
- modal={false}
118
- {...props}
119
- >
120
- <DropdownMenuTrigger asChild>
121
- <ToolbarSplitButtonSecondary />
122
- </DropdownMenuTrigger>
123
-
124
- <DropdownMenuContent
125
- onClick={(e) => e.stopPropagation()}
126
- align="start"
127
- alignOffset={-32}
128
- >
129
- <DropdownMenuGroup>
130
- <DropdownMenuItem onSelect={() => openFilePicker()}>
131
- {currentConfig.icon}
132
- Upload from computer
133
- </DropdownMenuItem>
134
- <DropdownMenuItem onSelect={() => setDialogOpen(true)}>
135
- <LinkIcon />
136
- Insert via URL
137
- </DropdownMenuItem>
138
- </DropdownMenuGroup>
139
- </DropdownMenuContent>
140
- </DropdownMenu>
141
- </ToolbarSplitButton>
142
-
143
- <AlertDialog
144
- open={dialogOpen}
145
- onOpenChange={(value) => {
146
- setDialogOpen(value);
147
- }}
148
- >
149
- <AlertDialogContent className="gap-6">
150
- <MediaUrlDialogContent
151
- currentConfig={currentConfig}
152
- nodeType={nodeType}
153
- setOpen={setDialogOpen}
154
- />
155
- </AlertDialogContent>
156
- </AlertDialog>
157
- </>
158
- );
159
- }
160
-
161
- function MediaUrlDialogContent({
162
- currentConfig,
163
- nodeType,
164
- setOpen,
165
- }: {
166
- currentConfig: (typeof MEDIA_CONFIG)[string];
167
- nodeType: string;
168
- setOpen: (value: boolean) => void;
169
- }) {
170
- const editor = useEditorRef();
171
- const [url, setUrl] = React.useState('');
172
-
173
- const embedMedia = React.useCallback(() => {
174
- if (!isUrl(url)) return toast.error('Invalid URL');
175
-
176
- setOpen(false);
177
- editor.tf.insertNodes({
178
- children: [{ text: '' }],
179
- name: nodeType === KEYS.file ? url.split('/').pop() : undefined,
180
- type: nodeType,
181
- url,
182
- });
183
- }, [url, editor, nodeType, setOpen]);
184
-
185
- return (
186
- <>
187
- <AlertDialogHeader>
188
- <AlertDialogTitle>{currentConfig.title}</AlertDialogTitle>
189
- </AlertDialogHeader>
190
-
191
- <AlertDialogDescription className="group relative w-full">
192
- <label
193
- className="-translate-y-1/2 absolute top-1/2 block cursor-text px-1 text-muted-foreground/70 text-sm transition-all group-focus-within:pointer-events-none group-focus-within:top-0 group-focus-within:cursor-default group-focus-within:font-medium group-focus-within:text-foreground group-focus-within:text-xs has-[+input:not(:placeholder-shown)]:pointer-events-none has-[+input:not(:placeholder-shown)]:top-0 has-[+input:not(:placeholder-shown)]:cursor-default has-[+input:not(:placeholder-shown)]:font-medium has-[+input:not(:placeholder-shown)]:text-foreground has-[+input:not(:placeholder-shown)]:text-xs"
194
- htmlFor="url"
195
- >
196
- <span className="inline-flex bg-background px-2">URL</span>
197
- </label>
198
- <Input
199
- id="url"
200
- className="w-full"
201
- value={url}
202
- onChange={(e) => setUrl(e.target.value)}
203
- onKeyDown={(e) => {
204
- if (e.key === 'Enter') embedMedia();
205
- }}
206
- placeholder=""
207
- type="url"
208
- autoFocus
209
- />
210
- </AlertDialogDescription>
211
-
212
- <AlertDialogFooter>
213
- <AlertDialogCancel>Cancel</AlertDialogCancel>
214
- <AlertDialogAction
215
- onClick={(e) => {
216
- e.preventDefault();
217
- embedMedia();
218
- }}
219
- >
220
- Accept
221
- </AlertDialogAction>
222
- </AlertDialogFooter>
223
- </>
224
- );
225
- }
@@ -1,115 +0,0 @@
1
- import React from 'react';
2
-
3
- import type { WithRequiredKey } from 'platejs';
4
-
5
- import {
6
- FloatingMedia as FloatingMediaPrimitive,
7
- FloatingMediaStore,
8
- useFloatingMediaValue,
9
- useImagePreviewValue,
10
- } from '@platejs/media/react';
11
- import { cva } from 'class-variance-authority';
12
- import { Link, Trash2Icon } from 'lucide-react';
13
- import {
14
- useEditorRef,
15
- useEditorSelector,
16
- useElement,
17
- useFocusedLast,
18
- useReadOnly,
19
- useRemoveNodeButton,
20
- useSelected,
21
- } from 'platejs/react';
22
-
23
- import { Button, buttonVariants } from '@/components/ui/button';
24
- import {
25
- Popover,
26
- PopoverAnchor,
27
- PopoverContent,
28
- } from '@/components/ui/popover';
29
- import { Separator } from '@/components/ui/separator';
30
-
31
- import { CaptionButton } from './caption';
32
-
33
- const inputVariants = cva(
34
- 'flex h-[28px] w-full rounded-md border-none bg-transparent px-1.5 py-1 text-base placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-transparent md:text-sm'
35
- );
36
-
37
- export function MediaToolbar({
38
- children,
39
- plugin,
40
- }: {
41
- children: React.ReactNode;
42
- plugin: WithRequiredKey;
43
- }) {
44
- const editor = useEditorRef();
45
- const readOnly = useReadOnly();
46
- const selected = useSelected();
47
- const isFocusedLast = useFocusedLast();
48
- const selectionCollapsed = useEditorSelector(
49
- (editor) => !editor.api.isExpanded(),
50
- []
51
- );
52
- const isImagePreviewOpen = useImagePreviewValue('isOpen', editor.id);
53
- const open =
54
- isFocusedLast &&
55
- !readOnly &&
56
- selected &&
57
- selectionCollapsed &&
58
- !isImagePreviewOpen;
59
- const isEditing = useFloatingMediaValue('isEditing');
60
-
61
- React.useEffect(() => {
62
- if (!open && isEditing) {
63
- FloatingMediaStore.set('isEditing', false);
64
- }
65
- // eslint-disable-next-line react-hooks/exhaustive-deps
66
- }, [open]);
67
-
68
- const element = useElement();
69
- const { props: buttonProps } = useRemoveNodeButton({ element });
70
-
71
- return (
72
- <Popover open={open} modal={false}>
73
- <PopoverAnchor>{children}</PopoverAnchor>
74
-
75
- <PopoverContent
76
- className="w-auto p-1"
77
- onOpenAutoFocus={(e) => e.preventDefault()}
78
- >
79
- {isEditing ? (
80
- <div className="flex w-[330px] flex-col">
81
- <div className="flex items-center">
82
- <div className="flex items-center pr-1 pl-2 text-muted-foreground">
83
- <Link className="size-4" />
84
- </div>
85
-
86
- <FloatingMediaPrimitive.UrlInput
87
- className={inputVariants()}
88
- placeholder="Paste the embed link..."
89
- options={{ plugin }}
90
- />
91
- </div>
92
- </div>
93
- ) : (
94
- <div className="box-content flex items-center">
95
- <FloatingMediaPrimitive.EditButton
96
- className={buttonVariants({ size: 'sm', variant: 'ghost' })}
97
- >
98
- Edit link
99
- </FloatingMediaPrimitive.EditButton>
100
-
101
- <CaptionButton size="sm" variant="ghost">
102
- Caption
103
- </CaptionButton>
104
-
105
- <Separator orientation="vertical" className="mx-1 h-6" />
106
-
107
- <Button size="sm" variant="ghost" {...buttonProps}>
108
- <Trash2Icon />
109
- </Button>
110
- </div>
111
- )}
112
- </PopoverContent>
113
- </Popover>
114
- );
115
- }
@@ -1,66 +0,0 @@
1
- import React from 'react';
2
-
3
- import { PlaceholderPlugin, UploadErrorCode } from '@platejs/media/react';
4
- import { usePluginOption } from 'platejs/react';
5
- import { toast } from 'sonner';
6
-
7
- export function MediaUploadToast() {
8
- useUploadErrorToast();
9
-
10
- return null;
11
- }
12
-
13
- const useUploadErrorToast = () => {
14
- const uploadError = usePluginOption(PlaceholderPlugin, 'error');
15
-
16
- React.useEffect(() => {
17
- if (!uploadError) return;
18
-
19
- const { code, data } = uploadError;
20
-
21
- switch (code) {
22
- case UploadErrorCode.INVALID_FILE_SIZE: {
23
- toast.error(
24
- `The size of files ${data.files
25
- .map((f) => f.name)
26
- .join(', ')} is invalid`
27
- );
28
-
29
- break;
30
- }
31
- case UploadErrorCode.INVALID_FILE_TYPE: {
32
- toast.error(
33
- `The type of files ${data.files
34
- .map((f) => f.name)
35
- .join(', ')} is invalid`
36
- );
37
-
38
- break;
39
- }
40
- case UploadErrorCode.TOO_LARGE: {
41
- toast.error(
42
- `The size of files ${data.files
43
- .map((f) => f.name)
44
- .join(', ')} is too large than ${data.maxFileSize}`
45
- );
46
-
47
- break;
48
- }
49
- case UploadErrorCode.TOO_LESS_FILES: {
50
- toast.error(
51
- `The mini um number of files is ${data.minFileCount} for ${data.fileType}`
52
- );
53
-
54
- break;
55
- }
56
- case UploadErrorCode.TOO_MANY_FILES: {
57
- toast.error(
58
- `The maximum number of files is ${data.maxFileCount} ${data.fileType ? `for ${data.fileType}` : ''
59
- }`
60
- );
61
-
62
- break;
63
- }
64
- }
65
- }, [uploadError]);
66
- };
@@ -1,30 +0,0 @@
1
- import type { TCaptionElement, TResizableProps, TVideoElement } from 'platejs';
2
- import type { SlateElementProps } from 'platejs/static';
3
-
4
- import { NodeApi } from 'platejs';
5
- import { SlateElement } from 'platejs/static';
6
-
7
- export function VideoElementStatic(
8
- props: SlateElementProps<TVideoElement & TCaptionElement & TResizableProps>
9
- ) {
10
- const { align = 'center', caption, url, width } = props.element;
11
-
12
- return (
13
- <SlateElement className="py-2.5" {...props}>
14
- <div style={{ textAlign: align }}>
15
- <figure
16
- className="group relative m-0 inline-block cursor-default"
17
- style={{ width }}
18
- >
19
- <video
20
- className="w-full max-w-full rounded-sm object-cover px-0"
21
- src={url}
22
- controls
23
- />
24
- {caption && <figcaption>{NodeApi.string(caption[0])}</figcaption>}
25
- </figure>
26
- </div>
27
- {props.children}
28
- </SlateElement>
29
- );
30
- }