trying to extend that editor
This commit is contained in:
parent
936ada94bd
commit
a33363eef0
4 changed files with 152 additions and 9 deletions
|
@ -1,15 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<editor-menu-bar :editor="editor" v-slot="{ commands, isActive, focused }">
|
<editor-menu-bar :editor="editor" v-slot="{ commands, isActive, focused }">
|
||||||
<div class="menu-bar" :class="{ active: focused }">
|
<div class="menu-bar" :class="{ active: focused }">
|
||||||
<button class="editor-button-bold" :class="{ active: isActive.bold() }" @click="commands.bold" />
|
<button class="editor-button-bold" :class="{ active: active.bold }" @click="menuAction('bold', commands.bold, isActive)" />
|
||||||
<button class="editor-button-italic" :class="{ active: isActive.italic() }" @click="commands.italic" />
|
<button class="editor-button-italic" :class="{ active: active.italic }" @click="menuAction('italic', commands.italic, isActive)" />
|
||||||
|
|
||||||
<button class="editor-button-paragraph" :class="{ active: isActive.paragraph() }" @click="commands.paragraph" />
|
<button class="editor-button-paragraph" :class="{ active: active.paragraph }" @click="menuAction('paragraph', commands.paragraph, isActive)" />
|
||||||
<button class="editor-button-heading2" :class="{ active: isActive.heading({ level: 2 }) }" @click="commands.heading({ level: 2})" />
|
<button class="editor-button-heading2" :class="{ active: active.heading2 }" @click="menuAction('heading2', commands.heading({ level: 2}), isActive)" />
|
||||||
<button class="editor-button-heading3" :class="{ active: isActive.heading({ level: 3 }) }" @click="commands.heading({ level: 3})" />
|
<button class="editor-button-heading3" :class="{ active: active.heading3 }" @click="menuAction('heading3', commands.heading({ level: 3}), isActive)" />
|
||||||
|
|
||||||
<button class="editor-button-bullet-list" :class="{ active: isActive.bullet_list() }" @click="commands.bullet_list" />
|
<button class="editor-button-bullet-list" :class="{ active: active.bullet_list }" @click="menuAction('bullet_list', commands.bullet_list, isActive)" />
|
||||||
<button class="editor-button-horizontal-rule" :class="{ active: isActive.horizontal_rule() }" @click="commands.horizontal_rule" />
|
<button class="editor-button-horizontal-rule" :class="{ active: active.horizontal_rule }" @click="menuAction('horizontal_rule', commands.horizontal_rule, isActive)" />
|
||||||
|
|
||||||
|
<button class="editor-button-stat-block" :class="{ active: active.stat_block }" @click="menuAction('stat_block', commands.stat_block, isActive)" />
|
||||||
</div>
|
</div>
|
||||||
</editor-menu-bar>
|
</editor-menu-bar>
|
||||||
</template>
|
</template>
|
||||||
|
@ -23,6 +25,26 @@ import { Editor, EditorMenuBar } from 'tiptap'
|
||||||
})
|
})
|
||||||
export default class DeckCardEditorMenu extends Vue {
|
export default class DeckCardEditorMenu extends Vue {
|
||||||
@Prop() public readonly editor!: Editor
|
@Prop() public readonly editor!: Editor
|
||||||
|
|
||||||
|
private active: {[key: string]: boolean} = {
|
||||||
|
bold: false,
|
||||||
|
italic: false,
|
||||||
|
|
||||||
|
paragraph: false,
|
||||||
|
heading2: false,
|
||||||
|
heading3: false,
|
||||||
|
|
||||||
|
bulletList: false,
|
||||||
|
horizontalLule: false
|
||||||
|
}
|
||||||
|
|
||||||
|
private menuAction (name: string, command: () => void, isActive: {[key: string]: () => boolean}) {
|
||||||
|
command()
|
||||||
|
|
||||||
|
Object.keys(this.active).forEach(action => {
|
||||||
|
this.active[action] = isActive[action]()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -63,6 +85,9 @@ export default class DeckCardEditorMenu extends Vue {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
.menu-bar > button.active {
|
||||||
|
background-color: #FF0;
|
||||||
|
}
|
||||||
.editor-button-bold { background-image: url(../assets/zondicons/format-bold.svg); }
|
.editor-button-bold { background-image: url(../assets/zondicons/format-bold.svg); }
|
||||||
.editor-button-italic { background-image: url(../assets/zondicons/format-italic.svg); }
|
.editor-button-italic { background-image: url(../assets/zondicons/format-italic.svg); }
|
||||||
.editor-button-bullet-list { background-image: url(../assets/zondicons/list-bullet.svg); }
|
.editor-button-bullet-list { background-image: url(../assets/zondicons/list-bullet.svg); }
|
||||||
|
@ -71,4 +96,6 @@ export default class DeckCardEditorMenu extends Vue {
|
||||||
.editor-button-heading3:after { content: 'H3'; }
|
.editor-button-heading3:after { content: 'H3'; }
|
||||||
.editor-button-paragraph:after { content: 'P'; }
|
.editor-button-paragraph:after { content: 'P'; }
|
||||||
.editor-button-horizontal-rule:after { content: '—'; }
|
.editor-button-horizontal-rule:after { content: '—'; }
|
||||||
|
|
||||||
|
.editor-button-stat-block:after { content: 'ST'; }
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -34,7 +34,20 @@
|
||||||
import { Component, Prop, Vue } from 'vue-property-decorator'
|
import { Component, Prop, Vue } from 'vue-property-decorator'
|
||||||
import { cardWHtoStyle, iconPath } from '@/lib'
|
import { cardWHtoStyle, iconPath } from '@/lib'
|
||||||
import { Editor, EditorContent } from 'tiptap'
|
import { Editor, EditorContent } from 'tiptap'
|
||||||
import { Heading, Bold, Italic, HorizontalRule, BulletList, ListItem, History } from 'tiptap-extensions'
|
import {
|
||||||
|
Heading,
|
||||||
|
Bold,
|
||||||
|
Italic,
|
||||||
|
HorizontalRule,
|
||||||
|
BulletList,
|
||||||
|
ListItem,
|
||||||
|
History,
|
||||||
|
Table,
|
||||||
|
TableCell,
|
||||||
|
TableRow,
|
||||||
|
TableHeader
|
||||||
|
} from 'tiptap-extensions'
|
||||||
|
import StatBlock from '@/editor/stat-block.js'
|
||||||
import DeckCardEditorMenu from '@/components/deck-card-editor-menu.vue'
|
import DeckCardEditorMenu from '@/components/deck-card-editor-menu.vue'
|
||||||
|
|
||||||
interface EditorContext {
|
interface EditorContext {
|
||||||
|
@ -51,7 +64,8 @@ const extensions = [
|
||||||
new HorizontalRule(),
|
new HorizontalRule(),
|
||||||
new BulletList(),
|
new BulletList(),
|
||||||
new ListItem(),
|
new ListItem(),
|
||||||
new History()
|
new History(),
|
||||||
|
new StatBlock()
|
||||||
]
|
]
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
53
src/editor/stat-block.js
Normal file
53
src/editor/stat-block.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import { Node } from 'tiptap'
|
||||||
|
import { tableNodes, tableEditing, goToNextCell, deleteTable } from 'prosemirror-tables'
|
||||||
|
import { createTable } from 'prosemirror-utils'
|
||||||
|
import { TextSelection } from 'prosemirror-state'
|
||||||
|
|
||||||
|
export default class StatBlock extends Node {
|
||||||
|
get name () {
|
||||||
|
return 'stat_block'
|
||||||
|
}
|
||||||
|
|
||||||
|
get defaultOptions () {
|
||||||
|
return {
|
||||||
|
resizable: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get schema () {
|
||||||
|
return {
|
||||||
|
group: 'block',
|
||||||
|
content: 'stat_column+',
|
||||||
|
toDOM: () => ['ol', { 'data-type': this.name }, 0],
|
||||||
|
parseDOM: [{
|
||||||
|
priority: 51,
|
||||||
|
tag: `[data-type="${this.name}"]`
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commands ({ schema }) {
|
||||||
|
return () => (state, dispatch) => {
|
||||||
|
const offset = state.tr.selection.anchor + 1
|
||||||
|
|
||||||
|
const nodes = createTable(schema, 2, 6, true)
|
||||||
|
const tr = state.tr.replaceSelectionWith(nodes).scrollIntoView()
|
||||||
|
const resolvedPos = tr.doc.resolve(offset)
|
||||||
|
|
||||||
|
tr.setSelection(TextSelection.near(resolvedPos))
|
||||||
|
|
||||||
|
dispatch(tr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys () {
|
||||||
|
return {
|
||||||
|
Tab: goToNextCell(1),
|
||||||
|
'Shift-Tab': goToNextCell(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get plugins () {
|
||||||
|
return [tableEditing()]
|
||||||
|
}
|
||||||
|
}
|
49
src/editor/stat-block.ts
Normal file
49
src/editor/stat-block.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import { Node } from 'tiptap'
|
||||||
|
import { tableEditing, goToNextCell, deleteTable } from 'prosemirror-tables'
|
||||||
|
import { createTable } from 'prosemirror-utils'
|
||||||
|
import { TextSelection } from 'prosemirror-state'
|
||||||
|
import { TableNodes } from 'tiptap-extensions'
|
||||||
|
|
||||||
|
export default class StatBlock extends Node {
|
||||||
|
public get name () {
|
||||||
|
return 'stat_block'
|
||||||
|
}
|
||||||
|
|
||||||
|
public get defaultOptions () {
|
||||||
|
return {
|
||||||
|
resizable: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get schema () {
|
||||||
|
return TableNodes.table
|
||||||
|
}
|
||||||
|
|
||||||
|
public commands ({ schema }) {
|
||||||
|
return {
|
||||||
|
createStatBlock: () => (state, dispatch) => {
|
||||||
|
const offset = state.tr.selection.anchor + 1
|
||||||
|
|
||||||
|
const nodes = createTable(schema, 2, 6, true)
|
||||||
|
const tr = state.tr.replaceSelectionWith(nodes).scrollIntoView()
|
||||||
|
const resolvedPos = tr.doc.resolve(offset)
|
||||||
|
|
||||||
|
tr.setSelection(TextSelection.near(resolvedPos))
|
||||||
|
|
||||||
|
dispatch(tr)
|
||||||
|
},
|
||||||
|
deleteTable: () => deleteTable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public keys () {
|
||||||
|
return {
|
||||||
|
Tab: goToNextCell(1),
|
||||||
|
'Shift-Tab': goToNextCell(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get plugins () {
|
||||||
|
return [tableEditing()]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue