learnhouse/apps/web/components/Objects/Activities/DynamicCanva/DynamicCanva.tsx
2024-02-07 13:42:21 +05:45

264 lines
6.1 KiB
TypeScript

import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import styled from "styled-components"
import Youtube from "@tiptap/extension-youtube";
// Custom Extensions
import InfoCallout from "@components/Objects/Editor/Extensions/Callout/Info/InfoCallout";
import WarningCallout from "@components/Objects/Editor/Extensions/Callout/Warning/WarningCallout";
import ImageBlock from "@components/Objects/Editor/Extensions/Image/ImageBlock";
import VideoBlock from "@components/Objects/Editor/Extensions/Video/VideoBlock";
import MathEquationBlock from "@components/Objects/Editor/Extensions/MathEquation/MathEquationBlock";
import PDFBlock from "@components/Objects/Editor/Extensions/PDF/PDFBlock";
import { OrderedList } from "@tiptap/extension-ordered-list";
import QuizBlock from "@components/Objects/Editor/Extensions/Quiz/QuizBlock";
// Lowlight
import { common, createLowlight } from 'lowlight'
const lowlight = createLowlight(common)
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight';
import css from 'highlight.js/lib/languages/css'
import js from 'highlight.js/lib/languages/javascript'
import ts from 'highlight.js/lib/languages/typescript'
import html from 'highlight.js/lib/languages/xml'
import python from 'highlight.js/lib/languages/python'
import java from 'highlight.js/lib/languages/java'
import { NoTextInput } from "@components/Objects/Editor/Extensions/NoTextInput/NoTextInput";
import EditorOptionsProvider from "@components/Contexts/Editor/EditorContext";
import AICanvaToolkit from "./AI/AICanvaToolkit";
interface Editor {
content: string;
activity: any;
}
function Canva(props: Editor) {
/**
* Important Note : This is a workaround to enable user interaction features to be implemented easily, like text selection, AI features and other planned features, this is set to true but otherwise it should be set to false.
* Another workaround is implemented below to disable the editor from being edited by the user by setting the caret-color to transparent and using a custom extension to filter out transactions that add/edit/remove text.
* To let the various Custom Extensions know that the editor is not editable, React context (EditorOptionsProvider) will be used instead of props.extension.options.editable.
*/
const isEditable = true;
// Code Block Languages for Lowlight
lowlight.register('html', html)
lowlight.register('css', css)
lowlight.register('js', js)
lowlight.register('ts', ts)
lowlight.register('python', python)
lowlight.register('java', java)
const editor: any = useEditor({
editable: isEditable,
extensions: [
StarterKit,
NoTextInput,
// Custom Extensions
InfoCallout.configure({
editable: isEditable,
}),
WarningCallout.configure({
editable: isEditable,
}),
ImageBlock.configure({
editable: isEditable,
activity: props.activity,
}),
VideoBlock.configure({
editable: true,
activity: props.activity,
}),
MathEquationBlock.configure({
editable: false,
activity: props.activity,
}),
PDFBlock.configure({
editable: true,
activity: props.activity,
}),
QuizBlock.configure({
editable: isEditable,
activity: props.activity,
}),
Youtube.configure({
controls: true,
modestBranding: true,
}),
OrderedList.configure(),
CodeBlockLowlight.configure({
lowlight,
}),
],
content: props.content,
});
return (
<EditorOptionsProvider options={{ isEditable: false }}>
<CanvaWrapper>
<AICanvaToolkit activity={props.activity} editor={editor} />
<EditorContent editor={editor} />
</CanvaWrapper>
</EditorOptionsProvider>
);
}
const CanvaWrapper = styled.div`
width: 100%;
margin: 0 auto;
.bubble-menu {
display: flex;
background-color: #0D0D0D;
padding: 0.2rem;
border-radius: 0.5rem;
button {
border: none;
background: none;
color: #FFF;
font-size: 0.85rem;
font-weight: 500;
padding: 0 0.2rem;
opacity: 0.6;
&:hover,
&.is-active {
opacity: 1;
}
}
}
// disable chrome outline
.ProseMirror {
// Workaround to disable editor from being edited by the user.
caret-color: transparent;
h1 {
font-size: 30px;
font-weight: 600;
margin-bottom: 10px;
}
h2 {
font-size: 25px;
font-weight: 600;
margin-bottom: 10px;
}
h3 {
font-size: 20px;
font-weight: 600;
margin-bottom: 10px;
}
h4 {
font-size: 18px;
font-weight: 600;
margin-top: 10px;
margin-bottom: 10px;
}
h5 {
font-size: 16px;
font-weight: 600;
margin-top: 10px;
margin-bottom: 10px;
}
ul, ol {
padding: 0 1rem;
padding-left: 20px;
list-style-type: decimal;
}
&:focus {
outline: none !important;
outline-style: none !important;
box-shadow: none !important;
}
// Code Block
pre {
background: #0d0d0d;
border-radius: 0.5rem;
color: #fff;
font-family: "JetBrainsMono", monospace;
padding: 0.75rem 1rem;
code {
background: none;
color: inherit;
font-size: 0.8rem;
padding: 0;
}
.hljs-comment,
.hljs-quote {
color: #616161;
}
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #f98181;
}
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #fbbc88;
}
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #b9f18d;
}
.hljs-title,
.hljs-section {
color: #faf594;
}
.hljs-keyword,
.hljs-selector-tag {
color: #70cff8;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: 700;
}
}
}
`;
export default Canva;