@fuma-content/studio 0.1.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.
- package/dist/bin.d.mts +1 -0
- package/dist/bin.mjs +90 -0
- package/dist/index.d.mts +13 -0
- package/dist/index.mjs +66 -0
- package/dist/mdx/actions.mjs +34 -0
- package/dist/mdx/client.mjs +167 -0
- package/dist/package.mjs +6 -0
- package/dist/src/components/code-editor/mdx.lazy.mjs +19 -0
- package/dist/src/components/code-editor/mdx.mjs +44 -0
- package/dist/src/components/code-editor/yaml.lazy.mjs +22 -0
- package/dist/src/components/code-editor/yaml.mjs +63 -0
- package/dist/src/components/editor/editor-base-kit.mjs +41 -0
- package/dist/src/components/editor/editor-kit.mjs +73 -0
- package/dist/src/components/editor/md.mjs +42 -0
- package/dist/src/components/editor/plugins/ai-kit.mjs +68 -0
- package/dist/src/components/editor/plugins/align-base-kit.mjs +28 -0
- package/dist/src/components/editor/plugins/align-kit.mjs +30 -0
- package/dist/src/components/editor/plugins/autoformat-kit.mjs +214 -0
- package/dist/src/components/editor/plugins/basic-blocks-base-kit.mjs +22 -0
- package/dist/src/components/editor/plugins/basic-blocks-kit.mjs +51 -0
- package/dist/src/components/editor/plugins/basic-marks-base-kit.mjs +20 -0
- package/dist/src/components/editor/plugins/basic-marks-kit.mjs +28 -0
- package/dist/src/components/editor/plugins/block-menu-kit.mjs +11 -0
- package/dist/src/components/editor/plugins/block-placeholder-kit.mjs +14 -0
- package/dist/src/components/editor/plugins/block-selection-kit.mjs +48 -0
- package/dist/src/components/editor/plugins/callout-base-kit.mjs +8 -0
- package/dist/src/components/editor/plugins/callout-kit.mjs +10 -0
- package/dist/src/components/editor/plugins/code-block-base-kit.mjs +16 -0
- package/dist/src/components/editor/plugins/code-block-kit.mjs +19 -0
- package/dist/src/components/editor/plugins/column-base-kit.mjs +8 -0
- package/dist/src/components/editor/plugins/column-kit.mjs +10 -0
- package/dist/src/components/editor/plugins/comment-base-kit.mjs +8 -0
- package/dist/src/components/editor/plugins/comment-kit.mjs +53 -0
- package/dist/src/components/editor/plugins/copilot-kit.mjs +49 -0
- package/dist/src/components/editor/plugins/cursor-overlay-kit.mjs +11 -0
- package/dist/src/components/editor/plugins/date-base-kit.mjs +8 -0
- package/dist/src/components/editor/plugins/date-kit.mjs +10 -0
- package/dist/src/components/editor/plugins/discussion-kit.mjs +94 -0
- package/dist/src/components/editor/plugins/dnd-kit.mjs +31 -0
- package/dist/src/components/editor/plugins/emoji-kit.mjs +11 -0
- package/dist/src/components/editor/plugins/exit-break-kit.mjs +12 -0
- package/dist/src/components/editor/plugins/fixed-toolbar-kit.mjs +15 -0
- package/dist/src/components/editor/plugins/floating-toolbar-kit.mjs +15 -0
- package/dist/src/components/editor/plugins/font-base-kit.mjs +14 -0
- package/dist/src/components/editor/plugins/font-kit.mjs +19 -0
- package/dist/src/components/editor/plugins/indent-base-kit.mjs +17 -0
- package/dist/src/components/editor/plugins/indent-kit.mjs +20 -0
- package/dist/src/components/editor/plugins/line-height-base-kit.mjs +20 -0
- package/dist/src/components/editor/plugins/line-height-kit.mjs +22 -0
- package/dist/src/components/editor/plugins/link-base-kit.mjs +8 -0
- package/dist/src/components/editor/plugins/link-kit.mjs +15 -0
- package/dist/src/components/editor/plugins/list-base-kit.mjs +19 -0
- package/dist/src/components/editor/plugins/list-kit.mjs +22 -0
- package/dist/src/components/editor/plugins/markdown-kit.mjs +17 -0
- package/dist/src/components/editor/plugins/math-base-kit.mjs +8 -0
- package/dist/src/components/editor/plugins/math-kit.mjs +10 -0
- package/dist/src/components/editor/plugins/media-base-kit.mjs +23 -0
- package/dist/src/components/editor/plugins/media-kit.mjs +37 -0
- package/dist/src/components/editor/plugins/slash-kit.mjs +11 -0
- package/dist/src/components/editor/plugins/suggestion-base-kit.mjs +8 -0
- package/dist/src/components/editor/plugins/suggestion-kit.mjs +50 -0
- package/dist/src/components/editor/plugins/table-base-kit.mjs +13 -0
- package/dist/src/components/editor/plugins/table-kit.mjs +15 -0
- package/dist/src/components/editor/transforms.mjs +125 -0
- package/dist/src/components/editor/ui/ai-chat-editor.mjs +21 -0
- package/dist/src/components/editor/ui/ai-menu.mjs +488 -0
- package/dist/src/components/editor/ui/ai-node.mjs +24 -0
- package/dist/src/components/editor/ui/ai-toolbar-button.mjs +23 -0
- package/dist/src/components/editor/ui/align-toolbar-button.mjs +71 -0
- package/dist/src/components/editor/ui/block-context-menu.mjs +130 -0
- package/dist/src/components/editor/ui/block-discussion.mjs +200 -0
- package/dist/src/components/editor/ui/block-draggable.mjs +265 -0
- package/dist/src/components/editor/ui/block-list-static.mjs +48 -0
- package/dist/src/components/editor/ui/block-list.mjs +47 -0
- package/dist/src/components/editor/ui/block-selection.mjs +28 -0
- package/dist/src/components/editor/ui/block-suggestion.mjs +319 -0
- package/dist/src/components/editor/ui/blockquote-node-static.mjs +14 -0
- package/dist/src/components/editor/ui/blockquote-node.mjs +16 -0
- package/dist/src/components/editor/ui/callout-node-static.mjs +29 -0
- package/dist/src/components/editor/ui/callout-node.mjs +50 -0
- package/dist/src/components/editor/ui/caption.mjs +39 -0
- package/dist/src/components/editor/ui/code-block-node-static.mjs +30 -0
- package/dist/src/components/editor/ui/code-block-node.mjs +121 -0
- package/dist/src/components/editor/ui/code-node-static.mjs +15 -0
- package/dist/src/components/editor/ui/code-node.mjs +17 -0
- package/dist/src/components/editor/ui/column-node-static.mjs +32 -0
- package/dist/src/components/editor/ui/column-node.mjs +229 -0
- package/dist/src/components/editor/ui/comment-node-static.mjs +14 -0
- package/dist/src/components/editor/ui/comment-node.mjs +33 -0
- package/dist/src/components/editor/ui/comment-toolbar-button.mjs +23 -0
- package/dist/src/components/editor/ui/comment.mjs +422 -0
- package/dist/src/components/editor/ui/cursor-overlay.mjs +36 -0
- package/dist/src/components/editor/ui/date-node-static.mjs +32 -0
- package/dist/src/components/editor/ui/date-node.mjs +60 -0
- package/dist/src/components/editor/ui/editor-static.mjs +31 -0
- package/dist/src/components/editor/ui/editor.mjs +60 -0
- package/dist/src/components/editor/ui/emoji-node.mjs +46 -0
- package/dist/src/components/editor/ui/emoji-toolbar-button.mjs +415 -0
- package/dist/src/components/editor/ui/equation-node-static.mjs +65 -0
- package/dist/src/components/editor/ui/equation-node.mjs +159 -0
- package/dist/src/components/editor/ui/equation-toolbar-button.mjs +23 -0
- package/dist/src/components/editor/ui/fixed-toolbar-buttons.mjs +109 -0
- package/dist/src/components/editor/ui/fixed-toolbar.mjs +16 -0
- package/dist/src/components/editor/ui/floating-toolbar-buttons.mjs +54 -0
- package/dist/src/components/editor/ui/floating-toolbar.mjs +51 -0
- package/dist/src/components/editor/ui/font-color-toolbar-button.mjs +637 -0
- package/dist/src/components/editor/ui/font-size-toolbar-button.mjs +83 -0
- package/dist/src/components/editor/ui/ghost-text.mjs +22 -0
- package/dist/src/components/editor/ui/heading-node-static.mjs +60 -0
- package/dist/src/components/editor/ui/heading-node.mjs +62 -0
- package/dist/src/components/editor/ui/highlight-node-static.mjs +15 -0
- package/dist/src/components/editor/ui/highlight-node.mjs +17 -0
- package/dist/src/components/editor/ui/history-toolbar-button.mjs +35 -0
- package/dist/src/components/editor/ui/hr-node-static.mjs +18 -0
- package/dist/src/components/editor/ui/hr-node.mjs +23 -0
- package/dist/src/components/editor/ui/indent-toolbar-button.mjs +29 -0
- package/dist/src/components/editor/ui/inline-combobox.mjs +148 -0
- package/dist/src/components/editor/ui/insert-toolbar-button.mjs +199 -0
- package/dist/src/components/editor/ui/kbd-node-static.mjs +15 -0
- package/dist/src/components/editor/ui/kbd-node.mjs +17 -0
- package/dist/src/components/editor/ui/line-height-toolbar-button.mjs +56 -0
- package/dist/src/components/editor/ui/link-node-static.mjs +20 -0
- package/dist/src/components/editor/ui/link-node.mjs +28 -0
- package/dist/src/components/editor/ui/link-toolbar-button.mjs +21 -0
- package/dist/src/components/editor/ui/link-toolbar.mjs +141 -0
- package/dist/src/components/editor/ui/list-toolbar-button.mjs +131 -0
- package/dist/src/components/editor/ui/mark-toolbar-button.mjs +20 -0
- package/dist/src/components/editor/ui/media-image-node-static.mjs +32 -0
- package/dist/src/components/editor/ui/media-image-node.mjs +64 -0
- package/dist/src/components/editor/ui/media-placeholder-node.mjs +184 -0
- package/dist/src/components/editor/ui/media-preview-dialog.mjs +113 -0
- package/dist/src/components/editor/ui/media-toolbar-button.mjs +156 -0
- package/dist/src/components/editor/ui/media-toolbar.mjs +80 -0
- package/dist/src/components/editor/ui/media-upload-toast.mjs +39 -0
- package/dist/src/components/editor/ui/media-video-node-static.mjs +27 -0
- package/dist/src/components/editor/ui/mode-toolbar-button.mjs +112 -0
- package/dist/src/components/editor/ui/paragraph-node-static.mjs +15 -0
- package/dist/src/components/editor/ui/paragraph-node.mjs +17 -0
- package/dist/src/components/editor/ui/resize-handle.mjs +43 -0
- package/dist/src/components/editor/ui/slash-node.mjs +228 -0
- package/dist/src/components/editor/ui/suggestion-node-static.mjs +24 -0
- package/dist/src/components/editor/ui/suggestion-node.mjs +111 -0
- package/dist/src/components/editor/ui/suggestion-toolbar-button.mjs +24 -0
- package/dist/src/components/editor/ui/table-icons.mjs +1310 -0
- package/dist/src/components/editor/ui/table-node-static.mjs +68 -0
- package/dist/src/components/editor/ui/table-node.mjs +375 -0
- package/dist/src/components/editor/ui/table-toolbar-button.mjs +190 -0
- package/dist/src/components/editor/ui/turn-into-toolbar-button.mjs +168 -0
- package/dist/src/components/editor/use-chat.mjs +80 -0
- package/dist/src/components/json-schema-editor/client.mjs +46 -0
- package/dist/src/components/json-schema-editor/components/inputs.mjs +438 -0
- package/dist/src/components/json-schema-editor/get-default-values.mjs +23 -0
- package/dist/src/components/json-schema-editor/schema.mjs +131 -0
- package/dist/src/components/json-schema-editor/utils/merge-schema.mjs +134 -0
- package/dist/src/components/json-schema-editor/utils/schema-to-string.mjs +53 -0
- package/dist/src/components/ui/alert-dialog.mjs +90 -0
- package/dist/src/components/ui/avatar.mjs +32 -0
- package/dist/src/components/ui/button.mjs +48 -0
- package/dist/src/components/ui/calendar.mjs +108 -0
- package/dist/src/components/ui/checkbox.mjs +23 -0
- package/dist/src/components/ui/combobox.mjs +53 -0
- package/dist/src/components/ui/command.mjs +42 -0
- package/dist/src/components/ui/context-menu.mjs +67 -0
- package/dist/src/components/ui/dialog.mjs +9 -0
- package/dist/src/components/ui/dropdown-menu.mjs +122 -0
- package/dist/src/components/ui/input-group.mjs +31 -0
- package/dist/src/components/ui/input.mjs +15 -0
- package/dist/src/components/ui/label.mjs +19 -0
- package/dist/src/components/ui/popover.mjs +37 -0
- package/dist/src/components/ui/select.mjs +80 -0
- package/dist/src/components/ui/separator.mjs +19 -0
- package/dist/src/components/ui/spinner.mjs +16 -0
- package/dist/src/components/ui/tabs.mjs +39 -0
- package/dist/src/components/ui/textarea.mjs +14 -0
- package/dist/src/components/ui/toolbar.mjs +183 -0
- package/dist/src/components/ui/tooltip.mjs +38 -0
- package/dist/src/hooks/editor/use-is-creator.mjs +19 -0
- package/dist/src/hooks/use-upload-file.mjs +73 -0
- package/dist/src/lib/config.mjs +38 -0
- package/dist/src/lib/data/store.d.mts +15 -0
- package/dist/src/lib/lowlight.mjs +7 -0
- package/dist/src/lib/utils/deep-equal.mjs +18 -0
- package/dist/src/lib/utils/remove-undefined.mjs +18 -0
- package/dist/src/lib/utils.mjs +10 -0
- package/dist/types.d.mts +50 -0
- package/next.config.ts +23 -0
- package/package.json +131 -0
- package/postcss.config.mjs +7 -0
- package/src/app/(dashboard)/collection/[name]/[...slug]/page.client.tsx +26 -0
- package/src/app/(dashboard)/collection/[name]/[...slug]/page.tsx +17 -0
- package/src/app/(dashboard)/collection/[name]/page.client.tsx +82 -0
- package/src/app/(dashboard)/collection/[name]/page.tsx +11 -0
- package/src/app/(dashboard)/layout.tsx +34 -0
- package/src/app/(dashboard)/page.tsx +38 -0
- package/src/app/api/ai/command/prompts.ts +313 -0
- package/src/app/api/ai/command/route.ts +203 -0
- package/src/app/api/ai/command/utils.ts +242 -0
- package/src/app/api/ai/copilot/route.ts +33 -0
- package/src/app/api/uploadthing/route.ts +5 -0
- package/src/app/codeblock/LICENSE +21 -0
- package/src/app/codeblock/styles.css +289 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +223 -0
- package/src/app/layout.client.tsx +15 -0
- package/src/app/layout.tsx +30 -0
- package/src/components/app-sidebar.tsx +162 -0
- package/src/components/code-editor/mdx.lazy.tsx +18 -0
- package/src/components/code-editor/mdx.tsx +48 -0
- package/src/components/code-editor/yaml.lazy.tsx +20 -0
- package/src/components/code-editor/yaml.tsx +71 -0
- package/src/components/collection/actions.tsx +41 -0
- package/src/components/collection/client.tsx +63 -0
- package/src/components/collection/context.tsx +24 -0
- package/src/components/collection/document/actions.tsx +83 -0
- package/src/components/editor/editor-base-kit.tsx +37 -0
- package/src/components/editor/editor-kit.tsx +87 -0
- package/src/components/editor/md.tsx +60 -0
- package/src/components/editor/plugins/ai-kit.tsx +102 -0
- package/src/components/editor/plugins/align-base-kit.tsx +16 -0
- package/src/components/editor/plugins/align-kit.tsx +18 -0
- package/src/components/editor/plugins/autoformat-kit.tsx +236 -0
- package/src/components/editor/plugins/basic-blocks-base-kit.tsx +34 -0
- package/src/components/editor/plugins/basic-blocks-kit.tsx +87 -0
- package/src/components/editor/plugins/basic-marks-base-kit.tsx +26 -0
- package/src/components/editor/plugins/basic-marks-kit.tsx +40 -0
- package/src/components/editor/plugins/basic-nodes-kit.tsx +6 -0
- package/src/components/editor/plugins/block-menu-kit.tsx +14 -0
- package/src/components/editor/plugins/block-placeholder-kit.tsx +17 -0
- package/src/components/editor/plugins/block-selection-kit.tsx +54 -0
- package/src/components/editor/plugins/callout-base-kit.tsx +5 -0
- package/src/components/editor/plugins/callout-kit.tsx +7 -0
- package/src/components/editor/plugins/code-block-base-kit.tsx +16 -0
- package/src/components/editor/plugins/code-block-kit.tsx +19 -0
- package/src/components/editor/plugins/column-base-kit.tsx +11 -0
- package/src/components/editor/plugins/column-kit.tsx +10 -0
- package/src/components/editor/plugins/comment-base-kit.tsx +5 -0
- package/src/components/editor/plugins/comment-kit.tsx +92 -0
- package/src/components/editor/plugins/copilot-kit.tsx +70 -0
- package/src/components/editor/plugins/cursor-overlay-kit.tsx +13 -0
- package/src/components/editor/plugins/date-base-kit.tsx +5 -0
- package/src/components/editor/plugins/date-kit.tsx +7 -0
- package/src/components/editor/plugins/discussion-kit.tsx +142 -0
- package/src/components/editor/plugins/dnd-kit.tsx +25 -0
- package/src/components/editor/plugins/emoji-kit.tsx +13 -0
- package/src/components/editor/plugins/exit-break-kit.tsx +12 -0
- package/src/components/editor/plugins/fixed-toolbar-kit.tsx +19 -0
- package/src/components/editor/plugins/floating-toolbar-kit.tsx +19 -0
- package/src/components/editor/plugins/font-base-kit.tsx +20 -0
- package/src/components/editor/plugins/font-kit.tsx +29 -0
- package/src/components/editor/plugins/indent-base-kit.tsx +13 -0
- package/src/components/editor/plugins/indent-kit.tsx +22 -0
- package/src/components/editor/plugins/line-height-base-kit.tsx +14 -0
- package/src/components/editor/plugins/line-height-kit.tsx +16 -0
- package/src/components/editor/plugins/link-base-kit.tsx +5 -0
- package/src/components/editor/plugins/link-kit.tsx +15 -0
- package/src/components/editor/plugins/list-base-kit.tsx +17 -0
- package/src/components/editor/plugins/list-kit.tsx +26 -0
- package/src/components/editor/plugins/markdown-kit.tsx +13 -0
- package/src/components/editor/plugins/math-base-kit.tsx +11 -0
- package/src/components/editor/plugins/math-kit.tsx +10 -0
- package/src/components/editor/plugins/media-base-kit.tsx +25 -0
- package/src/components/editor/plugins/media-kit.tsx +28 -0
- package/src/components/editor/plugins/slash-kit.tsx +18 -0
- package/src/components/editor/plugins/suggestion-base-kit.tsx +5 -0
- package/src/components/editor/plugins/suggestion-kit.tsx +83 -0
- package/src/components/editor/plugins/table-base-kit.tsx +20 -0
- package/src/components/editor/plugins/table-kit.tsx +22 -0
- package/src/components/editor/settings-dialog.tsx +418 -0
- package/src/components/editor/transforms.ts +193 -0
- package/src/components/editor/types.ts +149 -0
- package/src/components/editor/ui/ai-chat-editor.tsx +20 -0
- package/src/components/editor/ui/ai-menu.tsx +663 -0
- package/src/components/editor/ui/ai-node.tsx +40 -0
- package/src/components/editor/ui/ai-toolbar-button.tsx +23 -0
- package/src/components/editor/ui/align-toolbar-button.tsx +78 -0
- package/src/components/editor/ui/block-context-menu.tsx +154 -0
- package/src/components/editor/ui/block-discussion.tsx +318 -0
- package/src/components/editor/ui/block-draggable.tsx +464 -0
- package/src/components/editor/ui/block-list-static.tsx +75 -0
- package/src/components/editor/ui/block-list.tsx +72 -0
- package/src/components/editor/ui/block-selection.tsx +37 -0
- package/src/components/editor/ui/block-suggestion.tsx +438 -0
- package/src/components/editor/ui/blockquote-node-static.tsx +5 -0
- package/src/components/editor/ui/blockquote-node.tsx +7 -0
- package/src/components/editor/ui/callout-node-static.tsx +30 -0
- package/src/components/editor/ui/callout-node.tsx +64 -0
- package/src/components/editor/ui/caption.tsx +55 -0
- package/src/components/editor/ui/code-block-node-static.tsx +33 -0
- package/src/components/editor/ui/code-block-node.tsx +161 -0
- package/src/components/editor/ui/code-node-static.tsx +15 -0
- package/src/components/editor/ui/code-node.tsx +17 -0
- package/src/components/editor/ui/column-node-static.tsx +27 -0
- package/src/components/editor/ui/column-node.tsx +285 -0
- package/src/components/editor/ui/comment-node-static.tsx +12 -0
- package/src/components/editor/ui/comment-node.tsx +43 -0
- package/src/components/editor/ui/comment-toolbar-button.tsx +24 -0
- package/src/components/editor/ui/comment.tsx +577 -0
- package/src/components/editor/ui/cursor-overlay.tsx +66 -0
- package/src/components/editor/ui/date-node-static.tsx +45 -0
- package/src/components/editor/ui/date-node.tsx +86 -0
- package/src/components/editor/ui/editor-static.tsx +47 -0
- package/src/components/editor/ui/editor.tsx +120 -0
- package/src/components/editor/ui/emoji-node.tsx +65 -0
- package/src/components/editor/ui/emoji-toolbar-button.tsx +582 -0
- package/src/components/editor/ui/equation-node-static.tsx +94 -0
- package/src/components/editor/ui/equation-node.tsx +218 -0
- package/src/components/editor/ui/equation-toolbar-button.tsx +24 -0
- package/src/components/editor/ui/fixed-toolbar-buttons.tsx +135 -0
- package/src/components/editor/ui/fixed-toolbar.tsx +17 -0
- package/src/components/editor/ui/floating-toolbar-buttons.tsx +72 -0
- package/src/components/editor/ui/floating-toolbar.tsx +76 -0
- package/src/components/editor/ui/font-color-toolbar-button.tsx +804 -0
- package/src/components/editor/ui/font-size-toolbar-button.tsx +102 -0
- package/src/components/editor/ui/ghost-text.tsx +27 -0
- package/src/components/editor/ui/heading-node-static.tsx +54 -0
- package/src/components/editor/ui/heading-node.tsx +54 -0
- package/src/components/editor/ui/highlight-node-static.tsx +11 -0
- package/src/components/editor/ui/highlight-node.tsx +13 -0
- package/src/components/editor/ui/history-toolbar-button.tsx +41 -0
- package/src/components/editor/ui/hr-node-static.tsx +16 -0
- package/src/components/editor/ui/hr-node.tsx +28 -0
- package/src/components/editor/ui/indent-toolbar-button.tsx +27 -0
- package/src/components/editor/ui/inline-combobox.tsx +251 -0
- package/src/components/editor/ui/insert-toolbar-button.tsx +242 -0
- package/src/components/editor/ui/kbd-node-static.tsx +15 -0
- package/src/components/editor/ui/kbd-node.tsx +17 -0
- package/src/components/editor/ui/line-height-toolbar-button.tsx +66 -0
- package/src/components/editor/ui/link-node-static.tsx +21 -0
- package/src/components/editor/ui/link-node.tsx +37 -0
- package/src/components/editor/ui/link-toolbar-button.tsx +18 -0
- package/src/components/editor/ui/link-toolbar.tsx +196 -0
- package/src/components/editor/ui/list-toolbar-button.tsx +195 -0
- package/src/components/editor/ui/mark-toolbar-button.tsx +20 -0
- package/src/components/editor/ui/media-image-node-static.tsx +33 -0
- package/src/components/editor/ui/media-image-node.tsx +75 -0
- package/src/components/editor/ui/media-placeholder-node.tsx +235 -0
- package/src/components/editor/ui/media-preview-dialog.tsx +145 -0
- package/src/components/editor/ui/media-toolbar-button.tsx +202 -0
- package/src/components/editor/ui/media-toolbar.tsx +100 -0
- package/src/components/editor/ui/media-upload-toast.tsx +59 -0
- package/src/components/editor/ui/media-video-node-static.tsx +23 -0
- package/src/components/editor/ui/mode-toolbar-button.tsx +121 -0
- package/src/components/editor/ui/paragraph-node-static.tsx +13 -0
- package/src/components/editor/ui/paragraph-node.tsx +15 -0
- package/src/components/editor/ui/resize-handle.tsx +79 -0
- package/src/components/editor/ui/slash-node.tsx +274 -0
- package/src/components/editor/ui/suggestion-node-static.tsx +30 -0
- package/src/components/editor/ui/suggestion-node.tsx +157 -0
- package/src/components/editor/ui/suggestion-toolbar-button.tsx +25 -0
- package/src/components/editor/ui/table-icons.tsx +685 -0
- package/src/components/editor/ui/table-node-static.tsx +86 -0
- package/src/components/editor/ui/table-node.tsx +569 -0
- package/src/components/editor/ui/table-toolbar-button.tsx +260 -0
- package/src/components/editor/ui/turn-into-toolbar-button.tsx +176 -0
- package/src/components/editor/use-chat.ts +120 -0
- package/src/components/icons/logo.tsx +37 -0
- package/src/components/json-schema-editor/client.tsx +55 -0
- package/src/components/json-schema-editor/components/inputs.tsx +612 -0
- package/src/components/json-schema-editor/get-default-values.ts +29 -0
- package/src/components/json-schema-editor/schema.tsx +206 -0
- package/src/components/json-schema-editor/utils/merge-schema.ts +167 -0
- package/src/components/json-schema-editor/utils/schema-to-string.ts +87 -0
- package/src/components/nav-user.tsx +102 -0
- package/src/components/site-header.tsx +13 -0
- package/src/components/ui/alert-dialog.tsx +182 -0
- package/src/components/ui/avatar.tsx +96 -0
- package/src/components/ui/badge.tsx +46 -0
- package/src/components/ui/button.tsx +65 -0
- package/src/components/ui/calendar.tsx +186 -0
- package/src/components/ui/checkbox.tsx +29 -0
- package/src/components/ui/combobox.tsx +267 -0
- package/src/components/ui/command.tsx +180 -0
- package/src/components/ui/context-menu.tsx +161 -0
- package/src/components/ui/dialog.tsx +142 -0
- package/src/components/ui/drawer.tsx +120 -0
- package/src/components/ui/dropdown-menu.tsx +239 -0
- package/src/components/ui/field.tsx +224 -0
- package/src/components/ui/input-group.tsx +144 -0
- package/src/components/ui/input.tsx +19 -0
- package/src/components/ui/label.tsx +18 -0
- package/src/components/ui/popover.tsx +76 -0
- package/src/components/ui/select.tsx +182 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +130 -0
- package/src/components/ui/sidebar.tsx +608 -0
- package/src/components/ui/sonner.tsx +45 -0
- package/src/components/ui/spinner.tsx +15 -0
- package/src/components/ui/table.tsx +89 -0
- package/src/components/ui/tabs.tsx +60 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/toggle-group.tsx +86 -0
- package/src/components/ui/toggle.tsx +45 -0
- package/src/components/ui/toolbar.tsx +365 -0
- package/src/components/ui/tooltip.tsx +57 -0
- package/src/hooks/editor/use-is-creator.ts +21 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/hooks/use-mounted.ts +11 -0
- package/src/hooks/use-upload-file.ts +121 -0
- package/src/lib/ai/markdown-joiner-transform.ts +235 -0
- package/src/lib/config.ts +60 -0
- package/src/lib/data/actions.ts +51 -0
- package/src/lib/data/boundary.client.tsx +22 -0
- package/src/lib/data/boundary.tsx +22 -0
- package/src/lib/data/query.ts +9 -0
- package/src/lib/data/store.ts +52 -0
- package/src/lib/lowlight.ts +3 -0
- package/src/lib/uploadthing.ts +19 -0
- package/src/lib/utils/deep-equal.ts +37 -0
- package/src/lib/utils/remove-undefined.ts +21 -0
- package/src/lib/utils/urls.ts +6 -0
- package/src/lib/utils.ts +6 -0
- package/tsconfig.build.json +24 -0
- package/tsconfig.json +37 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type * as React from "react";
|
|
4
|
+
import { Tooltip as TooltipPrimitive } from "radix-ui";
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
function TooltipProvider({
|
|
9
|
+
delayDuration = 0,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
12
|
+
return (
|
|
13
|
+
<TooltipPrimitive.Provider
|
|
14
|
+
data-slot="tooltip-provider"
|
|
15
|
+
delayDuration={delayDuration}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
22
|
+
return (
|
|
23
|
+
<TooltipProvider>
|
|
24
|
+
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
25
|
+
</TooltipProvider>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
|
30
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function TooltipContent({
|
|
34
|
+
className,
|
|
35
|
+
sideOffset = 0,
|
|
36
|
+
children,
|
|
37
|
+
...props
|
|
38
|
+
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
39
|
+
return (
|
|
40
|
+
<TooltipPrimitive.Portal>
|
|
41
|
+
<TooltipPrimitive.Content
|
|
42
|
+
data-slot="tooltip-content"
|
|
43
|
+
sideOffset={sideOffset}
|
|
44
|
+
className={cn(
|
|
45
|
+
"data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) rounded-2xl bg-foreground px-3 py-1.5 text-background text-xs data-[state=delayed-open]:animate-in data-closed:animate-out data-open:animate-in **:data-[slot=kbd]:rounded-4xl",
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
|
|
52
|
+
</TooltipPrimitive.Content>
|
|
53
|
+
</TooltipPrimitive.Portal>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TElement } from "platejs";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { useEditor } from "@/components/editor/editor-kit";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if current user is the creator of this element (for Yjs collaboration)
|
|
7
|
+
*/
|
|
8
|
+
export function useIsCreator(element: TElement) {
|
|
9
|
+
const editor = useEditor();
|
|
10
|
+
|
|
11
|
+
return useMemo(() => {
|
|
12
|
+
const elementUserId =
|
|
13
|
+
"userId" in element && typeof element.userId === "string" ? element.userId : undefined;
|
|
14
|
+
const currentUserId = editor.meta.userId;
|
|
15
|
+
|
|
16
|
+
// If no userId (backwards compatibility or non-Yjs), allow
|
|
17
|
+
if (!elementUserId) return true;
|
|
18
|
+
|
|
19
|
+
return elementUserId === currentUserId;
|
|
20
|
+
}, [editor.meta.userId, element]);
|
|
21
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
const MOBILE_BREAKPOINT = 768;
|
|
4
|
+
|
|
5
|
+
export function useIsMobile() {
|
|
6
|
+
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
|
|
7
|
+
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
10
|
+
const onChange = () => {
|
|
11
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
12
|
+
};
|
|
13
|
+
mql.addEventListener("change", onChange);
|
|
14
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
15
|
+
return () => mql.removeEventListener("change", onChange);
|
|
16
|
+
}, []);
|
|
17
|
+
|
|
18
|
+
return !!isMobile;
|
|
19
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import type { OurFileRouter } from "@/lib/uploadthing";
|
|
4
|
+
import type { ClientUploadedFileData, UploadFilesOptions } from "uploadthing/types";
|
|
5
|
+
|
|
6
|
+
import { generateReactHelpers } from "@uploadthing/react";
|
|
7
|
+
import { toast } from "sonner";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
|
|
10
|
+
export type UploadedFile<T = unknown> = ClientUploadedFileData<T>;
|
|
11
|
+
|
|
12
|
+
interface UseUploadFileProps extends Pick<
|
|
13
|
+
UploadFilesOptions<OurFileRouter["editorUploader"]>,
|
|
14
|
+
"headers" | "onUploadBegin" | "onUploadProgress" | "skipPolling"
|
|
15
|
+
> {
|
|
16
|
+
onUploadComplete?: (file: UploadedFile) => void;
|
|
17
|
+
onUploadError?: (error: unknown) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function useUploadFile({
|
|
21
|
+
onUploadComplete,
|
|
22
|
+
onUploadError,
|
|
23
|
+
...props
|
|
24
|
+
}: UseUploadFileProps = {}) {
|
|
25
|
+
const [uploadedFile, setUploadedFile] = React.useState<UploadedFile>();
|
|
26
|
+
const [uploadingFile, setUploadingFile] = React.useState<File>();
|
|
27
|
+
const [progress, setProgress] = React.useState<number>(0);
|
|
28
|
+
const [isUploading, setIsUploading] = React.useState(false);
|
|
29
|
+
|
|
30
|
+
async function uploadThing(file: File) {
|
|
31
|
+
setIsUploading(true);
|
|
32
|
+
setUploadingFile(file);
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const res = await uploadFiles("editorUploader", {
|
|
36
|
+
...props,
|
|
37
|
+
files: [file],
|
|
38
|
+
onUploadProgress: ({ progress }) => {
|
|
39
|
+
setProgress(Math.min(progress, 100));
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
setUploadedFile(res[0]);
|
|
44
|
+
|
|
45
|
+
onUploadComplete?.(res[0]);
|
|
46
|
+
|
|
47
|
+
return uploadedFile;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
const errorMessage = getErrorMessage(error);
|
|
50
|
+
|
|
51
|
+
const message =
|
|
52
|
+
errorMessage.length > 0 ? errorMessage : "Something went wrong, please try again later.";
|
|
53
|
+
|
|
54
|
+
toast.error(message);
|
|
55
|
+
|
|
56
|
+
onUploadError?.(error);
|
|
57
|
+
|
|
58
|
+
// Mock upload for unauthenticated users
|
|
59
|
+
// toast.info('User not logged in. Mocking upload process.');
|
|
60
|
+
const mockUploadedFile = {
|
|
61
|
+
key: "mock-key-0",
|
|
62
|
+
appUrl: `https://mock-app-url.com/${file.name}`,
|
|
63
|
+
name: file.name,
|
|
64
|
+
size: file.size,
|
|
65
|
+
type: file.type,
|
|
66
|
+
url: URL.createObjectURL(file),
|
|
67
|
+
} as UploadedFile;
|
|
68
|
+
|
|
69
|
+
// Simulate upload progress
|
|
70
|
+
let progress = 0;
|
|
71
|
+
|
|
72
|
+
const simulateProgress = async () => {
|
|
73
|
+
while (progress < 100) {
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
75
|
+
progress += 2;
|
|
76
|
+
setProgress(Math.min(progress, 100));
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
await simulateProgress();
|
|
81
|
+
|
|
82
|
+
setUploadedFile(mockUploadedFile);
|
|
83
|
+
|
|
84
|
+
return mockUploadedFile;
|
|
85
|
+
} finally {
|
|
86
|
+
setProgress(0);
|
|
87
|
+
setIsUploading(false);
|
|
88
|
+
setUploadingFile(undefined);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
isUploading,
|
|
94
|
+
progress,
|
|
95
|
+
uploadedFile,
|
|
96
|
+
uploadFile: uploadThing,
|
|
97
|
+
uploadingFile,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const { uploadFiles, useUploadThing } = generateReactHelpers<OurFileRouter>();
|
|
102
|
+
|
|
103
|
+
export function getErrorMessage(err: unknown) {
|
|
104
|
+
const unknownError = "Something went wrong, please try again later.";
|
|
105
|
+
|
|
106
|
+
if (err instanceof z.ZodError) {
|
|
107
|
+
const errors = err.issues.map((issue) => issue.message);
|
|
108
|
+
|
|
109
|
+
return errors.join("\n");
|
|
110
|
+
}
|
|
111
|
+
if (err instanceof Error) {
|
|
112
|
+
return err.message;
|
|
113
|
+
}
|
|
114
|
+
return unknownError;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function showErrorToast(err: unknown) {
|
|
118
|
+
const errorMessage = getErrorMessage(err);
|
|
119
|
+
|
|
120
|
+
return toast.error(errorMessage);
|
|
121
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import type { TextStreamPart, ToolSet } from "ai";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Transform chunks like [**,bold,**] to [**bold**] make the md deserializer
|
|
5
|
+
* happy.
|
|
6
|
+
*
|
|
7
|
+
* @experimental
|
|
8
|
+
*/
|
|
9
|
+
export const markdownJoinerTransform =
|
|
10
|
+
<TOOLS extends ToolSet>() =>
|
|
11
|
+
() => {
|
|
12
|
+
const joiner = new MarkdownJoiner();
|
|
13
|
+
let lastTextDeltaId: string | undefined;
|
|
14
|
+
let textStreamEnded = false;
|
|
15
|
+
|
|
16
|
+
return new TransformStream<TextStreamPart<TOOLS>, TextStreamPart<TOOLS>>({
|
|
17
|
+
async flush(controller) {
|
|
18
|
+
// Only flush if we haven't seen text-end yet
|
|
19
|
+
if (!textStreamEnded) {
|
|
20
|
+
const remaining = joiner.flush();
|
|
21
|
+
if (remaining && lastTextDeltaId) {
|
|
22
|
+
controller.enqueue({
|
|
23
|
+
id: lastTextDeltaId,
|
|
24
|
+
text: remaining,
|
|
25
|
+
type: "text-delta",
|
|
26
|
+
} as TextStreamPart<TOOLS>);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
async transform(chunk, controller) {
|
|
31
|
+
if (chunk.type === "text-delta") {
|
|
32
|
+
lastTextDeltaId = chunk.id;
|
|
33
|
+
const processedText = joiner.processText(chunk.text);
|
|
34
|
+
if (processedText) {
|
|
35
|
+
controller.enqueue({
|
|
36
|
+
...chunk,
|
|
37
|
+
text: processedText,
|
|
38
|
+
});
|
|
39
|
+
await delay(joiner.delayInMs);
|
|
40
|
+
}
|
|
41
|
+
} else if (chunk.type === "text-end") {
|
|
42
|
+
// Flush any remaining buffer before text-end
|
|
43
|
+
const remaining = joiner.flush();
|
|
44
|
+
if (remaining && lastTextDeltaId) {
|
|
45
|
+
controller.enqueue({
|
|
46
|
+
id: lastTextDeltaId,
|
|
47
|
+
text: remaining,
|
|
48
|
+
type: "text-delta",
|
|
49
|
+
} as TextStreamPart<TOOLS>);
|
|
50
|
+
}
|
|
51
|
+
textStreamEnded = true;
|
|
52
|
+
controller.enqueue(chunk);
|
|
53
|
+
} else {
|
|
54
|
+
controller.enqueue(chunk);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const DEFAULT_DELAY_IN_MS = 10;
|
|
61
|
+
const NEST_BLOCK_DELAY_IN_MS = 100;
|
|
62
|
+
|
|
63
|
+
const BOLD_PATTERN = /\*\*.*?\*\*/;
|
|
64
|
+
const CODE_LINE_PATTERN = /```[^\s]+/;
|
|
65
|
+
const LINK_PATTERN = /^\[.*?\]\(.*?\)$/;
|
|
66
|
+
const UNORDERED_LIST_PATTERN = /^[*-]\s+.+/;
|
|
67
|
+
const TODO_LIST_PATTERN = /^[*-]\s+\[[ xX]\]\s+.+/;
|
|
68
|
+
const ORDERED_LIST_PATTERN = /^\d+\.\s+.+/;
|
|
69
|
+
const MDX_TAG_PATTERN = /<([A-Za-z][A-Za-z0-9\-_]*)>/;
|
|
70
|
+
const DIGIT_PATTERN = /^[0-9]$/;
|
|
71
|
+
|
|
72
|
+
export class MarkdownJoiner {
|
|
73
|
+
delayInMs = DEFAULT_DELAY_IN_MS;
|
|
74
|
+
|
|
75
|
+
private buffer = "";
|
|
76
|
+
private documentCharacterCount = 0;
|
|
77
|
+
private isBuffering = false;
|
|
78
|
+
private streamingCodeBlock = false;
|
|
79
|
+
private streamingLargeDocument = false;
|
|
80
|
+
private streamingTable = false;
|
|
81
|
+
|
|
82
|
+
private clearBuffer(): void {
|
|
83
|
+
this.buffer = "";
|
|
84
|
+
this.isBuffering = false;
|
|
85
|
+
}
|
|
86
|
+
private isCompleteBold(): boolean {
|
|
87
|
+
return BOLD_PATTERN.test(this.buffer);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private isCompleteCodeBlockEnd(): boolean {
|
|
91
|
+
return this.buffer.trimEnd() === "```";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private isCompleteCodeBlockStart(): boolean {
|
|
95
|
+
return CODE_LINE_PATTERN.test(this.buffer);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private isCompleteLink(): boolean {
|
|
99
|
+
return LINK_PATTERN.test(this.buffer);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private isCompleteList(): boolean {
|
|
103
|
+
if (UNORDERED_LIST_PATTERN.test(this.buffer) && this.buffer.includes("["))
|
|
104
|
+
return TODO_LIST_PATTERN.test(this.buffer);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
UNORDERED_LIST_PATTERN.test(this.buffer) ||
|
|
108
|
+
ORDERED_LIST_PATTERN.test(this.buffer) ||
|
|
109
|
+
TODO_LIST_PATTERN.test(this.buffer)
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private isCompleteMdxTag(): boolean {
|
|
114
|
+
return MDX_TAG_PATTERN.test(this.buffer);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private isCompleteTableStart(): boolean {
|
|
118
|
+
return this.buffer.startsWith("|") && this.buffer.endsWith("|");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private isFalsePositive(char: string): boolean {
|
|
122
|
+
// when link is not complete, even if ths buffer is more than 30 characters, it is not a false positive
|
|
123
|
+
if (this.buffer.startsWith("[") && this.buffer.includes("http")) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return char === "\n" || this.buffer.length > 30;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private isLargeDocumentStart(): boolean {
|
|
131
|
+
return this.documentCharacterCount > 2500;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private isListStartChar(char: string): boolean {
|
|
135
|
+
return char === "-" || char === "*" || DIGIT_PATTERN.test(char);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private isTableExisted(): boolean {
|
|
139
|
+
return this.buffer.length > 10 && !this.buffer.includes("|");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
flush(): string {
|
|
143
|
+
const remaining = this.buffer;
|
|
144
|
+
this.clearBuffer();
|
|
145
|
+
return remaining;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
processText(text: string): string {
|
|
149
|
+
let output = "";
|
|
150
|
+
|
|
151
|
+
for (const char of text) {
|
|
152
|
+
if (this.streamingCodeBlock || this.streamingTable || this.streamingLargeDocument) {
|
|
153
|
+
this.buffer += char;
|
|
154
|
+
|
|
155
|
+
if (char === "\n") {
|
|
156
|
+
output += this.buffer;
|
|
157
|
+
this.clearBuffer();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (this.isCompleteCodeBlockEnd() && this.streamingCodeBlock) {
|
|
161
|
+
this.streamingCodeBlock = false;
|
|
162
|
+
this.delayInMs = DEFAULT_DELAY_IN_MS;
|
|
163
|
+
|
|
164
|
+
output += this.buffer;
|
|
165
|
+
this.clearBuffer();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (this.isTableExisted() && this.streamingTable) {
|
|
169
|
+
this.streamingTable = false;
|
|
170
|
+
this.delayInMs = DEFAULT_DELAY_IN_MS;
|
|
171
|
+
|
|
172
|
+
output += this.buffer;
|
|
173
|
+
this.clearBuffer();
|
|
174
|
+
}
|
|
175
|
+
} else if (this.isBuffering) {
|
|
176
|
+
this.buffer += char;
|
|
177
|
+
|
|
178
|
+
if (this.isCompleteCodeBlockStart()) {
|
|
179
|
+
this.delayInMs = NEST_BLOCK_DELAY_IN_MS;
|
|
180
|
+
this.streamingCodeBlock = true;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (this.isCompleteTableStart()) {
|
|
185
|
+
this.delayInMs = NEST_BLOCK_DELAY_IN_MS;
|
|
186
|
+
this.streamingTable = true;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (this.isLargeDocumentStart()) {
|
|
191
|
+
this.delayInMs = NEST_BLOCK_DELAY_IN_MS;
|
|
192
|
+
this.streamingLargeDocument = true;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (
|
|
197
|
+
this.isCompleteBold() ||
|
|
198
|
+
this.isCompleteMdxTag() ||
|
|
199
|
+
this.isCompleteList() ||
|
|
200
|
+
this.isCompleteLink()
|
|
201
|
+
) {
|
|
202
|
+
output += this.buffer;
|
|
203
|
+
this.clearBuffer();
|
|
204
|
+
} else if (this.isFalsePositive(char)) {
|
|
205
|
+
// False positive - flush buffer as raw text
|
|
206
|
+
output += this.buffer;
|
|
207
|
+
this.clearBuffer();
|
|
208
|
+
}
|
|
209
|
+
// Check if we should start buffering
|
|
210
|
+
} else if (
|
|
211
|
+
char === "*" ||
|
|
212
|
+
char === "<" ||
|
|
213
|
+
char === "`" ||
|
|
214
|
+
char === "|" ||
|
|
215
|
+
char === "[" ||
|
|
216
|
+
this.isListStartChar(char)
|
|
217
|
+
) {
|
|
218
|
+
this.buffer = char;
|
|
219
|
+
this.isBuffering = true;
|
|
220
|
+
} else {
|
|
221
|
+
// Pass through character directly
|
|
222
|
+
output += char;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
this.documentCharacterCount += text.length;
|
|
227
|
+
return output;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async function delay(delayInMs?: number | null): Promise<void> {
|
|
232
|
+
return delayInMs == null
|
|
233
|
+
? Promise.resolve()
|
|
234
|
+
: new Promise((resolve) => setTimeout(resolve, delayInMs));
|
|
235
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { StudioDocument } from "lib/types";
|
|
2
|
+
import { type CollectionWithHandler, Core } from "fuma-content";
|
|
3
|
+
import { Collection, CollectionHandlers } from "fuma-content/collections";
|
|
4
|
+
|
|
5
|
+
let core: Promise<Core>;
|
|
6
|
+
|
|
7
|
+
export async function getCore(): Promise<Core> {
|
|
8
|
+
core ??= (async () => {
|
|
9
|
+
const core = new Core({
|
|
10
|
+
outDir: ".content",
|
|
11
|
+
configPath: process.env.STUDIO_CONFIG,
|
|
12
|
+
cwd: process.env.STUDIO_PARENT_DIR,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
await core.init({
|
|
16
|
+
config: await import("virtual:content.config"),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return core;
|
|
20
|
+
})();
|
|
21
|
+
|
|
22
|
+
return core;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function requireCollection<Handler extends keyof CollectionHandlers = never>(
|
|
26
|
+
collectionId: string,
|
|
27
|
+
handlers: Handler[],
|
|
28
|
+
): Promise<CollectionWithHandler<Handler>> {
|
|
29
|
+
const core = await getCore();
|
|
30
|
+
const collection = core.getCollection(collectionId);
|
|
31
|
+
if (!collection) throw new Error(`Missing Collection ${collectionId}`);
|
|
32
|
+
|
|
33
|
+
if (hasHandler(collection, handlers)) {
|
|
34
|
+
return collection;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
throw new Error(`Missing ${handlers.join(", ")} handlers for ${collectionId}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function requireDocument<Doc extends StudioDocument = StudioDocument>(
|
|
41
|
+
collectionId: string,
|
|
42
|
+
documentId: string,
|
|
43
|
+
): Promise<{ collection: CollectionWithHandler<"studio">; document: Doc }> {
|
|
44
|
+
const collection = await requireCollection(collectionId, ["studio"]);
|
|
45
|
+
const document: Doc | undefined = await collection.handlers.studio.getDocument(documentId);
|
|
46
|
+
if (!document) throw new Error(`Missing Document ${documentId}`);
|
|
47
|
+
|
|
48
|
+
return { collection: collection as CollectionWithHandler<"studio">, document };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function hasHandler<Handler extends keyof CollectionHandlers = never>(
|
|
52
|
+
collection: Collection,
|
|
53
|
+
handlers: Handler[],
|
|
54
|
+
): collection is CollectionWithHandler<Handler> {
|
|
55
|
+
for (const handler of handlers) {
|
|
56
|
+
if (collection.handlers[handler] === undefined) return false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
|
|
3
|
+
import { getCore, requireDocument } from "../config";
|
|
4
|
+
import type { CollectionItem, DocumentItem } from "./store";
|
|
5
|
+
|
|
6
|
+
export async function getCollectionItems(): Promise<CollectionItem[]> {
|
|
7
|
+
const core = await getCore();
|
|
8
|
+
return core.getCollections(true).map<CollectionItem>((collection) => ({
|
|
9
|
+
id: collection.name,
|
|
10
|
+
name: collection.name,
|
|
11
|
+
badge: collection.typeInfo.id,
|
|
12
|
+
handlers: Object.fromEntries(Object.keys(collection.handlers).map((k) => [k, null])),
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function getDocumentItems(): Promise<DocumentItem[]> {
|
|
17
|
+
const core = await getCore();
|
|
18
|
+
const items = await Promise.all(
|
|
19
|
+
core.getCollections(true).map(async (collection) => {
|
|
20
|
+
const handler = collection.handlers.studio;
|
|
21
|
+
|
|
22
|
+
if (handler) {
|
|
23
|
+
const docs = await handler.getDocuments();
|
|
24
|
+
const supportDelete = handler.actions?.deleteDocument !== undefined;
|
|
25
|
+
|
|
26
|
+
return docs.map<DocumentItem>((doc) => ({
|
|
27
|
+
name: doc.name,
|
|
28
|
+
id: doc.id,
|
|
29
|
+
collectionId: collection.name,
|
|
30
|
+
permissions: {
|
|
31
|
+
delete: supportDelete,
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return [];
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
return items.flat();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function deleteDocumentAction(documentId: string, collectionId: string) {
|
|
44
|
+
const { collection, document } = await requireDocument(collectionId, documentId);
|
|
45
|
+
const { deleteDocument } = collection.handlers.studio.actions ?? {};
|
|
46
|
+
if (deleteDocument) {
|
|
47
|
+
await deleteDocument({ collection, document });
|
|
48
|
+
} else {
|
|
49
|
+
throw new Error(`collection ${collectionId} does not support the delete operation.`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Spinner } from "@/components/ui/spinner";
|
|
3
|
+
import { useMounted } from "@/hooks/use-mounted";
|
|
4
|
+
import { Suspense, type ReactNode } from "react";
|
|
5
|
+
|
|
6
|
+
export function BoundaryClient({ children }: { children: ReactNode }) {
|
|
7
|
+
const mounted = useMounted();
|
|
8
|
+
const fallback = (
|
|
9
|
+
<div className="fixed flex items-center justify-center inset-0 bg-background z-50 text-sm text-muted-foreground gap-1">
|
|
10
|
+
<Spinner />
|
|
11
|
+
Loading
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
if (!mounted) return fallback;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Suspense fallback={fallback} defer>
|
|
19
|
+
{children}
|
|
20
|
+
</Suspense>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { getCollectionItems, getDocumentItems } from "./actions";
|
|
3
|
+
import { dehydrate, HydrationBoundary } from "@tanstack/react-query";
|
|
4
|
+
import { queryClient } from "./query";
|
|
5
|
+
import { BoundaryClient } from "./boundary.client";
|
|
6
|
+
|
|
7
|
+
export async function DataBoundary({ children }: { children: ReactNode }) {
|
|
8
|
+
await queryClient.prefetchQuery({
|
|
9
|
+
queryKey: ["collections"],
|
|
10
|
+
queryFn: () => getCollectionItems(),
|
|
11
|
+
});
|
|
12
|
+
await queryClient.prefetchQuery({
|
|
13
|
+
queryKey: ["documents"],
|
|
14
|
+
queryFn: () => getDocumentItems(),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<BoundaryClient>
|
|
19
|
+
<HydrationBoundary state={dehydrate(queryClient)}>{children}</HydrationBoundary>
|
|
20
|
+
</BoundaryClient>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createCollection } from "@tanstack/react-db";
|
|
2
|
+
import { queryCollectionOptions } from "@tanstack/query-db-collection";
|
|
3
|
+
import { queryClient } from "./query";
|
|
4
|
+
import { deleteDocumentAction, getCollectionItems, getDocumentItems } from "./actions";
|
|
5
|
+
|
|
6
|
+
export interface CollectionItem {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
badge?: string;
|
|
10
|
+
handlers?: Record<string, null>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface DocumentItem {
|
|
14
|
+
id: string;
|
|
15
|
+
collectionId: string;
|
|
16
|
+
name: string;
|
|
17
|
+
|
|
18
|
+
permissions: {
|
|
19
|
+
delete: boolean;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const collection = createCollection(
|
|
24
|
+
queryCollectionOptions({
|
|
25
|
+
queryClient,
|
|
26
|
+
queryKey: ["collections"],
|
|
27
|
+
queryFn: () => getCollectionItems(),
|
|
28
|
+
getKey: (item) => item.id,
|
|
29
|
+
}),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export const documentCollection = createCollection(
|
|
33
|
+
queryCollectionOptions({
|
|
34
|
+
queryClient,
|
|
35
|
+
queryKey: ["documents"],
|
|
36
|
+
queryFn: () => getDocumentItems(),
|
|
37
|
+
getKey: (item) => `${item.collectionId}-${item.id}`,
|
|
38
|
+
onDelete: async ({ transaction }) => {
|
|
39
|
+
const mutation = transaction.mutations[0];
|
|
40
|
+
const original = mutation.original;
|
|
41
|
+
// ignore if not supported
|
|
42
|
+
if (!original.permissions.delete) return;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
await deleteDocumentAction(original.id, original.collectionId);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error("Delete failed, rolling back:", error);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
}),
|
|
52
|
+
);
|