From f76f00b1049254667c1f703c7c7ed2dc150574d4 Mon Sep 17 00:00:00 2001 From: Diivvuu Date: Sun, 13 Oct 2024 02:37:51 +0530 Subject: [PATCH] added changed in editor --- .../channel/[channelId]/chat-input.tsx | 27 ++- .../channel/[channelId]/page.tsx | 4 +- src/components/Editor.tsx | 202 +++++++++++++++++- 3 files changed, 223 insertions(+), 10 deletions(-) diff --git a/src/app/workspace/[workspaceId]/channel/[channelId]/chat-input.tsx b/src/app/workspace/[workspaceId]/channel/[channelId]/chat-input.tsx index cc4a41c..0df66d9 100644 --- a/src/app/workspace/[workspaceId]/channel/[channelId]/chat-input.tsx +++ b/src/app/workspace/[workspaceId]/channel/[channelId]/chat-input.tsx @@ -1,7 +1,24 @@ -import Editor from "@/components/Editor"; +import dynamic from "next/dynamic"; +import Quill from "quill"; +import { useRef } from "react"; -export const ChatInput = () => { - return
- -
; +const Editor = dynamic(() => import("@/components/Editor"), { ssr: false }); + +interface ChatInputProps { + placeholder: string; +} + +export const ChatInput = ({ placeholder }: ChatInputProps) => { + const editorRef = useRef(null); + return ( +
+ {}} + disabled={false} + innerRef={editorRef} + variant="create" + /> +
+ ); }; diff --git a/src/app/workspace/[workspaceId]/channel/[channelId]/page.tsx b/src/app/workspace/[workspaceId]/channel/[channelId]/page.tsx index 3e83022..dbe6bce 100644 --- a/src/app/workspace/[workspaceId]/channel/[channelId]/page.tsx +++ b/src/app/workspace/[workspaceId]/channel/[channelId]/page.tsx @@ -33,8 +33,8 @@ const ChannelIdPage = () => { return (
-
- +
+
); }; diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index 1303c22..d000e54 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -1,10 +1,65 @@ "use client"; +import { + MutableRefObject, + useEffect, + useLayoutEffect, + useRef, + useState, +} from "react"; + import Quill, { QuillOptions } from "quill"; import "quill/dist/quill.snow.css"; -import { useEffect, useRef } from "react"; -const Editor = () => { +import { Button } from "./ui/button"; +import { PiTextAa } from "react-icons/pi"; +import { MdSend } from "react-icons/md"; +import { Image, Smile } from "lucide-react"; +import { Hint } from "./hint"; +import { Delta, Op } from "quill/core"; +import { cn } from "@/lib/utils"; +import { current } from "../../convex/members"; + +type EditorValue = { + image: File | null; + body: string; +}; +//will be used to edit and create messages +interface EditorProps { + onSubmit: ({ image, body }: EditorValue) => void; + onCancel?: () => void; + placeholder?: string; + defaultValue?: Delta | Op[]; + disabled?: boolean; + innerRef?: MutableRefObject; + variant?: "create" | "update"; +} + +const Editor = ({ + onCancel, + onSubmit, + placeholder = "Write Something", + defaultValue = [], + disabled = false, + innerRef, + variant = "create", +}: EditorProps) => { + // cant use ref it wont rerender, need usestate to keep on checking length of text inside the editor + const [text, setText] = useState(""); + const [isToolbarVisible, setIsToolbarVisible] = useState(true); + //using ref bnecause it wont rerender the editor on every change const containerRef = useRef(null); + const submitRef = useRef(onSubmit); + const placeholderRef = useRef(placeholder); + const quillRef = useRef(null); + const defaultValueRef = useRef(defaultValue); + const disabledRef = useRef(disabled); + + useLayoutEffect(() => { + submitRef.current = onSubmit; + placeholderRef.current = placeholder; + defaultValueRef.current = defaultValue; + disabledRef.current = disabled; + }); useEffect(() => { if (typeof window === "undefined" || !containerRef.current) return; @@ -13,20 +68,161 @@ const Editor = () => { const editorContainer = container.appendChild( container.ownerDocument.createElement("div") ); + const toolbarOptions = [ + ["bold", "italic", "underline", "strike"], + ["blockquote", "code-block"], + ["link", "formula"], + [{ list: "ordered" }, { list: "bullet" }, { list: "check" }], + [{ size: ["small", false, "large", "huge"] }], + [{ header: [1, 2, 3, 4, 5, 6, false] }], + [{ color: [] }, { background: [] }], + [{ font: [] }], + [{ align: [] }], + ]; const options: QuillOptions = { theme: "snow", + placeholder: placeholderRef.current, + + modules: { + toolbar: toolbarOptions, + keyboard: { + bindings: { + enter: { + key: "Enter", + handler: () => { + return; //todo submit form + }, + }, + shift_enter: { + key: "Enter", + shiftKey: true, + handler: () => { + quill.insertText(quill.getSelection()?.index || 0, "\n"); + }, + }, + }, + }, + }, }; - new Quill(editorContainer, options); + const quill = new Quill(editorContainer, options); + quillRef.current = quill; + quillRef.current.focus(); + + if (innerRef) { + innerRef.current = quill; + } + + quill.setContents(defaultValueRef.current); + setText(quill.getText()); + + quill.on(Quill.events.TEXT_CHANGE, () => { + setText(quill.getText()); + }); return () => { + quill.off(Quill.events.TEXT_CHANGE); if (container) container.innerHTML = ""; + + if (quillRef.current) { + quillRef.current = null; + } + + if (innerRef) { + innerRef.current = null; + } }; }, []); + const isEmpty = text.replace(/<(.|\n)*?>/g, "").trim().length === 0; + + const toggleToolbar = () => { + setIsToolbarVisible((current) => !current); + const toolbarElement = containerRef.current?.querySelector(".ql-toolbar"); + + if (toolbarElement) { + toolbarElement.classList.toggle("hidden"); + } + }; + return (
+
+ + + + + + + {variant === "create" && ( + + + + )} + {variant === "create" ? ( + + ) : ( +
+ + +
+ )} +
+
+
+

+ Shift + Return to add a new line +

);