Skip to content

Commit

Permalink
feat(images): image extensions
Browse files Browse the repository at this point in the history
support for adding images (Image extension from tiptap)

re #16
  • Loading branch information
iliyaZelenko committed Nov 3, 2019
1 parent f15d554 commit e464b2b
Show file tree
Hide file tree
Showing 11 changed files with 417 additions and 10 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,14 +199,15 @@ You can use the necessary extensions. The corresponding buttons are added automa

How to import and use them can be seen in the example above.

Available extensions:
Available extensions (native tiptap extensions from `tiptap-extensions` package):

- `Bold`
- `Italic`
- `Strike`
- `Underline`
- `Code`
- `CodeBlock`
- `Image`
- `Paragraph`
- `BulletList`
- `OrderedList`
Expand Down Expand Up @@ -362,7 +363,7 @@ You can add content after the toolbar.

## TODO

- images uploading (free hosting by default) [Relevant issue.](https://github.com/iliyaZelenko/tiptap-vuetify/issues/16) Ability to choose your uploading strategy.
- better images support: uploading (free hosting by default) [Relevant issue.](https://github.com/iliyaZelenko/tiptap-vuetify/issues/16) Ability to choose your uploading strategy. [Resize](https://github.com/scrumpy/tiptap/issues/333) image and change other params.
- site with full-docs and examples
- emoticons
- tests
Expand Down
2 changes: 1 addition & 1 deletion demo/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { MAIN_MODULE } from './config'

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

Expand Down
3 changes: 2 additions & 1 deletion demo/pages/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default {
async created () {
const {
Heading, Bold, Italic, Strike, Underline, Code, CodeBlock, Paragraph, BulletList, OrderedList, ListItem,
Link, Blockquote, HardBreak, HorizontalRule, History
Link, Blockquote, HardBreak, HorizontalRule, History, Image
} = await MAIN_MODULE
this.extensions = [
Expand All @@ -52,6 +52,7 @@ export default {
ListItem, // если нужно использовать список (BulletList, OrderedList)
BulletList,
OrderedList,
Image,
[Heading, {
// Опции которые попадают в расширение tiptap
options: {
Expand Down
72 changes: 72 additions & 0 deletions src/extensions/nativeExtensions/image/Image.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Image as ImageOriginal } from 'tiptap-extensions'
import { VuetifyIconsGroups } from '~/configs/theme'
import VuetifyIcon from '~/extensions/nativeExtensions/icons/VuetifyIcon'
import I18nText from '~/i18n/I18nText'
import AbstractExtension from '~/extensions/AbstractExtension'
import ExtensionActionInterface from '~/extensions/actions/ExtensionActionInterface'
import Vue from 'vue'
import ExtensionActionRenderBtn from '~/extensions/actions/renders/btn/ExtensionActionRenderBtn.ts'

export default class Image extends AbstractExtension {
constructor (options) {
super(options, ImageOriginal)
}

get availableActions (): ExtensionActionInterface[] {
const nativeExtensionName = 'image'

return [
{
render: new ExtensionActionRenderBtn({
tooltip: new I18nText('extensions.Image.buttons.tooltip'),
icons: {
[VuetifyIconsGroups.md]: new VuetifyIcon('image'),
[VuetifyIconsGroups.fa]: new VuetifyIcon('fas fa-image'),
[VuetifyIconsGroups.mdi]: new VuetifyIcon('mdi-image'),
[VuetifyIconsGroups.mdiSvg]: new VuetifyIcon('M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5A2,2 0 0,0 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19Z')
},
nativeExtensionName,
async onClick ({ context, editor }) {
const ImageWindow = (await import('~/extensions/nativeExtensions/image/ImageWindow.vue')).default
const LinkWindowComponent = Vue.extend(ImageWindow)
const instance = new LinkWindowComponent({
vuetify: Vue.prototype.tiptapVuetifyPlugin.vuetify,
propsData: {
value: true,
nativeExtensionName,
context,
editor
}
})

instance.$mount()
document.querySelector('body')!.appendChild(instance.$el)
}
})
}
]
}
}

// export const icons = {
// save: {
// [VuetifyIconsGroups.md]: new VuetifyIcon('check'),
// [VuetifyIconsGroups.fa]: new VuetifyIcon('fas fa-check'),
// [VuetifyIconsGroups.mdi]: new VuetifyIcon('mdi-check')
// },
// cancel: {
// [VuetifyIconsGroups.md]: new VuetifyIcon('link_off'),
// [VuetifyIconsGroups.fa]: new VuetifyIcon('fas fa-unlink'),
// [VuetifyIconsGroups.mdi]: new VuetifyIcon('mdi-link-off')
// },
// linkUpdate: {
// [VuetifyIconsGroups.md]: new VuetifyIcon('link'),
// [VuetifyIconsGroups.fa]: new VuetifyIcon('fas fas fa-link'),
// [VuetifyIconsGroups.mdi]: new VuetifyIcon('mdi-link')
// },
// linkAdd: {
// [VuetifyIconsGroups.md]: new VuetifyIcon('link'),
// [VuetifyIconsGroups.fa]: new VuetifyIcon('fas fa-link'),
// [VuetifyIconsGroups.mdi]: new VuetifyIcon('mdi-link-plus')
// }
// }
106 changes: 106 additions & 0 deletions src/extensions/nativeExtensions/image/ImageUploadArea.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<template>
<div class="tiptap-vuetify-image-upload-area">
<input
id="tiptap-vuetify-image-upload-area__input-file"
type="file"
accept="image/*"
multiple
>

<label
class="tiptap-vuetify-image-upload-area-holder"
for="tiptap-vuetify-image-upload-area__input-file"
>
<div>
<svg
class="tiptap-vuetify-image-upload-area-holder__icon"
xmlns="http://www.w3.org/2000/svg"
width="50"
height="43"
viewBox="0 0 50 43"
>
<path d="M48.4 26.5c-.9 0-1.7.7-1.7 1.7v11.6h-43.3v-11.6c0-.9-.7-1.7-1.7-1.7s-1.7.7-1.7 1.7v13.2c0 .9.7 1.7 1.7 1.7h46.7c.9 0 1.7-.7 1.7-1.7v-13.2c0-1-.7-1.7-1.7-1.7zm-24.5 6.1c.3.3.8.5 1.2.5.4 0 .9-.2 1.2-.5l10-11.6c.7-.7.7-1.7 0-2.4s-1.7-.7-2.4 0l-7.1 8.3v-25.3c0-.9-.7-1.7-1.7-1.7s-1.7.7-1.7 1.7v25.3l-7.1-8.3c-.7-.7-1.7-.7-2.4 0s-.7 1.7 0 2.4l10 11.6z"/>
</svg>
<br><br>
<h3>Choose a file(s) or drag it here.</h3>
</div>
</label>
</div>
</template>

<script lang="ts">
import { mixins } from 'vue-class-component'
import { Component } from 'vue-property-decorator'
import I18nMixin from '~/mixins/I18nMixin'
export const EVENTS = {
SELECT_FILES: 'select-files' as const
}
const HOLDER_CLASS = 'tiptap-vuetify-image-upload-area-holder'
@Component
export default class ImageUploadArea extends mixins(I18nMixin) {
mounted () {
const holder = this.$el.querySelector('.' + HOLDER_CLASS)! as HTMLElement
const input = this.$el.querySelector('#tiptap-vuetify-image-upload-area__input-file')! as HTMLInputElement
input.addEventListener('change', e => {
if (e.target instanceof HTMLInputElement) {
this.$emit(EVENTS.SELECT_FILES, e.target.files)
holder.classList.remove(HOLDER_CLASS + '--dragover')
e.target.value = ''
}
})
holder.addEventListener('dragover', () => {
holder.classList.add(HOLDER_CLASS + '--dragover')
return false
})
const dragleaveOrEndHandler = () => {
holder.classList.remove(HOLDER_CLASS + '--dragover')
return false
}
holder.addEventListener('dragleave', dragleaveOrEndHandler)
holder.addEventListener('dragend', dragleaveOrEndHandler)
holder.addEventListener('drop', e => {
e.preventDefault()
this.$emit(EVENTS.SELECT_FILES, e.dataTransfer!.files)
})
}
}
</script>

<style lang="stylus">
#tiptap-vuetify-image-upload-area__input-file
display none
.tiptap-vuetify-image-upload-area-holder
background-color #c8dadf
height 400px
outline 2px dashed #92b0b3
outline-offset -10px
transition all .15s ease-in-out
display flex !important
justify-content center
align-items center
&:hover,
&--dragover
background-color #a5b7bc
outline 2px dashed #648083
color #444444
cursor pointer
.tiptap-vuetify-image-upload-area-holder__icon
fill #5f777a !important
.tiptap-vuetify-image-upload-area-holder__icon
width 100%
height 80px
fill #92b0b3
display block
margin-bottom 40px
transition all .15s ease-in-out
</style>
Loading

0 comments on commit e464b2b

Please sign in to comment.