Merge branch 'feat/release-v2' of https://github.com/classroomio/classroomio into feat/release-v2
This commit is contained in:
+21
-21
@@ -37,33 +37,33 @@
|
||||
"vaul-svelte": "1.0.0-next.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aarkue/tiptap-math-extension": "^1.4.0",
|
||||
"@floating-ui/dom": "^1.7.4",
|
||||
"@tiptap/core": "^3.7.1",
|
||||
"@tiptap/extension-bubble-menu": "^3.7.1",
|
||||
"@tiptap/extension-code-block-lowlight": "^3.7.1",
|
||||
"@tiptap/extension-highlight": "^3.7.1",
|
||||
"@tiptap/extension-image": "^3.7.1",
|
||||
"@tiptap/extension-list": "^3.7.1",
|
||||
"@tiptap/extension-subscript": "^3.7.1",
|
||||
"@tiptap/extension-superscript": "^3.7.1",
|
||||
"@tiptap/extension-table": "^3.7.1",
|
||||
"@tiptap/extension-text-align": "^3.7.1",
|
||||
"@tiptap/extension-text-style": "^3.7.1",
|
||||
"@tiptap/extension-typography": "^3.7.1",
|
||||
"@tiptap/extensions": "^3.7.1",
|
||||
"@tiptap/pm": "^3.7.1",
|
||||
"@tiptap/starter-kit": "^3.7.1",
|
||||
"@tiptap/suggestion": "^3.7.1",
|
||||
"@tiptap/core": "^3.10.7",
|
||||
"@tiptap/extension-bubble-menu": "^3.10.7",
|
||||
"@tiptap/extension-code-block-lowlight": "^3.10.7",
|
||||
"@tiptap/extension-highlight": "^3.10.7",
|
||||
"@tiptap/extension-image": "^3.10.7",
|
||||
"@tiptap/extension-list": "^3.10.7",
|
||||
"@tiptap/extension-mathematics": "^3.10.7",
|
||||
"@tiptap/extension-subscript": "^3.10.7",
|
||||
"@tiptap/extension-superscript": "^3.10.7",
|
||||
"@tiptap/extension-table": "^3.10.7",
|
||||
"@tiptap/extension-text-align": "^3.10.7",
|
||||
"@tiptap/extension-text-style": "^3.10.7",
|
||||
"@tiptap/extension-typography": "^3.10.7",
|
||||
"@tiptap/extensions": "^3.10.7",
|
||||
"@tiptap/markdown": "^3.10.7",
|
||||
"@tiptap/pm": "^3.10.7",
|
||||
"@tiptap/starter-kit": "^3.10.7",
|
||||
"@tiptap/suggestion": "^3.10.7",
|
||||
"d3-array": "^3.2.4",
|
||||
"d3-scale": "^4.0.2",
|
||||
"dompurify": "^3.3.0",
|
||||
"katex": "^0.16.22",
|
||||
"katex": "^0.16.25",
|
||||
"lowlight": "^3.3.0",
|
||||
"svelte-tiptap": "^3.0.0",
|
||||
"svelte-tiptap": "^2.2.0",
|
||||
"tippy.js": "^6.3.7",
|
||||
"tiptap-extension-auto-joiner": "^0.1.3",
|
||||
"tiptap-markdown": "^0.9.0"
|
||||
"tiptap-extension-auto-joiner": "^0.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bits-ui": "^2.14.4"
|
||||
|
||||
@@ -26,6 +26,10 @@ import Table from '@lucide/svelte/icons/table';
|
||||
import Underline from '@lucide/svelte/icons/underline';
|
||||
import Undo from '@lucide/svelte/icons/undo-2';
|
||||
import Video from '@lucide/svelte/icons/video';
|
||||
import Radical from '@lucide/svelte/icons/radical';
|
||||
import SquareRadical from '@lucide/svelte/icons/square-radical';
|
||||
import { isTextSelection } from '@tiptap/core';
|
||||
import Pilcrow from '@lucide/svelte/icons/pilcrow';
|
||||
import { isMac } from '../utils';
|
||||
|
||||
const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
@@ -64,6 +68,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleHeading({ level: 1 }).run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).setHeading({ level: 1 }).run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleHeading({ level: 1 });
|
||||
},
|
||||
@@ -79,6 +86,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleHeading({ level: 2 }).run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).setHeading({ level: 2 }).run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleHeading({ level: 2 });
|
||||
},
|
||||
@@ -94,6 +104,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleHeading({ level: 3 }).run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).setHeading({ level: 3 }).run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleHeading({ level: 3 });
|
||||
},
|
||||
@@ -109,6 +122,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleHeading({ level: 4 }).run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).setHeading({ level: 4 }).run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleHeading({ level: 4 });
|
||||
},
|
||||
@@ -136,6 +152,24 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
return editor.isActive('link');
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: Pilcrow,
|
||||
name: 'paragraph',
|
||||
tooltip: 'Paragraph',
|
||||
shortCut: `${isMac ? '⌘⇧' : 'Ctrl+Shift+'}0`,
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().setParagraph().run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).setParagraph().run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().setParagraph();
|
||||
},
|
||||
isActive: (editor) => {
|
||||
return editor.isActive('paragraph');
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: Bold,
|
||||
name: 'bold',
|
||||
@@ -144,6 +178,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleBold().run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).setMark('bold').run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleBold();
|
||||
},
|
||||
@@ -159,6 +196,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleItalic().run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).setMark('italic').run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleItalic();
|
||||
},
|
||||
@@ -174,6 +214,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleUnderline().run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).setMark('underline').run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleUnderline();
|
||||
},
|
||||
@@ -189,6 +232,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleStrike().run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).setMark('strike').run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleStrike();
|
||||
},
|
||||
@@ -204,6 +250,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleBlockquote().run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).toggleBlockquote().run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleBlockquote();
|
||||
},
|
||||
@@ -219,6 +268,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleCode().run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).toggleCodeBlock().run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleCode();
|
||||
},
|
||||
@@ -320,6 +372,9 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleBulletList().run();
|
||||
},
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).toggleBulletList().run();
|
||||
},
|
||||
isActive: (editor) => editor.isActive('bulletList')
|
||||
},
|
||||
{
|
||||
@@ -330,7 +385,15 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleOrderedList().run();
|
||||
},
|
||||
isActive: (editor) => editor.isActive('orderedList')
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).toggleOrderedList().run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleOrderedList();
|
||||
},
|
||||
isActive: (editor) => {
|
||||
return editor.isActive('orderedList');
|
||||
}
|
||||
},
|
||||
{
|
||||
icon: ListChecks,
|
||||
@@ -340,7 +403,15 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
onClick: (editor) => {
|
||||
editor.chain().focus().toggleTaskList().run();
|
||||
},
|
||||
isActive: (editor) => editor.isActive('taskList')
|
||||
turnInto: (editor, pos) => {
|
||||
editor.chain().setNodeSelection(pos).toggleTaskList().run();
|
||||
},
|
||||
clickable: (editor) => {
|
||||
return editor.can().toggleTaskList();
|
||||
},
|
||||
isActive: (editor) => {
|
||||
return editor.isActive('taskList');
|
||||
}
|
||||
}
|
||||
],
|
||||
media: [
|
||||
@@ -398,6 +469,34 @@ const commands: Record<string, EdraToolBarCommands[]> = {
|
||||
},
|
||||
isActive: (editor) => editor.isActive('table')
|
||||
}
|
||||
],
|
||||
math: [
|
||||
{
|
||||
icon: Radical,
|
||||
name: 'mathematics',
|
||||
tooltip: 'Inline Expression',
|
||||
onClick: (editor) => {
|
||||
let latex = 'a^2 + b^2 = c^2';
|
||||
const chain = editor.chain().focus();
|
||||
if (isTextSelection(editor.view.state.selection)) {
|
||||
const { from, to } = editor.view.state.selection;
|
||||
latex = editor.view.state.doc.textBetween(from, to);
|
||||
chain.deleteRange({ from, to });
|
||||
}
|
||||
chain.insertInlineMath({ latex }).run();
|
||||
},
|
||||
isActive: (editor) => editor.isActive('inlineMath')
|
||||
},
|
||||
{
|
||||
icon: SquareRadical,
|
||||
name: 'mathematics',
|
||||
tooltip: 'Block Expression',
|
||||
onClick: (editor) => {
|
||||
const latex = 'a^2 + b^2 = c^2';
|
||||
editor.chain().focus().insertBlockMath({ latex }).run();
|
||||
},
|
||||
isActive: (editor) => editor.isActive('blockMath')
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface EdraToolBarCommands {
|
||||
tooltip?: string;
|
||||
shortCut?: string;
|
||||
onClick?: (editor: Editor) => void;
|
||||
turnInto?: (editor: Editor, pos: number) => void;
|
||||
isActive?: (editor: Editor) => boolean;
|
||||
clickable?: (editor: Editor) => boolean;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
}
|
||||
|
||||
/* For Placeholder */
|
||||
.tiptap .is-empty::before {
|
||||
|
||||
.tiptap .is-empty:not(blockquote.is-empty)::before {
|
||||
pointer-events: none;
|
||||
float: left;
|
||||
height: 0;
|
||||
color: var(--border-color-hover);
|
||||
color: var(--color-muted-foreground);
|
||||
content: attr(data-placeholder);
|
||||
}
|
||||
|
||||
@@ -66,12 +67,12 @@
|
||||
}
|
||||
|
||||
.tiptap blockquote::before {
|
||||
content: '';
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 0.25rem;
|
||||
width: 0.4rem;
|
||||
background-color: var(--blockquote-border);
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
@@ -208,8 +209,8 @@ input[type='checkbox'] {
|
||||
align-items: center;
|
||||
cursor: grab;
|
||||
opacity: 100;
|
||||
transition-property: opacity;
|
||||
transition-duration: 200ms;
|
||||
transition-property: all;
|
||||
transition-duration: 300ms;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
|
||||
color: var(--border-color-hover);
|
||||
}
|
||||
@@ -452,3 +453,41 @@ input[type='checkbox'] {
|
||||
.tiptap iframe {
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
|
||||
/* Mathematics extension styles */
|
||||
.tiptap .tiptap-mathematics-render {
|
||||
padding: 0 0.25rem;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
/* Editable math block */
|
||||
.tiptap .tiptap-mathematics-render--editable {
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.tiptap .tiptap-mathematics-render--editable:hover {
|
||||
background: var(--code-bg);
|
||||
}
|
||||
|
||||
/* Inline math */
|
||||
.tiptap .tiptap-mathematics-render[data-type='inline-math'] {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* Block math */
|
||||
.tiptap .tiptap-mathematics-render[data-type='block-math'] {
|
||||
display: block;
|
||||
margin: 1rem 0;
|
||||
padding: 0.5rem;
|
||||
text-align: center;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
/* Error styles */
|
||||
.tiptap .tiptap-mathematics-render.inline-math-error,
|
||||
.tiptap .tiptap-mathematics-render.block-math-error {
|
||||
background: var(--code-bg);
|
||||
color: var(--color-destructive);
|
||||
border: 1px solid darkred;
|
||||
}
|
||||
|
||||
@@ -12,10 +12,12 @@ import SearchAndReplace from './extensions/FindAndReplace';
|
||||
import { TaskItem, TaskList } from '@tiptap/extension-list';
|
||||
import { Table, TableCell, TableRow, TableHeader } from './extensions/table';
|
||||
import { Placeholder } from '@tiptap/extensions';
|
||||
import { Markdown } from 'tiptap-markdown';
|
||||
import MathExtension from '@aarkue/tiptap-math-extension';
|
||||
import { Markdown } from '@tiptap/markdown';
|
||||
import MathMatics from '@tiptap/extension-mathematics';
|
||||
|
||||
import AutoJoiner from 'tiptap-extension-auto-joiner';
|
||||
import 'katex/dist/katex.min.css';
|
||||
import { InlineMathReplacer } from './extensions/InlineMathReplacer';
|
||||
|
||||
export default (
|
||||
element?: HTMLElement,
|
||||
@@ -82,22 +84,41 @@ export default (
|
||||
nested: true
|
||||
}),
|
||||
SearchAndReplace,
|
||||
MathExtension.configure({ evaluation: true }),
|
||||
InlineMathReplacer,
|
||||
MathMatics.configure({
|
||||
blockOptions: {
|
||||
onClick: (node, pos) => {
|
||||
const newCalculation = prompt('Enter new calculation:', node.attrs.latex);
|
||||
if (newCalculation) {
|
||||
editor
|
||||
.chain()
|
||||
.setNodeSelection(pos)
|
||||
.updateBlockMath({ latex: newCalculation })
|
||||
.focus()
|
||||
.run();
|
||||
}
|
||||
}
|
||||
},
|
||||
inlineOptions: {
|
||||
onClick: (node, pos) => {
|
||||
const newCalculation = prompt('Enter new calculation:', node.attrs.latex);
|
||||
if (newCalculation) {
|
||||
editor
|
||||
.chain()
|
||||
.setNodeSelection(pos)
|
||||
.updateInlineMath({ latex: newCalculation })
|
||||
.focus()
|
||||
.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
AutoJoiner,
|
||||
Table,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
TableCell,
|
||||
Markdown.configure({
|
||||
html: true,
|
||||
tightLists: true,
|
||||
tightListClass: 'tight',
|
||||
bulletListMarker: '-',
|
||||
linkify: true,
|
||||
breaks: true,
|
||||
transformPastedText: true,
|
||||
transformCopiedText: false
|
||||
}),
|
||||
Markdown,
|
||||
|
||||
...(extensions ?? [])
|
||||
],
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { textInputRule } from '@tiptap/core';
|
||||
import { InlineMath } from '@tiptap/extension-mathematics';
|
||||
|
||||
export const InlineMathReplacer = InlineMath.extend({
|
||||
name: 'inlineMathReplacer',
|
||||
addInputRules() {
|
||||
return [
|
||||
textInputRule({
|
||||
find: /\$\$([^$]+)\$\$/,
|
||||
replace: ({ match, commands }) => {
|
||||
const latex = match[1];
|
||||
// Insert the inline math node with the LaTeX content
|
||||
commands.insertInlineMath({
|
||||
latex
|
||||
});
|
||||
return '';
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
});
|
||||
@@ -42,6 +42,7 @@ export const GROUPS: Group[] = [
|
||||
actions: [
|
||||
...commands.media,
|
||||
...commands.table,
|
||||
...commands.math,
|
||||
{
|
||||
icon: Minus,
|
||||
name: 'horizontalRule',
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
import Duplicate from '@lucide/svelte/icons/copy';
|
||||
import Clipboard from '@lucide/svelte/icons/clipboard';
|
||||
import Delete from '@lucide/svelte/icons/trash-2';
|
||||
import Repeat2 from '@lucide/svelte/icons/repeat-2';
|
||||
import Plus from '@lucide/svelte/icons/plus';
|
||||
import { NodeSelection } from '@tiptap/pm/state';
|
||||
import commands from '../commands/toolbar-commands';
|
||||
|
||||
interface Props {
|
||||
editor: Editor;
|
||||
@@ -21,6 +24,9 @@
|
||||
let currentNode: Node | null = $state(null);
|
||||
let currentNodePos: number = $state(-1);
|
||||
let open = $state(false);
|
||||
const turnIntoCommand = Object.values(commands)
|
||||
.flat()
|
||||
.filter((c) => c.turnInto !== undefined);
|
||||
|
||||
const pluginKey = 'globalDragHandle';
|
||||
|
||||
@@ -71,10 +77,39 @@
|
||||
const handleDelete = () => {
|
||||
editor.chain().setMeta('hideDragHandle', true).setNodeSelection(currentNodePos).deleteSelection().run();
|
||||
};
|
||||
|
||||
const handleAddNodeNext = () => {
|
||||
if (currentNodePos === -1) return;
|
||||
const currentNodeSize = currentNode?.nodeSize || 0;
|
||||
const insertPos = currentNodePos + currentNodeSize;
|
||||
const currentNodeIsEmptyParagraph =
|
||||
currentNode?.type.name === 'paragraph' && currentNode?.content?.size === 0;
|
||||
const focusPos = currentNodeIsEmptyParagraph ? currentNodePos + 2 : insertPos + 2;
|
||||
editor
|
||||
.chain()
|
||||
.command(({ dispatch, tr, state }) => {
|
||||
if (dispatch) {
|
||||
if (currentNodeIsEmptyParagraph) {
|
||||
tr.insertText('/', currentNodePos, currentNodePos + 1);
|
||||
} else {
|
||||
tr.insert(
|
||||
insertPos,
|
||||
state.schema.nodes.paragraph.create(null, [state.schema.text('/')])
|
||||
);
|
||||
}
|
||||
|
||||
return dispatch(tr);
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.focus(focusPos)
|
||||
.run();
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="drag-handle">
|
||||
<Button variant="ghost" class="ui:rounded-sm ui:p-0 !size-6" onclick={() => (open = true)}>
|
||||
<Button variant="ghost" class="!ui:size-6 ui:rounded-sm ui:p-0" onclick={() => (open = true)}>
|
||||
<GripVertical />
|
||||
</Button>
|
||||
<DropdownMenu.Root bind:open>
|
||||
@@ -82,10 +117,43 @@
|
||||
<span>Drag Handle</span>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.GroupHeading class="ui:text-muted-foreground ui:capitalize">
|
||||
{currentNode?.type.name}
|
||||
</DropdownMenu.GroupHeading>
|
||||
<DropdownMenu.Sub>
|
||||
<DropdownMenu.SubTrigger openDelay={300}>
|
||||
<Repeat2 />
|
||||
Turn Into
|
||||
</DropdownMenu.SubTrigger>
|
||||
<DropdownMenu.SubContent class="ui:max-h-96 ui:overflow-auto ui:duration-300">
|
||||
{#each turnIntoCommand as command (command)}
|
||||
{@const Icon = command.icon}
|
||||
<DropdownMenu.Item
|
||||
onclick={() => {
|
||||
if (currentNode && currentNodePos) command.turnInto?.(editor, currentNodePos);
|
||||
}}
|
||||
>
|
||||
<Icon />
|
||||
<span>{command.tooltip}</span>
|
||||
<DropdownMenu.Shortcut class="ui:bg-background ui:rounded ui:border ui:p-0.5"
|
||||
>{command.shortCut}</DropdownMenu.Shortcut
|
||||
>
|
||||
</DropdownMenu.Item>
|
||||
{/each}
|
||||
</DropdownMenu.SubContent>
|
||||
</DropdownMenu.Sub>
|
||||
</DropdownMenu.Group>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item onclick={handleAddNodeNext}>
|
||||
<Plus />
|
||||
Add Node
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={handleRemoveFormatting}>
|
||||
<RemoveFormatting />
|
||||
Remove Formatting
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item onclick={handleDuplicate}>
|
||||
<Duplicate />
|
||||
Duplicate Node
|
||||
@@ -94,6 +162,7 @@
|
||||
<Clipboard />
|
||||
Copy to clipboard
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item onclick={handleDelete}>
|
||||
<Delete class="ui:text-destructive" />
|
||||
Delete Node
|
||||
|
||||
@@ -106,7 +106,11 @@
|
||||
{:else}
|
||||
{@const commandGroup = commands[cmd]}
|
||||
{#each commandGroup as command (command)}
|
||||
<ToolBarIcon {editor} {command} />
|
||||
{#if command.name === 'paragraph'}
|
||||
<span></span>
|
||||
{:else}
|
||||
<ToolBarIcon {editor} {command} />
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
Reference in New Issue
Block a user