mirror of
https://github.com/docmost/docmost.git
synced 2025-11-13 05:02:36 +10:00
feat: enhance editor uploads (#895)
* * multi-file paste support * allow media files (image/videos) to be attachments * insert trailing node if file placeholder is at the end of the editor * fix video align
This commit is contained in:
@ -17,8 +17,11 @@ export const uploadAttachmentAction = handleAttachmentUpload({
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
validateFn: (file) => {
|
||||
if (file.type.includes("image/") || file.type.includes("video/")) {
|
||||
validateFn: (file, allowMedia: boolean) => {
|
||||
if (
|
||||
(file.type.includes("image/") || file.type.includes("video/")) &&
|
||||
!allowMedia
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (file.size > getFileUploadSizeLimit()) {
|
||||
|
||||
@ -40,10 +40,8 @@ export const handlePaste = (
|
||||
|
||||
if (event.clipboardData?.files.length) {
|
||||
event.preventDefault();
|
||||
const [file] = Array.from(event.clipboardData.files);
|
||||
const pos = view.state.selection.from;
|
||||
|
||||
if (file) {
|
||||
for (const file of event.clipboardData.files) {
|
||||
const pos = view.state.selection.from;
|
||||
uploadImageAction(file, view, pos, pageId);
|
||||
uploadVideoAction(file, view, pos, pageId);
|
||||
uploadAttachmentAction(file, view, pos, pageId);
|
||||
@ -61,13 +59,13 @@ export const handleFileDrop = (
|
||||
) => {
|
||||
if (!moved && event.dataTransfer?.files.length) {
|
||||
event.preventDefault();
|
||||
const [file] = Array.from(event.dataTransfer.files);
|
||||
const coordinates = view.posAtCoords({
|
||||
left: event.clientX,
|
||||
top: event.clientY,
|
||||
});
|
||||
// here we deduct 1 from the pos or else the image will create an extra node
|
||||
if (file) {
|
||||
|
||||
for (const file of event.dataTransfer.files) {
|
||||
const coordinates = view.posAtCoords({
|
||||
left: event.clientX,
|
||||
top: event.clientY,
|
||||
});
|
||||
|
||||
uploadImageAction(file, view, coordinates?.pos ?? 0 - 1, pageId);
|
||||
uploadVideoAction(file, view, coordinates?.pos ?? 0 - 1, pageId);
|
||||
uploadAttachmentAction(file, view, coordinates?.pos ?? 0 - 1, pageId);
|
||||
|
||||
@ -38,7 +38,8 @@ import {
|
||||
LoomIcon,
|
||||
MiroIcon,
|
||||
TypeformIcon,
|
||||
VimeoIcon, YoutubeIcon
|
||||
VimeoIcon,
|
||||
YoutubeIcon,
|
||||
} from "@/components/icons";
|
||||
|
||||
const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
@ -221,13 +222,7 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
if (input.files?.length) {
|
||||
const file = input.files[0];
|
||||
const pos = editor.view.state.selection.from;
|
||||
if (file.type.includes("image/*")) {
|
||||
uploadImageAction(file, editor.view, pos, pageId);
|
||||
} else if (file.type.includes("video/*")) {
|
||||
uploadVideoAction(file, editor.view, pos, pageId);
|
||||
} else {
|
||||
uploadAttachmentAction(file, editor.view, pos, pageId);
|
||||
}
|
||||
uploadAttachmentAction(file, editor.view, pos, pageId, true);
|
||||
}
|
||||
};
|
||||
input.click();
|
||||
@ -368,7 +363,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["airtable"],
|
||||
icon: AirtableIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'airtable' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "airtable" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -377,7 +377,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["loom"],
|
||||
icon: LoomIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'loom' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "loom" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -386,7 +391,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["figma"],
|
||||
icon: FigmaIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'figma' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "figma" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -395,7 +405,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["typeform"],
|
||||
icon: TypeformIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'typeform' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "typeform" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -404,7 +419,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["miro"],
|
||||
icon: MiroIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'miro' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "miro" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -413,7 +433,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["youtube", "yt"],
|
||||
icon: YoutubeIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'youtube' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "youtube" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -422,7 +447,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["vimeo"],
|
||||
icon: VimeoIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'vimeo' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "vimeo" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -431,7 +461,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["framer"],
|
||||
icon: FramerIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'framer' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "framer" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -440,7 +475,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["google drive", "gdrive"],
|
||||
icon: GoogleDriveIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'gdrive' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "gdrive" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -449,7 +489,12 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
searchTerms: ["google sheets", "gsheets"],
|
||||
icon: GoogleSheetsIcon,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setEmbed({ provider: 'gsheets' }).run();
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.setEmbed({ provider: "gsheets" })
|
||||
.run();
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@ -22,6 +22,7 @@ export default function VideoView(props: NodeViewProps) {
|
||||
controls
|
||||
src={getFileUrl(src)}
|
||||
className={clsx(selected ? "ProseMirror-selectednode" : "", alignClass)}
|
||||
style={{ display: "block" }}
|
||||
/>
|
||||
</NodeViewWrapper>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user