Skip to content

Instantly share code, notes, and snippets.

@Aymkdn
Created March 3, 2021 10:12
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aymkdn/9f993c5cfe8476f718c4fd2fd7bda1f0 to your computer and use it in GitHub Desktop.
Save Aymkdn/9f993c5cfe8476f718c4fd2fd7bda1f0 to your computer and use it in GitHub Desktop.
TipTap TextColor extension
// this is a simplified example using Vuetify v1 and TipTap v1
<template>
<div>
<editor-menu-bar :editor="editor" v-else>
<div class="menubar" slot-scope="{ commands, isActive }">
<v-tooltip top>
<button :class="{ 'menubar__button':true, 'is-active': isActive.bold() }" @click="commands.bold" slot="activator">
<v-icon>format_bold</v-icon>
</button>
<span>Bold</span>
</v-tooltip>
<v-tooltip top>
<button :class="{ 'menubar__button':true, 'is-active': isActive.italic() }" @click="commands.italic" slot="activator">
<v-icon>format_italic</v-icon>
</button>
<span>Italic</span>
</v-tooltip>
<v-tooltip top>
<v-menu slot="activator">
<button :class="{ 'menubar__button':true }" style="margin-top:-18px" slot="activator">
<v-icon>format_color_text</v-icon>
</button>
<v-list>
<v-list-tile :key="color" v-for="color in colors" @click="applyTextColor(commands, color)">
<v-list-tile-title>{{color}}</v-list-tile-title>
</v-list-tile>
</v-list>
</v-menu>
<span>Text Color</span>
</v-tooltip>
<v-tooltip top>
<button :class="{ 'menubar__button':true, 'is-active': isActive.bullet_list() }" @click="commands.bullet_list" slot="activator">
<v-icon>format_list_bulleted</v-icon>
</button>
<span>Bullet List</span>
</v-tooltip>
<v-tooltip top>
<button :class="{ 'menubar__button':true, 'is-active': isActive.ordered_list() }" @click="commands.ordered_list" slot="activator">
<v-icon>format_list_numbered</v-icon>
</button>
<span>Ordered List</span>
</v-tooltip>
<v-tooltip top>
<button :class="{ 'menubar__button':true, 'is-active': isActive.link() }" @click="commands.link" slot="activator">
<v-icon>link</v-icon>
</button>
<span>Link</span>
</v-tooltip>
<v-tooltip top>
<button class="menubar__button" @click="commands.undo" slot="activator">
<v-icon>undo</v-icon>
</button>
<span>Undo</span>
</v-tooltip>
<v-tooltip top>
<button class="menubar__button" @click="commands.redo" slot="activator">
<v-icon>redo</v-icon>
</button>
<span>Redo</span>
</v-tooltip>
</div>
</editor-menu-bar>
<editor-content :editor="editor" class="height-row-3" />
</div>
</template>
<script>
// Import the editor
import { Editor, EditorContent, EditorMenuBar } from 'tiptap'
import Vue from 'vue'
import {
Bold,
Italic,
OrderedList,
BulletList,
ListItem,
Link,
History
} from 'tiptap-extensions'
import TextColor from './tiptap-textcolor.js'
export default {
components: {
EditorContent,
EditorMenuBar
},
data() {
return {
editor: null,
}
},
computed:{
colors () {
return [
'black',
'green',
'red',
'blue',
'purple'
]
}
},
methods:{
applyTextColor (commands, color) {
commands.textcolor({ color: color });
}
},
mounted() {
this.editor = new Editor({
content: "",
disablePasteRules:true,
disableInputRules:true,
extensions:[
new Bold(),
new Italic(),
new TextColor(),
new OrderedList(),
new BulletList(),
new ListItem(),
new Link(),
new History()
]
})
},
beforeDestroy() {
this.editor.destroy()
}
}
</script>
<style>
.menubar {
-webkit-transition:visibility .2s .4s,opacity .2s .4s;
transition:visibility .2s .4s,opacity .2s .4s;
width: 90%;
border: 1px solid #CCC;
background-color: #EEE;
padding: 3px 0 0 5px;
}
.menubar.is-hidden {
visibility:hidden;
opacity:0
}
.menubar.is-focused {
visibility:visible;
opacity:1;
-webkit-transition:visibility .2s,opacity .2s;
transition:visibility .2s,opacity .2s
}
.menubar__button {
font-weight:700;
display:-webkit-inline-box;
display:-ms-inline-flexbox;
display:inline-flex;
background:rgba(0,0,0,0);
border:0;
color:#000;
padding:.2rem .5rem;
margin-right:.2rem;
border-radius:3px;
cursor:pointer
}
.menubar__button:hover {
background-color:rgba(0,0,0,.05)
}
.menubar__button.is-active {
background-color:rgba(0,0,0,.1)
}
/* make the area resizable */
.ProseMirror {
resize:vertical;
}
/* different height depending of the number of rows defined */
.height-row-1 > div[contenteditable] { height:35px }
.height-row-2 > div[contenteditable] { height:70px }
.height-row-3 > div[contenteditable] { height:105px }
.height-row-4 > div[contenteditable] { height:140px }
.height-row-5 > div[contenteditable] { height:175px }
.height-row-6 > div[contenteditable] { height:210px }
</style>
import { Mark } from 'tiptap'
import { updateMark, markInputRule, markPasteRule } from 'tiptap-commands'
export default class TextColor extends Mark {
get name() {
return 'textcolor'
}
get schema() {
return {
attrs: {
color: {
default: 'black'
}
},
parseDOM: [
{
tag: 'span',
getAttrs: dom => {
return {
color: dom.style.color
}
}
}
],
toDOM: (node) => {
return ['span', {
style: `color:${node.attrs.color}`
}, 0]
}
}
}
keys({ type }) {
return {
'Mod-c': updateMark(type),
}
}
commands({ type }) {
return attrs => updateMark(type, attrs);
}
inputRules({ type }) {
return [
markInputRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)$/, type),
]
}
pasteRules({ type }) {
return [
markPasteRule(/(?:\*\*|__)([^*_]+)(?:\*\*|__)/g, type),
]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment