diff --git a/package-lock.json b/package-lock.json index 137ed41921..63f4da6a3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,9 @@ "@sveltejs/adapter-node": "^2.0.0", "@sveltejs/svelte-virtual-list": "^3.0.1", "@tiptap/core": "^2.11.9", + "@tiptap/extension-bubble-menu": "^2.25.0", "@tiptap/extension-code-block-lowlight": "^2.11.9", + "@tiptap/extension-floating-menu": "^2.25.0", "@tiptap/extension-highlight": "^2.10.0", "@tiptap/extension-placeholder": "^2.10.0", "@tiptap/extension-table": "^2.12.0", @@ -29,6 +31,7 @@ "@tiptap/extension-task-item": "^2.25.0", "@tiptap/extension-task-list": "^2.25.0", "@tiptap/extension-typography": "^2.10.0", + "@tiptap/extension-underline": "^2.25.0", "@tiptap/pm": "^2.11.7", "@tiptap/starter-kit": "^2.10.0", "@xyflow/svelte": "^0.1.19", @@ -2952,6 +2955,23 @@ "@tiptap/core": "^2.7.0" } }, + "node_modules/@tiptap/extension-bubble-menu": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.25.0.tgz", + "integrity": "sha512-BnbfQWRXJDDy9/x/0Atu2Nka5ZAMyXLDFqzSLMAXqXSQcG6CZRTSNRgOCnjpda6Hq2yCtq7l/YEoXkbHT1ZZdQ==", + "license": "MIT", + "dependencies": { + "tippy.js": "^6.3.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, "node_modules/@tiptap/extension-bullet-list": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.10.0.tgz", @@ -3036,6 +3056,23 @@ "@tiptap/pm": "^2.7.0" } }, + "node_modules/@tiptap/extension-floating-menu": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.25.0.tgz", + "integrity": "sha512-hPZ5SNpI14smTz4GpWQXTnxmeICINYiABSgXcsU5V66tik9OtxKwoCSR/gpU35esaAFUVRdjW7+sGkACLZD5AQ==", + "license": "MIT", + "dependencies": { + "tippy.js": "^6.3.7" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, "node_modules/@tiptap/extension-gapcursor": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.10.0.tgz", @@ -3315,6 +3352,19 @@ "@tiptap/core": "^2.7.0" } }, + "node_modules/@tiptap/extension-underline": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.25.0.tgz", + "integrity": "sha512-RqXkWSMJyllfsDukugDzWEZfWRUOgcqzuMWC40BnuDUs4KgdRA0nhVUWJbLfUEmXI0UVqN5OwYTTAdhaiF7kjQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, "node_modules/@tiptap/pm": { "version": "2.11.7", "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.11.7.tgz", diff --git a/package.json b/package.json index 4bc2fadd65..1ef8049e14 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,9 @@ "@sveltejs/adapter-node": "^2.0.0", "@sveltejs/svelte-virtual-list": "^3.0.1", "@tiptap/core": "^2.11.9", + "@tiptap/extension-bubble-menu": "^2.25.0", "@tiptap/extension-code-block-lowlight": "^2.11.9", + "@tiptap/extension-floating-menu": "^2.25.0", "@tiptap/extension-highlight": "^2.10.0", "@tiptap/extension-placeholder": "^2.10.0", "@tiptap/extension-table": "^2.12.0", @@ -73,6 +75,7 @@ "@tiptap/extension-task-item": "^2.25.0", "@tiptap/extension-task-list": "^2.25.0", "@tiptap/extension-typography": "^2.10.0", + "@tiptap/extension-underline": "^2.25.0", "@tiptap/pm": "^2.11.7", "@tiptap/starter-kit": "^2.10.0", "@xyflow/svelte": "^0.1.19", diff --git a/src/app.css b/src/app.css index 5ffe32827c..b2d7d527cf 100644 --- a/src/app.css +++ b/src/app.css @@ -488,3 +488,7 @@ input[type='number'] { .tiptap tr { @apply bg-white dark:bg-gray-900 dark:border-gray-850 text-xs; } + +.tippy-box[data-theme~='transparent'] { + @apply bg-transparent p-0 m-0; +} diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 04d825c05f..f8af668911 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1058,6 +1058,7 @@ }} json={true} messageInput={true} + showFormattingButtons={false} insertPromptAsRichText={$settings?.insertPromptAsRichText ?? false} shiftEnter={!($settings?.ctrlEnterToSend ?? false) && (!$mobile || diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index 3293ac96a4..21dc926ccf 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -23,9 +23,10 @@ } }); - import { onMount, onDestroy, tick } from 'svelte'; + import { onMount, onDestroy, tick, getContext } from 'svelte'; import { createEventDispatcher } from 'svelte'; + const i18n = getContext('i18n'); const eventDispatch = createEventDispatcher(); import { Fragment, DOMParser } from 'prosemirror-model'; @@ -39,6 +40,7 @@ import TableHeader from '@tiptap/extension-table-header'; import TableCell from '@tiptap/extension-table-cell'; + import Underline from '@tiptap/extension-underline'; import TaskItem from '@tiptap/extension-task-item'; import TaskList from '@tiptap/extension-task-list'; @@ -47,10 +49,16 @@ import StarterKit from '@tiptap/starter-kit'; import Highlight from '@tiptap/extension-highlight'; import Typography from '@tiptap/extension-typography'; + + import BubbleMenu from '@tiptap/extension-bubble-menu'; + import FloatingMenu from '@tiptap/extension-floating-menu'; + import { all, createLowlight } from 'lowlight'; import { PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants'; + import FormattingButtons from './RichTextInput/FormattingButtons.svelte'; + export let oncompositionstart = (e) => {}; export let oncompositionend = (e) => {}; export let onChange = (e) => {}; @@ -69,6 +77,8 @@ export let raw = false; export let editable = true; + export let showFormattingButtons = true; + export let preserveBreaks = false; export let generateAutoCompletion: Function = async () => null; export let autocomplete = false; @@ -77,6 +87,8 @@ export let largeTextAsFile = false; export let insertPromptAsRichText = false; + let floatingMenuElement = null; + let bubbleMenuElement = null; let element; let editor; @@ -447,6 +459,7 @@ }), Highlight, Typography, + Underline, Placeholder.configure({ placeholder }), Table.configure({ resizable: true }), TableRow, @@ -473,6 +486,31 @@ } }) ] + : []), + + ...(showFormattingButtons + ? [ + BubbleMenu.configure({ + element: bubbleMenuElement, + tippyOptions: { + duration: 100, + arrow: false, + placement: 'top', + theme: 'transparent', + offset: [0, 2] + } + }), + FloatingMenu.configure({ + element: floatingMenuElement, + tippyOptions: { + duration: 100, + arrow: false, + placement: 'top-start', + theme: 'transparent', + offset: [-10, 2] + } + }) + ] : []) ], content: content, @@ -738,4 +776,14 @@ }; +{#if showFormattingButtons} +