feat: init and add video extension to editor/canva

This commit is contained in:
swve 2022-12-14 17:49:21 +01:00
parent 8d0efdb93e
commit 9f916449c5
9 changed files with 163 additions and 10 deletions

View file

@ -7,6 +7,7 @@ import WarningCallout from "../Editor/Extensions/Callout/Warning/WarningCallout"
import ImageBlock from "../Editor/Extensions/Image/ImageBlock";
import Youtube from "@tiptap/extension-youtube";
import { EditorContentWrapper } from "../Editor/Editor";
import VideoBlock from "../Editor/Extensions/Video/VideoBlock";
interface Editor {
content: string;
@ -31,6 +32,10 @@ function Canva(props: Editor) {
editable: isEditable,
element: props.element,
}),
VideoBlock.configure({
editable: true,
element: props.element,
}),
Youtube.configure({
controls: true,
modestBranding: true,

View file

@ -17,6 +17,7 @@ import InfoCallout from "./Extensions/Callout/Info/InfoCallout";
import WarningCallout from "./Extensions/Callout/Warning/WarningCallout";
import ImageBlock from "./Extensions/Image/ImageBlock";
import Youtube from "@tiptap/extension-youtube";
import VideoBlock from "./Extensions/Video/VideoBlock";
interface Editor {
content: string;
@ -48,6 +49,10 @@ function Editor(props: Editor) {
editable: true,
element: props.element,
}),
VideoBlock.configure({
editable: true,
element: props.element,
}),
Youtube.configure({
controls: true,
modestBranding: true,

View file

@ -4,23 +4,28 @@ import { ReactNodeViewRenderer } from "@tiptap/react";
import VideoBlockComponent from "./VideoBlockComponent";
export default Node.create({
name: "calloutWarning",
name: "blockVideo",
group: "block",
draggable: true,
content: "inline*",
// TODO : multi line support
atom: true,
addAttributes() {
return {
fileObject: {
default: null,
},
};
},
parseHTML() {
return [
{
tag: "callout-warning",
tag: "block-video",
},
];
},
renderHTML({ HTMLAttributes }) {
return ["callout-info", mergeAttributes(HTMLAttributes), 0];
return ["block-video", mergeAttributes(HTMLAttributes), 0];
},
addNodeView() {

View file

@ -0,0 +1,86 @@
import { NodeViewWrapper } from "@tiptap/react";
import { AlertTriangle, Image, Video } from "lucide-react";
import React from "react";
import styled from "styled-components";
import { getBackendUrl } from "../../../../services/config";
import { uploadNewVideoFile } from "../../../../services/files/video";
function VideoBlockComponents(props: any) {
const [video, setVideo] = React.useState(null);
const [isLoading, setIsLoading] = React.useState(false);
const [fileObject, setfileObject] = React.useState(props.node.attrs.fileObject);
const handleVideoChange = (event: React.ChangeEvent<any>) => {
setVideo(event.target.files[0]);
};
const handleSubmit = async (e: any) => {
e.preventDefault();
setIsLoading(true);
let object = await uploadNewVideoFile(video, props.extension.options.element.element_id);
setIsLoading(false);
setfileObject(object);
props.updateAttributes({
fileObject: object,
});
};
return (
<NodeViewWrapper className="block-video">
{!fileObject && (
<BlockVideoWrapper contentEditable={props.extension.options.editable}>
<div>
<Video color="#e1e0e0" size={50} />
<br />
</div>
<input onChange={handleVideoChange} type="file" name="" id="" />
<br />
<button onClick={handleSubmit}>Submit</button>
</BlockVideoWrapper>
)}
{fileObject && (
<BlockVideo>
<video
controls
src={`${getBackendUrl()}content/uploads/files/videos/${props.extension.options.element.element_id}/${fileObject.file_id}.${
fileObject.file_format
}`}
></video>
</BlockVideo>
)}
{isLoading && (
<div>
<AlertTriangle color="#e1e0e0" size={50} />
</div>
)}
</NodeViewWrapper>
);
}
const BlockVideoWrapper = styled.div`
display: flex;
flex-direction: column;
background: #f9f9f9;
border-radius: 3px;
padding: 30px;
min-height: 74px;
border: ${(props) => (props.contentEditable ? "2px dashed #713f1117" : "none")};
// center
align-items: center;
justify-content: center;
text-align: center;
font-size: 14px;
`;
const BlockVideo = styled.div`
display: flex;
flex-direction: column;
video {
width: 100%;
border-radius: 6px;
height: 300px;
// cover
object-fit: cover;
}
`;
export default VideoBlockComponents;

View file

@ -1,6 +1,6 @@
import styled from "styled-components";
import { FontBoldIcon, FontItalicIcon, StrikethroughIcon, ArrowLeftIcon, ArrowRightIcon, OpacityIcon } from "@radix-ui/react-icons";
import { AlertCircle, AlertTriangle, ImagePlus, Info, Youtube } from "lucide-react";
import { AlertCircle, AlertTriangle, ImagePlus, Info, Video, Youtube } from "lucide-react";
export const ToolbarButtons = ({ editor }: any) => {
if (!editor) {
@ -74,6 +74,19 @@ export const ToolbarButtons = ({ editor }: any) => {
>
<ImagePlus size={15} />
</ToolBtn>
<ToolBtn
onClick={() =>
editor
.chain()
.focus()
.insertContent({
type: "blockVideo",
})
.run()
}
>
<Video size={15} />
</ToolBtn>
<ToolBtn onClick={() => addYoutubeVideo()}>
<Youtube size={15} />
</ToolBtn>

View file

@ -39,7 +39,7 @@ const AuthProvider = (props: any) => {
}
} else {
setAuth({ access_token, isAuthenticated: false, userInfo, isLoading });
router.push("/login");
//router.push("/login");
}
} catch (error) {
router.push("/");

View file

@ -0,0 +1,38 @@
import { getAPIUrl } from "../config";
export async function uploadNewVideoFile(file: any, element_id: string) {
const HeadersConfig = new Headers();
// Send file thumbnail as form data
const formData = new FormData();
formData.append("file_object", file);
formData.append("element_id", element_id);
const requestOptions: any = {
method: "POST",
headers: HeadersConfig,
redirect: "follow",
credentials: "include",
body: formData,
};
return fetch(`${getAPIUrl()}files/video`, requestOptions)
.then((result) => result.json())
.catch((error) => console.log("error", error));
}
export async function getVideoFile(file_id: string) {
const HeadersConfig = new Headers({ "Content-Type": "application/json" });
const requestOptions: any = {
method: "GET",
headers: HeadersConfig,
redirect: "follow",
credentials: "include",
};
return fetch(`${getAPIUrl()}files/video?file_id=${file_id}`, requestOptions)
.then((result) => result.json())
.catch((error) => console.log("error", error));
}