"use client" import * as React from "react" import { EditorContent, EditorContext, useEditor } from "@tiptap/react" // --- Tiptap Core Extensions --- import { StarterKit } from "@tiptap/starter-kit" import { Image } from "@tiptap/extension-image" import { TaskItem, TaskList } from "@tiptap/extension-list" import { TextAlign } from "@tiptap/extension-text-align" import { Typography } from "@tiptap/extension-typography" import { Highlight } from "@tiptap/extension-highlight" import { Subscript } from "@tiptap/extension-subscript" import { Superscript } from "@tiptap/extension-superscript" import { Selection } from "@tiptap/extensions" // --- UI Primitives --- import { Button } from "@/components/tiptap-ui-primitive/button" import { Spacer } from "@/components/tiptap-ui-primitive/spacer" import { Toolbar, ToolbarGroup, ToolbarSeparator, } from "@/components/tiptap-ui-primitive/toolbar" // --- Tiptap Node --- import { ImageUploadNode } from "@/components/tiptap-node/image-upload-node/image-upload-node-extension" import { HorizontalRule } from "@/components/tiptap-node/horizontal-rule-node/horizontal-rule-node-extension" import "@/components/tiptap-node/blockquote-node/blockquote-node.scss" import "@/components/tiptap-node/code-block-node/code-block-node.scss" import "@/components/tiptap-node/horizontal-rule-node/horizontal-rule-node.scss" import "@/components/tiptap-node/list-node/list-node.scss" import "@/components/tiptap-node/image-node/image-node.scss" import "@/components/tiptap-node/heading-node/heading-node.scss" import "@/components/tiptap-node/paragraph-node/paragraph-node.scss" // --- Tiptap UI --- import { HeadingDropdownMenu } from "@/components/tiptap-ui/heading-dropdown-menu" import { ImageUploadButton } from "@/components/tiptap-ui/image-upload-button" import { ListDropdownMenu } from "@/components/tiptap-ui/list-dropdown-menu" import { BlockquoteButton } from "@/components/tiptap-ui/blockquote-button" import { CodeBlockButton } from "@/components/tiptap-ui/code-block-button" import { ColorHighlightPopover, ColorHighlightPopoverContent, ColorHighlightPopoverButton, } from "@/components/tiptap-ui/color-highlight-popover" import { LinkPopover, LinkContent, LinkButton, } from "@/components/tiptap-ui/link-popover" import { MarkButton } from "@/components/tiptap-ui/mark-button" import { TextAlignButton } from "@/components/tiptap-ui/text-align-button" import { UndoRedoButton } from "@/components/tiptap-ui/undo-redo-button" // --- Icons --- import { ArrowLeftIcon } from "@/components/tiptap-icons/arrow-left-icon" import { HighlighterIcon } from "@/components/tiptap-icons/highlighter-icon" import { LinkIcon } from "@/components/tiptap-icons/link-icon" // --- Hooks --- import { useIsMobile } from "@/hooks/use-mobile" import { useWindowSize } from "@/hooks/use-window-size" import { useCursorVisibility } from "@/hooks/use-cursor-visibility" // --- Components --- import { ThemeToggle } from "@/components/tiptap-templates/simple/theme-toggle" // --- Lib --- import { handleImageUpload, MAX_FILE_SIZE } from "@/lib/tiptap-utils" // --- Styles --- import "@/components/tiptap-templates/simple/simple-editor.scss" import content from "@/components/tiptap-templates/simple/data/content.json" const MainToolbarContent = ({ onHighlighterClick, onLinkClick, isMobile, }: { onHighlighterClick: () => void onLinkClick: () => void isMobile: boolean }) => { return ( <> {!isMobile ? ( ) : ( )} {!isMobile ? : } {isMobile && } ) } const MobileToolbarContent = ({ type, onBack, }: { type: "highlighter" | "link" onBack: () => void }) => ( <> {type === "highlighter" ? ( ) : ( )} ) export function SimpleEditor() { const isMobile = useIsMobile() const { height } = useWindowSize() const [mobileView, setMobileView] = React.useState< "main" | "highlighter" | "link" >("main") const toolbarRef = React.useRef(null) const editor = useEditor({ immediatelyRender: false, shouldRerenderOnTransaction: false, editorProps: { attributes: { autocomplete: "off", autocorrect: "off", autocapitalize: "off", "aria-label": "Main content area, start typing to enter text.", class: "simple-editor", }, }, extensions: [ StarterKit.configure({ horizontalRule: false, link: { openOnClick: false, enableClickSelection: true, }, }), HorizontalRule, TextAlign.configure({ types: ["heading", "paragraph"] }), TaskList, TaskItem.configure({ nested: true }), Highlight.configure({ multicolor: true }), Image, Typography, Superscript, Subscript, Selection, ImageUploadNode.configure({ accept: "image/*", maxSize: MAX_FILE_SIZE, limit: 3, upload: handleImageUpload, onError: (error) => console.error("Upload failed:", error), }), ], content, }) const rect = useCursorVisibility({ editor, overlayHeight: toolbarRef.current?.getBoundingClientRect().height ?? 0, }) React.useEffect(() => { if (!isMobile && mobileView !== "main") { setMobileView("main") } }, [isMobile, mobileView]) return (
{mobileView === "main" ? ( setMobileView("highlighter")} onLinkClick={() => setMobileView("link")} isMobile={isMobile} /> ) : ( setMobileView("main")} /> )}
) }