diff --git a/front/components/Canva/Canva.tsx b/front/components/Canva/Canva.tsx new file mode 100644 index 00000000..81991667 --- /dev/null +++ b/front/components/Canva/Canva.tsx @@ -0,0 +1,32 @@ +import React from "react"; +import { useEditor, EditorContent } from "@tiptap/react"; +import StarterKit from "@tiptap/starter-kit"; +// Custom Extensions +import InfoCallout from "../Editor/Extensions/Callout/Info/InfoCallout"; + +interface Editor { + content: string; + element: any; + //course: any; +} + +function Canva(props: Editor) { + const isEditable = false; + const editor: any = useEditor({ + editable: isEditable, + extensions: [ + StarterKit, + + // Custom Extensions + InfoCallout.configure({ + editable: isEditable, + }), + ], + + content: props.content, + }); + + return ; +} + +export default Canva; diff --git a/front/components/Editor/Editor.tsx b/front/components/Editor/Editor.tsx index d0fb944c..6f098fd9 100644 --- a/front/components/Editor/Editor.tsx +++ b/front/components/Editor/Editor.tsx @@ -10,8 +10,10 @@ import { motion, AnimatePresence } from "framer-motion"; import Image from "next/image"; import styled from "styled-components"; import { getBackendUrl } from "../../services/config"; -import { GlobeIcon, PaperPlaneIcon, SlashIcon } from "@radix-ui/react-icons"; +import { SlashIcon } from "@radix-ui/react-icons"; import Avvvatars from "avvvatars-react"; +// extensions +import InfoCallout from "./Extensions/Callout/Info/InfoCallout"; interface Editor { content: string; @@ -26,23 +28,27 @@ function Editor(props: Editor) { const auth: any = React.useContext(AuthContext); const editor: any = useEditor({ + editable: true, extensions: [ StarterKit.configure({ // The Collaboration extension comes with its own history handling - history: false, + // history: false, + }), + InfoCallout.configure({ + editable: true, }), // Register the document with Tiptap - Collaboration.configure({ - document: props.ydoc, - }), + // Collaboration.configure({ + // document: props.ydoc, + // }), // Register the collaboration cursor extension - CollaborationCursor.configure({ - provider: props.provider, - user: { - name: auth.userInfo.username, - color: "#f783ac", - }, - }), + // CollaborationCursor.configure({ + // provider: props.provider, + // user: { + // name: auth.userInfo.username, + // color: "#f783ac", + // }, + // }), ], content: props.content, @@ -65,15 +71,13 @@ function Editor(props: Editor) { - + {" "} {props.course.course.name} {props.element.name}{" "} - props.setContent(editor.getJSON())}> - Save - + props.setContent(editor.getJSON())}>Save @@ -90,7 +94,6 @@ function Editor(props: Editor) { ); } + const Page = styled.div` height: 100vh; width: 100%; @@ -113,13 +117,13 @@ const Page = styled.div` min-width: 100vw; padding-top: 30px; - // dots background + // dots background background-image: radial-gradient(#4744446b 1px, transparent 1px), radial-gradient(#4744446b 1px, transparent 1px); background-position: 0 0, 25px 25px; background-size: 50px 50px; background-attachment: fixed; background-repeat: repeat; -` +`; const EditorTop = styled.div` background-color: #ffffffb8; diff --git a/front/components/Editor/Extensions/Callout/Info/InfoCallout.ts b/front/components/Editor/Extensions/Callout/Info/InfoCallout.ts new file mode 100644 index 00000000..a12aaf45 --- /dev/null +++ b/front/components/Editor/Extensions/Callout/Info/InfoCallout.ts @@ -0,0 +1,27 @@ +import { mergeAttributes, Node } from "@tiptap/core"; +import { ReactNodeViewRenderer } from "@tiptap/react"; + +import InfoCalloutComponent from "./InfoCalloutComponent"; + +export default Node.create({ + name: "calloutInfo", + group: "block", + draggable: true, + content: "inline*", + + parseHTML() { + return [ + { + tag: "callout-info", + }, + ]; + }, + + renderHTML({ HTMLAttributes }) { + return ["callout-info", mergeAttributes(HTMLAttributes), 0]; + }, + + addNodeView() { + return ReactNodeViewRenderer(InfoCalloutComponent); + }, +}); diff --git a/front/components/Editor/Extensions/Callout/Info/InfoCalloutComponent.tsx b/front/components/Editor/Extensions/Callout/Info/InfoCalloutComponent.tsx new file mode 100644 index 00000000..7ef60f05 --- /dev/null +++ b/front/components/Editor/Extensions/Callout/Info/InfoCalloutComponent.tsx @@ -0,0 +1,45 @@ +import { NodeViewContent, NodeViewWrapper } from "@tiptap/react"; +import React from "react"; +import styled from "styled-components"; + +function InfoCalloutComponent(props: any) { + return ( + + +
⚠️
+
+
+ ); +} + +const InfoCalloutWrapper = styled.div` + display: flex; + flex-direction: row; + background: #fefce8; + color: #713f11; + border: 1px solid #fff103; + border-radius: 16px; + margin: 1rem 0; + align-items: center; + padding-left: 15px; + + + .content { + margin: 5px; + padding: 0.5rem; + border: ${(props) => (props.contentEditable ? "2px dashed #713f1117" : "none")}; + border-radius: 0.5rem; + } +`; + +const DragHandle = styled.div` + position: absolute; + top: 0; + left: 0; + width: 1rem; + height: 100%; + cursor: move; + z-index: 1; +`; + +export default InfoCalloutComponent; diff --git a/front/components/Editor/Toolbar/ToolbarButtons.tsx b/front/components/Editor/Toolbar/ToolbarButtons.tsx index 3e682fbc..995a4a03 100644 --- a/front/components/Editor/Toolbar/ToolbarButtons.tsx +++ b/front/components/Editor/Toolbar/ToolbarButtons.tsx @@ -1,5 +1,6 @@ import styled from "styled-components"; -import { FontBoldIcon, FontItalicIcon, StrikethroughIcon, ArrowLeftIcon, ArrowRightIcon } from "@radix-ui/react-icons"; +import { FontBoldIcon, FontItalicIcon, StrikethroughIcon, ArrowLeftIcon, ArrowRightIcon, OpacityIcon } from "@radix-ui/react-icons"; +import { AlertTriangle, Info } from "lucide-react"; export const ToolbarButtons = ({ editor }: any) => { if (!editor) { @@ -31,6 +32,10 @@ export const ToolbarButtons = ({ editor }: any) => { + {/* TODO: fix this : toggling only works one-way */} + editor.chain().focus().toggleNode('calloutInfo').run()} > + + ); }; @@ -49,10 +54,13 @@ const ToolBtn = styled.div` width: 25px; height: 25px; padding: 5px; - font-size: 5px; margin-right: 5px; transition: all 0.2s ease-in-out; + svg{ + padding: 1px; + } + &.is-active { background: rgba(176, 176, 176, 0.5); diff --git a/front/package-lock.json b/front/package-lock.json index 4542cc72..a342a827 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -17,6 +17,7 @@ "@tiptap/starter-kit": "^2.0.0-beta.199", "avvvatars-react": "^0.4.2", "framer-motion": "^7.3.6", + "lucide-react": "^0.104.1", "next": "12.3.1", "react": "18.2.0", "react-beautiful-dnd": "^13.1.1", @@ -3532,6 +3533,15 @@ "node": ">=10" } }, + "node_modules/lucide-react": { + "version": "0.104.1", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.104.1.tgz", + "integrity": "sha512-BKvhulnLKmBj+6pqUN5ViYk4a5fabMgc4B0a4ZLUnbRqkDDWH3h7Iet6U4WbesJzjWauQrXUlEvQCe5XpFuRnw==", + "peerDependencies": { + "prop-types": "^15.7.2", + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", @@ -7577,6 +7587,12 @@ "yallist": "^4.0.0" } }, + "lucide-react": { + "version": "0.104.1", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.104.1.tgz", + "integrity": "sha512-BKvhulnLKmBj+6pqUN5ViYk4a5fabMgc4B0a4ZLUnbRqkDDWH3h7Iet6U4WbesJzjWauQrXUlEvQCe5XpFuRnw==", + "requires": {} + }, "memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", diff --git a/front/package.json b/front/package.json index ec6ffb14..1f7280a8 100644 --- a/front/package.json +++ b/front/package.json @@ -18,6 +18,7 @@ "@tiptap/starter-kit": "^2.0.0-beta.199", "avvvatars-react": "^0.4.2", "framer-motion": "^7.3.6", + "lucide-react": "^0.104.1", "next": "12.3.1", "react": "18.2.0", "react-beautiful-dnd": "^13.1.1", diff --git a/front/pages/index.tsx b/front/pages/index.tsx index 0fe7549e..cf64a4ae 100644 --- a/front/pages/index.tsx +++ b/front/pages/index.tsx @@ -4,12 +4,10 @@ import styled from "styled-components"; import learnhouseBigIcon from "public/learnhouse_bigicon.png"; import Image from "next/image"; import Link from "next/link"; -import { PreAlphaLabel } from "../components//UI/Layout"; const Home: NextPage = () => { return ( - 🚧 Pre-Alpha { - if (router.isReady && !isLoading) { - console.log(element); - - if (element.type == "dynamic") { - let content = - Object.keys(element.content).length > 0 - ? element.content - : { - type: "doc", - content: [ - { - type: "paragraph", - content: [ - { - type: "text", - text: "Hello world, this is a example Canva ⚡️", - }, - ], - }, - ], - }; - console.log("element", content); - - return generateHTML(content, [Document, StarterKit, Paragraph, Text, Bold]); - } - } - }, [element.content]); - return ( {isLoading ? ( @@ -69,7 +35,7 @@ function ElementPage() {

{element.name}


- {element.type == "dynamic" &&
} + {element.type == "dynamic" && } {/* todo : use apis & streams instead of this */} {element.type == "video" && ( diff --git a/front/tsconfig.json b/front/tsconfig.json index 99710e85..b8d3d81d 100644 --- a/front/tsconfig.json +++ b/front/tsconfig.json @@ -16,5 +16,12 @@ "incremental": true }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "paths": { + "@components/*": ["components/*"], + "@public/*": ["public/*"], + "@images/*": ["public/img/*"], + "@services/*": ["services/*"], + "@editor/*": ["components/Editor/*"] + }, "exclude": ["node_modules"] }