Skip to content

Commit

Permalink
feat(extensions, i18n, icons): rewrite extensions for a new look, new…
Browse files Browse the repository at this point in the history
…s i18n for links, fix icons
  • Loading branch information
iliyaZelenko committed Oct 6, 2019
1 parent 7ac50f3 commit 42cdc13
Show file tree
Hide file tree
Showing 38 changed files with 467 additions and 289 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ WYSIWYG editor for Vuetify. Component simplifies integration [tiptap](https://gi

- used vuetify components
- support for different types of icons ([fa](https://fontawesome.com/), [md](https://material.io/tools/icons/), [mdi](https://materialdesignicons.com/))
- internationalization (2 languages: en, ru)
- internationalization (en, fr, pl, es, ru), with automatic detection of the current language through the Vuetify
- easy to start using
- props and events are available
- the project is ready to actively develop if there is support (stars)!
- TypeScript support
- the project is ready to actively develop if there is support (stars)!
- the ability to create and use your own extensions
- choose where the extension buttons should be displayed: in the toolbar or in the bubble menu

## Installation

Expand Down Expand Up @@ -354,4 +356,3 @@ In the future version this problem will most likely be solved and you will not n
- site with docs and examples
- emoticons
- tests
- choose where the extension buttons should be displayed: in the toolbar or in the bubble menu (it's done and ready to go to the new version)
8 changes: 6 additions & 2 deletions demo/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import router from './router'
import '../dist/main.css'
import { MAIN_MODULE } from './config'

const vuetify = new Vuetify()
const vuetify = new Vuetify({
lang: {
current: 'en' // en | es | fr | pl | ru
}
})

MAIN_MODULE.then(({ TiptapVuetifyPlugin }) => {
Vue.use(Router)
Expand All @@ -31,7 +35,7 @@ MAIN_MODULE.then(({ TiptapVuetifyPlugin }) => {
})
Vue.use(TiptapVuetifyPlugin, {
vuetify,
iconsGroup: 'fa'
iconsGroup: 'fa' // VuetifyIconsGroups (fa, md, mdi)
})

Vue.config.productionTip = false
Expand Down
32 changes: 27 additions & 5 deletions demo/pages/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,43 @@ export default {
`
}),
async created () {
const { Heading, Bold, Italic, Strike, Underline, Code, CodeBlock, Paragraph, BulletList, OrderedList, ListItem,
const {
Heading, Bold, Italic, Strike, Underline, Code, CodeBlock, Paragraph, BulletList, OrderedList, ListItem,
Link, Blockquote, HardBreak, HorizontalRule, History
} = await MAIN_MODULE
this.extensions = [
// опции которые попадают в расширение tiptap
[Blockquote, {
renderIn: 'bubbleMenu',
nativeOptions: {
Code,
CodeBlock,
HorizontalRule,
Paragraph,
[History, {
// если не нужны кнокпи
options: { noActions: true }
}],
HardBreak, // позволяет переносить через Shift + Ctrl + Enter
Underline,
Strike,
Italic,
ListItem, // если нужно использовать список (BulletList, OrderedList)
BulletList,
OrderedList,
[Heading, {
// Опции которые попадают в расширение tiptap
options: {
levels: [1, 2, 3]
}
}],
// но опции не обязательно указывать если нужно чтобы renderIn: 'toolbar', это по умолчанию.
[Bold, {
renderIn: 'toolbar'
}],
[Blockquote, {
renderIn: 'bubbleMenu',
options: {
levels: [1, 2, 3]
}
}],
[Link, {
renderIn: 'bubbleMenu'
}]
Expand Down
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ async function getConfig ({
}
}),
commonjs(),
// TODO autoprefixer
// TODO autoprefixer (update: разве в postcssPresetEnv его нет?)
postcss({
// TODO для каждого конфига генерируется свой main.css (одинаковый файл), исправить
extract: join(distDir, 'main.css'),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
<template>
<div>
<span
v-for="(action, i) in $props[PROPS.ACTIONS]"
:key="'actions-' + i"
>
<template v-for="(action, i) in $props[PROPS.ACTIONS]">
<action-btn
v-if="isBtn(action)"
:key="'action-button-' + i"
:options="action.render.options"
:context="$props[PROPS.CONTEXT]"
:editor="$props[PROPS.EDITOR]"
:dark="$props[PROPS.DARK]"
/>
</span>
</template>
</div>
</template>

Expand All @@ -35,7 +33,7 @@ export const PROPS = {
'action-btn': ExtensionActionRenderBtnComponent
}
})
export default class ActionsBtnsRender extends Vue {
export default class ActionsRender extends Vue {
@Prop({ type: Object, required: true })
readonly [PROPS.EDITOR]: Editor
Expand Down
6 changes: 3 additions & 3 deletions src/components/Bubble.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
</v-btn>
-->

<actions-btns-render
<actions-render
:actions="actions"
:context="context"
:editor="editor"
Expand All @@ -95,12 +95,12 @@ import { Editor, EditorMenuBubble } from 'tiptap'
// import { icons } from '~/extensions/nativeExtensions/link/Link'
import I18nMixin from '~/mixins/I18nMixin'
import ExtensionActionInterface from '~/extensions/actions/ExtensionActionInterface'
import ActionsBtnsRender from '~/components/ActionsBtnsRender.vue'
import ActionsRender from '~/components/ActionsRender.vue'
import { VCard } from 'vuetify/lib'
@Component({
components: {
ActionsBtnsRender,
ActionsRender,
EditorMenuBubble,
VCard
}
Expand Down
47 changes: 35 additions & 12 deletions src/components/TiptapVuetify.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,33 +136,56 @@ export default class TiptapVuetify extends Vue {
mounted () {
const nativeExtensionsInstances: any = []
// опции расширений по умолчанию
const paramsDefault = {
renderIn: ExtensionActionRenderInEnum.toolbar,
options: {}
}
this[PROPS.EXTENSIONS].forEach(([ExtensionClass, options]) => {
const extension: AbstractExtension = new ExtensionClass(options.nativeOptions)
const renderInVariants = Object.values(ExtensionActionRenderInEnum)
if (!renderInVariants.includes(options.renderIn)) {
throw new Error('Please, set the "renderIn" option to one of following values: ' + renderInVariants)
this[PROPS.EXTENSIONS].forEach(extensionDefinition => {
let ExtensionClass
let params
// Получение расширения и его опций
if (Array.isArray(extensionDefinition)) {
([ExtensionClass, params] = extensionDefinition)
} else if (extensionDefinition.prototype instanceof AbstractExtension) { // Если extends от AbstractExtension
ExtensionClass = extensionDefinition
} else {
throw new Error('Incorrect extension declaration passed to "extensions" prop (array). ' +
'It looks like the array\'s element is in the wrong format.')
}
this.availableActions[options.renderIn].push(...extension.availableActions)
// параметры с дефолтными значениями TODO deep merge
const paramsFinal = { ...paramsDefault, ...params }
const extension: AbstractExtension = new ExtensionClass(paramsFinal.options)
// const renderInVariants = Object.values(ExtensionActionRenderInEnum)
//
// if (!renderInVariants.includes(options.renderIn)) {
// throw new Error('Please, set the "renderIn" option to one of following values: ' + renderInVariants)
// }
// пополнение доступных действий для конкретного renderIn
this.availableActions[paramsFinal.renderIn].push(...extension.availableActions)
// Сбор нативных расширений
if (extension.nativeExtensionInstance) {
nativeExtensionsInstances.push(extension.nativeExtensionInstance)
}
})
const extensions = [
...this[PROPS.NATIVE_EXTENSIONS],
...nativeExtensionsInstances,
...nativeExtensionsInstances
]
// TODO только если есть prop placeholder
if (this[PROPS.PLACEHOLDER]) {
// !!!!!!!!!!!!!!!!! TODO ONLY FOR TEST (update: не помню что это, возможно и не нужно убирать код ниже)
new Placeholder({
extensions.push(new Placeholder({
emptyNodeClass: 'tiptap-vuetify-editor__paragraph--is-empty',
emptyNodeText: this[PROPS.PLACEHOLDER],
showOnlyWhenEditable: true
})
]
}))
}
this.editor = new Editor({
extensions,
Expand Down
6 changes: 3 additions & 3 deletions src/components/Toolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
...toolbarAttributes
}"
>
<actions-btns-render
<actions-render
:actions="actions"
:context="menuBarContext"
:editor="editor"
Expand All @@ -35,12 +35,12 @@ import { Editor, EditorMenuBar } from 'tiptap'
import toolbarConfig from '~/configs/toolbar'
import ExtensionActionInterface from '~/extensions/actions/ExtensionActionInterface'
import ExtensionActionRenderBtn from '~/extensions/actions/renders/btn/ExtensionActionRenderBtn.ts'
import ActionsBtnsRender from '~/components/ActionsBtnsRender.vue'
import ActionsRender from '~/components/ActionsRender.vue'
import { VToolbar } from 'vuetify/lib'
@Component({
components: {
ActionsBtnsRender,
ActionsRender,
EditorMenuBar,
VToolbar
}
Expand Down
6 changes: 2 additions & 4 deletions src/configs/theme.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
export const enum VuetifyIconsGropus {
export const enum VuetifyIconsGroups {
// default icons in vuetify (official material design icons)
md = 'md',
mdi = 'mdi',
fa = 'fa'
}

export default {
defaultIconsGroup: VuetifyIconsGropus.md
defaultIconsGroup: VuetifyIconsGroups.md
}

export const faIconsSize = 'fa-sm'
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ export default class ExtensionActionRenderBtn {

this.options = {
onClick ({ context }) {
context.commands[nativeExtensionName]()
context.commands[nativeExtensionName](options.onClickOptions)
},
isActive ({ isActive }) {
return !!isActive[nativeExtensionName] && isActive[nativeExtensionName]()
return !!isActive[nativeExtensionName] && isActive[nativeExtensionName](options.isActiveOptions)
},
...options
}
Expand Down
15 changes: 13 additions & 2 deletions src/extensions/actions/renders/btn/ExtensionActionRenderBtn.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@
<template #activator="{ on }">
<!--TODO options.isActive сделать реактивным -->
<v-btn
:class="{ 'v-btn--active': $props[PROPS.OPTIONS].isActive($props[PROPS.CONTEXT]) }"
:class="{
'tiptap-vuetify-editor__action-render-btn': true,
'v-btn--active': $props[PROPS.OPTIONS].isActive($props[PROPS.CONTEXT])
}"
:dark="$props[PROPS.DARK]"
small
icon
v-on="on"
@click="options.onClick({ context: $props[PROPS.CONTEXT], editor: $props[PROPS.EDITOR] })"
>
<component
class="tiptap-vuetify-editor__btn-icon"
:is="isTextIcon ? 'b' : isVuetifyIcon ? 'v-icon' : null"
x-small
>
{{ buttonIcon }}
</component>
Expand Down Expand Up @@ -82,3 +85,11 @@ export default class ExtensionActionRenderBtn extends Vue {
}
}
</script>

<style lang="stylus">
.tiptap-vuetify-editor__action-render-btn
margin: 0 6px
.tiptap-vuetify-editor__btn-icon.v-icon.fas
font-size: 16px
</style>
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import I18nText from '~/i18n/I18nText'
import { VuetifyIconsGropus } from '~/configs/theme'
import { VuetifyIconsGroups } from '~/configs/theme'
import IconInterface from '~/extensions/nativeExtensions/icons/IconInterface'

export default interface ExtensionActionRenderBtnOptionsInterface {
tooltip: I18nText | ((context, options) => I18nText)
icons: {
[VuetifyIconsGropus.md]: IconInterface
[VuetifyIconsGropus.fa]: IconInterface
[VuetifyIconsGropus.mdi]: IconInterface
[VuetifyIconsGroups.md]: IconInterface
[VuetifyIconsGroups.fa]: IconInterface
[VuetifyIconsGroups.mdi]: IconInterface
}
onClick: ({ context, editor }) => any
onClickOptions?: { [key: string]: any }
isActive: (...arg: any) => boolean
isActiveOptions?: { [key: string]: any }
nativeExtensionName?: string
}
8 changes: 4 additions & 4 deletions src/extensions/nativeExtensions/Blockquote.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Blockquote as BlockquoteOriginal } from 'tiptap-extensions'
import { faIconsSize, VuetifyIconsGropus } from '~/configs/theme'
import { VuetifyIconsGroups } from '~/configs/theme'
import VuetifyIcon from '~/extensions/nativeExtensions/icons/VuetifyIcon'
import I18nText from '~/i18n/I18nText'
import AbstractExtension from '~/extensions/AbstractExtension'
Expand All @@ -17,9 +17,9 @@ export default class Blockquote extends AbstractExtension {
render: new ExtensionActionRenderBtn({
tooltip: new I18nText('extensions.Blockquote.buttons.blockquote.tooltip'),
icons: {
[VuetifyIconsGropus.md]: new VuetifyIcon('format_quote'),
[VuetifyIconsGropus.fa]: new VuetifyIcon('fas fa-quote-right ' + faIconsSize),
[VuetifyIconsGropus.mdi]: new VuetifyIcon('mdi-format-quote-close')
[VuetifyIconsGroups.md]: new VuetifyIcon('format_quote'),
[VuetifyIconsGroups.fa]: new VuetifyIcon('fas fa-quote-right'),
[VuetifyIconsGroups.mdi]: new VuetifyIcon('mdi-format-quote-close')
},
nativeExtensionName: 'blockquote'
})
Expand Down
8 changes: 4 additions & 4 deletions src/extensions/nativeExtensions/Bold.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Bold as BoldOriginal } from 'tiptap-extensions'
import { faIconsSize, VuetifyIconsGropus } from '~/configs/theme'
import { VuetifyIconsGroups } from '~/configs/theme'
import VuetifyIcon from '~/extensions/nativeExtensions/icons/VuetifyIcon'
import I18nText from '~/i18n/I18nText'
import AbstractExtension from '~/extensions/AbstractExtension'
Expand All @@ -17,9 +17,9 @@ export default class Bold extends AbstractExtension {
render: new ExtensionActionRenderBtn({
tooltip: new I18nText('extensions.Bold.buttons.bold.tooltip'),
icons: {
[VuetifyIconsGropus.md]: new VuetifyIcon('format_bold'),
[VuetifyIconsGropus.fa]: new VuetifyIcon('fas fa-bold ' + faIconsSize),
[VuetifyIconsGropus.mdi]: new VuetifyIcon('mdi-format-bold')
[VuetifyIconsGroups.md]: new VuetifyIcon('format_bold'),
[VuetifyIconsGroups.fa]: new VuetifyIcon('fas fa-bold'),
[VuetifyIconsGroups.mdi]: new VuetifyIcon('mdi-format-bold')
},
nativeExtensionName: 'bold'
})
Expand Down
Loading

0 comments on commit 42cdc13

Please sign in to comment.