working video

This commit is contained in:
2026-03-12 16:33:57 -05:00
parent 75723ed133
commit 1e5f80739c
7 changed files with 183 additions and 7 deletions
+69
View File
@@ -0,0 +1,69 @@
import { Extension } from '@tiptap/core';
import { activeTaskId, uploadTaskAttachment, activeNoteId, uploadNoteAttachment } from "@/store";
import { toast } from "solid-sonner";
declare module '@tiptap/core' {
interface Commands<ReturnType> {
videoUpload: {
uploadVideo: () => ReturnType;
};
}
}
export const VideoUpload = Extension.create({
name: 'videoUpload',
addCommands() {
return {
uploadVideo: () => ({ editor }) => {
const taskId = activeTaskId();
const noteId = activeNoteId();
if (!taskId && !noteId) {
toast.error("Cannot upload video outside of a task or note.");
return false;
}
const input = document.createElement("input");
input.type = "file";
input.accept = "video/*";
input.onchange = async () => {
if (input.files?.length) {
const originalFile = input.files[0];
toast.promise(
(async () => {
// For video, we don't necessarily convert to webp. We just upload it directly.
if (taskId) {
return uploadTaskAttachment(taskId, originalFile);
} else {
return uploadNoteAttachment(noteId!, originalFile);
}
})(),
{
loading: "Uploading video...",
success: (url) => {
// Insert video
editor.chain()
.focus()
.setVideo({ src: url })
.run();
// Manually force a new paragraph at the end so the user can keep typing
editor.chain()
.focus('end')
.insertContent('<p></p>')
.run();
return "Video uploaded.";
},
error: "Failed to upload video."
}
);
}
};
input.click();
return true;
},
};
},
});
+63
View File
@@ -0,0 +1,63 @@
import { Node, mergeAttributes } from '@tiptap/core';
export interface VideoOptions {
HTMLAttributes: Record<string, any>;
}
export const Video = Node.create<VideoOptions>({
name: 'video',
group: 'block',
// Allows it to be selected and manipulated as a single block
selectable: true,
draggable: true,
addOptions() {
return {
HTMLAttributes: {
class: 'w-full rounded-lg border border-border/50 shadow-sm overflow-hidden my-4',
controls: true,
},
};
},
addAttributes() {
return {
src: {
default: null,
},
};
},
parseHTML() {
return [
{
tag: 'video',
},
];
},
renderHTML({ HTMLAttributes }) {
return ['video', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)];
},
addCommands() {
return {
setVideo: (options: { src: string }) => ({ commands }) => {
return commands.insertContent({
type: this.name,
attrs: options,
});
},
};
},
});
declare module '@tiptap/core' {
interface Commands<ReturnType> {
video: {
setVideo: (options: { src: string }) => ReturnType;
};
}
}