From 996a5fd9892da7e90ce72ac35a5bb8676bdf88a3 Mon Sep 17 00:00:00 2001 From: sharevb Date: Sat, 28 Sep 2024 11:22:56 +0200 Subject: [PATCH] feat(Html WYSYWIG): add colors and tables Fix #796 --- .../html-wysiwyg-editor/editor/editor.vue | 22 ++- .../html-wysiwyg-editor/editor/menu-bar.vue | 163 +++++++++++++++++- 2 files changed, 181 insertions(+), 4 deletions(-) diff --git a/src/tools/html-wysiwyg-editor/editor/editor.vue b/src/tools/html-wysiwyg-editor/editor/editor.vue index 86bdebbc1..eb64246b4 100644 --- a/src/tools/html-wysiwyg-editor/editor/editor.vue +++ b/src/tools/html-wysiwyg-editor/editor/editor.vue @@ -3,6 +3,14 @@ import { tryOnBeforeUnmount, useVModel } from '@vueuse/core'; import { Editor, EditorContent } from '@tiptap/vue-3'; import StarterKit from '@tiptap/starter-kit'; import { useThemeVars } from 'naive-ui'; +import { Color } from '@tiptap/extension-color'; +import TextStyle from '@tiptap/extension-text-style'; +import Highlight from '@tiptap/extension-highlight'; +import Gapcursor from '@tiptap/extension-gapcursor'; +import Table from '@tiptap/extension-table'; +import TableCell from '@tiptap/extension-table-cell'; +import TableHeader from '@tiptap/extension-table-header'; +import TableRow from '@tiptap/extension-table-row'; import MenuBar from './menu-bar.vue'; const props = defineProps<{ html: string }>(); @@ -12,7 +20,19 @@ const html = useVModel(props, 'html', emit); const editor = new Editor({ content: html.value, - extensions: [StarterKit], + extensions: [ + StarterKit, + TextStyle, + Color, + Highlight.configure({ multicolor: true }), + Gapcursor, + Table.configure({ + resizable: true, + }), + TableRow, + TableHeader, + TableCell, + ], }); editor.on('update', ({ editor }) => emit('update:html', editor.getHTML())); diff --git a/src/tools/html-wysiwyg-editor/editor/menu-bar.vue b/src/tools/html-wysiwyg-editor/editor/menu-bar.vue index d3ad31686..129800dad 100644 --- a/src/tools/html-wysiwyg-editor/editor/menu-bar.vue +++ b/src/tools/html-wysiwyg-editor/editor/menu-bar.vue @@ -8,15 +8,25 @@ import { ClearFormatting, Code, CodePlus, + ColorPicker, + ColumnInsertLeft, + ColumnInsertRight, + Cross, H1, H2, H3, H4, + Heading, Italic, + LayersIntersect2, + LayersUnion, + LayoutDistributeHorizontal, + LayoutDistributeVertical, List, ListNumbers, - Strikethrough, - TextWrap, + RowInsertBottom, + RowInsertTop, + SeparatorVertical, Strikethrough, Table, TableOff, TextWrap, Tool, } from '@vicons/tabler'; import type { Component } from 'vue'; import MenuBarItem from './menu-bar-item.vue'; @@ -29,9 +39,16 @@ type MenuItem = icon: Component title: string action: () => void + value?: () => string isActive?: () => boolean type: 'button' } + | { icon: Component + title: string + action: (color: string) => void + value: () => string + type: 'color' + } | { type: 'divider' }; const items: MenuItem[] = [ @@ -141,7 +158,42 @@ const items: MenuItem[] = [ title: 'Clear format', action: () => editor.value.chain().focus().clearNodes().unsetAllMarks().run(), }, - + { + type: 'divider', + }, + { + type: 'color', + title: 'Forecolor', + icon: ColorPicker, + action: color => editor.value.chain().focus().setColor(color).run(), + value: () => editor.value.getAttributes('textStyle').color, + }, + { + type: 'button', + icon: ClearFormatting, + title: 'Clear Forecolor', + action: () => editor.value.chain().focus().unsetColor().run(), + }, + { + type: 'divider', + }, + { + type: 'color', + title: 'Highlight color', + icon: ColorPicker, + action: color => editor.value.chain().focus().setHighlight({ color }), + value: () => '#FAF594', + }, + { + type: 'button', + icon: ClearFormatting, + title: 'Clear Highlight', + action: () => editor.value.chain().focus().unsetHighlight().run(), + isActive: () => editor.value.isActive('highlight'), + }, + { + type: 'divider', + }, { type: 'button', icon: ArrowBack, @@ -154,6 +206,99 @@ const items: MenuItem[] = [ title: 'Redo', action: () => editor.value.chain().focus().redo().run(), }, + { + type: 'divider', + }, + { + type: 'button', + action: () => editor.value.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }), + title: 'Insert table', + icon: Table, + }, + { + type: 'button', + action: () => editor.value.chain().focus().addColumnBefore(), + title: 'Add column before', + icon: ColumnInsertLeft, + }, + { + type: 'button', + action: () => editor.value.chain().focus().addColumnAfter(), + title: 'Add column after', + icon: ColumnInsertRight, + }, + { + type: 'button', + action: () => editor.value.chain().focus().deleteColumn(), + title: 'Delete column', + icon: Cross, + }, + { + type: 'button', + action: () => editor.value.chain().focus().addRowBefore(), + title: 'Add row before', + icon: RowInsertTop, + }, + { + type: 'button', + action: () => editor.value.chain().focus().addRowAfter(), + title: 'Add row after', + icon: RowInsertBottom, + }, + { + type: 'button', + action: () => editor.value.chain().focus().deleteRow(), + title: 'Delete row', + icon: Cross, + }, + { + type: 'button', + action: () => editor.value.chain().focus().deleteTable(), + title: 'Delete table', + icon: TableOff, + }, + { + type: 'button', + action: () => editor.value.chain().focus().mergeCells(), + title: 'Merge cells', + icon: LayersUnion, + }, + { + type: 'button', + action: () => editor.value.chain().focus().splitCell(), + title: 'Split cell', + icon: SeparatorVertical, + }, + { + type: 'button', + action: () => editor.value.chain().focus().toggleHeaderColumn(), + title: 'Toggle header column', + icon: LayoutDistributeVertical, + }, + { + type: 'button', + action: () => editor.value.chain().focus().toggleHeaderRow(), + title: 'Toggle header row', + icon: LayoutDistributeHorizontal, + }, + { + type: 'button', + action: () => editor.value.chain().focus().toggleHeaderCell(), + title: 'Toggle header cell', + icon: Heading, + }, + { + type: 'button', + action: () => editor.value.chain().focus().mergeOrSplit(), + title: 'Merge or split', + icon: LayersIntersect2, + }, + { + type: 'button', + action: () => editor.value.chain().focus().fixTables(), + title: 'Fix tables', + icon: Tool, + }, ]; @@ -162,6 +307,18 @@ const items: MenuItem[] = [