feat: formatting buttons
This commit is contained in:
@@ -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 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if showFormattingButtons}
|
||||
<div bind:this={bubbleMenuElement} class="p-0">
|
||||
<FormattingButtons {editor} />
|
||||
</div>
|
||||
|
||||
<div bind:this={floatingMenuElement} class="p-0">
|
||||
<FormattingButtons {editor} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div bind:this={element} class="relative w-full min-w-full h-full min-h-fit {className}" />
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
<script>
|
||||
import { getContext } from 'svelte';
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
export let editor = null;
|
||||
|
||||
import Bold from '$lib/components/icons/Bold.svelte';
|
||||
import CodeBracket from '$lib/components/icons/CodeBracket.svelte';
|
||||
import H1 from '$lib/components/icons/H1.svelte';
|
||||
import H2 from '$lib/components/icons/H2.svelte';
|
||||
import H3 from '$lib/components/icons/H3.svelte';
|
||||
import Italic from '$lib/components/icons/Italic.svelte';
|
||||
import ListBullet from '$lib/components/icons/ListBullet.svelte';
|
||||
import NumberedList from '$lib/components/icons/NumberedList.svelte';
|
||||
import QueueList from '$lib/components/icons/QueueList.svelte';
|
||||
import Strikethrough from '$lib/components/icons/Strikethrough.svelte';
|
||||
import Underline from '$lib/components/icons/Underline.svelte';
|
||||
import Tooltip from '../Tooltip.svelte';
|
||||
</script>
|
||||
|
||||
<div class="flex gap-0.5 p-0.5 rounded-lg shadow-lg dark:bg-gray-800 min-w-fit">
|
||||
<Tooltip placement="top" content={$i18n.t('H1')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
class="{editor?.isActive('heading', { level: 1 })
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<H1 />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('H2')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
class="{editor?.isActive('heading', { level: 2 })
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<H2 />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('H3')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
class="{editor?.isActive('heading', { level: 3 })
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<H3 />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('Bullet List')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleBulletList().run()}
|
||||
class="{editor?.isActive('bulletList')
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<ListBullet />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('Ordered List')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleOrderedList().run()}
|
||||
class="{editor?.isActive('orderedList')
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<NumberedList />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('Task List')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleTaskList().run()}
|
||||
class="{editor?.isActive('taskList')
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<QueueList />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('Bold')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleBold().run()}
|
||||
class="{editor?.isActive('bold')
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<Bold />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('Italic')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleItalic().run()}
|
||||
class="{editor?.isActive('italic')
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<Italic />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('Underline')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleUnderline().run()}
|
||||
class="{editor?.isActive('underline')
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<Underline />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('Strikethrough')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleStrike().run()}
|
||||
class="{editor?.isActive('strike')
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<Strikethrough />
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip placement="top" content={$i18n.t('Code Block')}>
|
||||
<button
|
||||
on:click={() => editor?.chain().focus().toggleCodeBlock().run()}
|
||||
class="{editor?.isActive('codeBlock')
|
||||
? 'bg-gray-50 dark:bg-gray-700'
|
||||
: ''} hover:bg-gray-50 dark:hover:bg-gray-700 rounded-lg p-1.5 transition-all"
|
||||
type="button"
|
||||
>
|
||||
<CodeBracket />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
Reference in New Issue
Block a user