diff --git a/package-lock.json b/package-lock.json index 983941f6..9f5d401a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,10 @@ "dependencies": { "@heroicons/react": "^2.0.17", "@tanstack/react-query": "^5.17.8", + "@tiptap/extension-bubble-menu": "^2.14.0", "@tiptap/extension-color": "^2.12.0", - "@tiptap/extension-image": "^2.12.0", + "@tiptap/extension-image": "^2.14.0", + "@tiptap/extension-link": "^2.14.0", "@tiptap/extension-placeholder": "^2.14.0", "@tiptap/extension-youtube": "^2.12.0", "@tiptap/pm": "^2.12.0", @@ -2410,9 +2412,9 @@ } }, "node_modules/@tiptap/extension-bubble-menu": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.12.0.tgz", - "integrity": "sha512-DYijoE0igV0Oi+ZppFsp2UrQsM/4HZtmmpD78BJM9zfCbd1YvAUIxmzmXr8uqU18OHd1uQy+/zvuNoUNYyw67g==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.14.0.tgz", + "integrity": "sha512-sN15n0RjPh+2Asvxs7l47hVEvX6c0aPempU8QQWcPUlHoGf1D/XkyHXy6GWVPSxZ5Rj5uAwgKvhHsG/FJ/YGKQ==", "license": "MIT", "dependencies": { "tippy.js": "^6.3.7" @@ -2593,9 +2595,9 @@ } }, "node_modules/@tiptap/extension-image": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.12.0.tgz", - "integrity": "sha512-wO+yrfMlnW3SYCb1Q1qAb+nt5WH6jnlQPTV6qdoIabRtW0puwMWULZDUgclPN5hxn8EXb9vBEu44egvH6hgkfQ==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.14.0.tgz", + "integrity": "sha512-pYCUzZBgsxIvVGTzuW03cPz6PIrAo26xpoxqq4W090uMVoK0SgY5W5y0IqCdw4QyLkJ2/oNSFNc2EP9jVi1CcQ==", "license": "MIT", "funding": { "type": "github", @@ -2618,6 +2620,23 @@ "@tiptap/core": "^2.7.0" } }, + "node_modules/@tiptap/extension-link": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.14.0.tgz", + "integrity": "sha512-fsqW7eRD2xoD6xy7eFrNPAdIuZ3eicA4jKC45Vcft/Xky0DJoIehlVBLxsPbfmv3f27EBrtPkg5+msLXkLyzJA==", + "license": "MIT", + "dependencies": { + "linkifyjs": "^4.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, "node_modules/@tiptap/extension-list-item": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.12.0.tgz", @@ -8378,6 +8397,12 @@ "uc.micro": "^2.0.0" } }, + "node_modules/linkifyjs": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.3.1.tgz", + "integrity": "sha512-DRSlB9DKVW04c4SUdGvKK5FR6be45lTU9M76JnngqPeeGDqPwYc0zdUErtsNVMtxPXgUWV4HbXbnC4sNyBxkYg==", + "license": "MIT" + }, "node_modules/listr2": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", diff --git a/package.json b/package.json index 1d58f3c0..27083a4b 100644 --- a/package.json +++ b/package.json @@ -99,8 +99,10 @@ "dependencies": { "@heroicons/react": "^2.0.17", "@tanstack/react-query": "^5.17.8", + "@tiptap/extension-bubble-menu": "^2.14.0", "@tiptap/extension-color": "^2.12.0", - "@tiptap/extension-image": "^2.12.0", + "@tiptap/extension-image": "^2.14.0", + "@tiptap/extension-link": "^2.14.0", "@tiptap/extension-placeholder": "^2.14.0", "@tiptap/extension-youtube": "^2.12.0", "@tiptap/pm": "^2.12.0", diff --git a/src/Components/Input/RichTextEditor.tsx b/src/Components/Input/RichTextEditor.tsx index e5f90806..74aff56e 100644 --- a/src/Components/Input/RichTextEditor.tsx +++ b/src/Components/Input/RichTextEditor.tsx @@ -5,6 +5,7 @@ import { Color } from '@tiptap/extension-color' import { Image } from '@tiptap/extension-image' import { Placeholder } from '@tiptap/extension-placeholder' import { Youtube } from '@tiptap/extension-youtube' +import { Link } from '@tiptap/extension-link' import { EditorContent, useEditor } from '@tiptap/react' import { StarterKit } from '@tiptap/starter-kit' import { useEffect } from 'react' @@ -56,6 +57,7 @@ export function RichTextEditor({ }), Markdown, Image, + Link, Youtube.configure({ controls: false, nocookie: true, diff --git a/src/Components/Input/TextEditorMenu.tsx b/src/Components/Input/TextEditorMenu.tsx index 863daebe..275c219b 100644 --- a/src/Components/Input/TextEditorMenu.tsx +++ b/src/Components/Input/TextEditorMenu.tsx @@ -1,3 +1,5 @@ +import LinkIcon from '@heroicons/react/24/outline/LinkIcon' +import PhotoIcon from '@heroicons/react/24/outline/PhotoIcon' import BoldIcon from '@heroicons/react/24/solid/BoldIcon' import H1Icon from '@heroicons/react/24/solid/H1Icon' import H2Icon from '@heroicons/react/24/solid/H2Icon' @@ -6,6 +8,7 @@ import ItalicIcon from '@heroicons/react/24/solid/ItalicIcon' import ListBulletIcon from '@heroicons/react/24/solid/ListBulletIcon' import NumberedListIcon from '@heroicons/react/24/solid/NumberedListIcon' import { useEditorState } from '@tiptap/react' +import { useCallback, useEffect, useState } from 'react' import { MdUndo, MdRedo, MdHorizontalRule } from 'react-icons/md' import type { Editor } from '@tiptap/react' @@ -31,6 +34,7 @@ export const TextEditorMenu = ({ editor }: { editor: Editor }) => { isHeading4: ctx.editor.isActive('heading', { level: 4 }), isHeading5: ctx.editor.isActive('heading', { level: 5 }), isHeading6: ctx.editor.isActive('heading', { level: 6 }), + isHeading: ctx.editor.isActive('heading'), isBulletList: ctx.editor.isActive('bulletList'), isOrderedList: ctx.editor.isActive('orderedList'), isCodeBlock: ctx.editor.isActive('codeBlock'), @@ -41,31 +45,29 @@ export const TextEditorMenu = ({ editor }: { editor: Editor }) => { }, }) + const addImage = useCallback(() => { + const url = window.prompt('URL') + + if (url) { + editor.chain().focus().setImage({ src: url }).run() + } + }, [editor]) + + const [url, setUrl] = useState('') + + const setLink = (e: React.MouseEvent) => { + e.preventDefault() + + editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run() + } + return ( <>