tiptapify 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -2
- package/dist/tiptapify.css +1 -1
- package/dist/tiptapify.mjs +26215 -22992
- package/dist/tiptapify.umd.js +39 -39
- package/index.d.ts +49 -0
- package/package.json +10 -8
- package/src/components/Footer.vue +48 -6
- package/src/components/Tiptapify.vue +37 -29
- package/src/components/Toolbar/Group.vue +13 -14
- package/src/components/Toolbar/GroupBtn.vue +30 -0
- package/src/components/Toolbar/GroupDropdown.vue +4 -8
- package/src/components/Toolbar/Index.vue +26 -77
- package/src/components/Toolbar/Items.vue +77 -0
- package/src/components/Toolbar/defaultExtensionComponents.ts +32 -0
- package/src/components/Toolbar/items/format.ts +7 -20
- package/src/components/Toolbar/items/formatExtra.ts +1 -1
- package/src/components/Toolbar/items/media.ts +1 -1
- package/src/components/Toolbar/items/misc.ts +1 -1
- package/src/components/Toolbar/items/style.ts +60 -2
- package/src/components/Toolbar/items.ts +6 -4
- package/src/components/UI/Dialog.vue +141 -0
- package/src/components/editorExtensions.ts +3 -7
- package/src/extensions/components/ImageDialog.vue +17 -29
- package/src/extensions/components/LinkDialog.vue +58 -43
- package/src/extensions/components/PreviewDialog.vue +8 -16
- package/src/extensions/components/ShowSourceDialog.vue +14 -16
- package/src/extensions/components/StyleColor.vue +230 -0
- package/src/extensions/components/TableBuilder.vue +4 -8
- package/src/i18n/locales/ch.json +118 -0
- package/src/i18n/locales/cz.json +118 -0
- package/src/i18n/locales/de.json +90 -72
- package/src/i18n/locales/en.json +89 -71
- package/src/i18n/locales/es.json +90 -72
- package/src/i18n/locales/fr.json +91 -72
- package/src/i18n/locales/it.json +90 -72
- package/src/i18n/locales/la.json +118 -0
- package/src/i18n/locales/lt.json +118 -0
- package/src/i18n/locales/nl.json +118 -0
- package/src/i18n/locales/pl.json +90 -72
- package/src/i18n/locales/pt.json +118 -0
- package/src/i18n/locales/ru.json +85 -67
- package/src/i18n/locales/se.json +118 -0
- package/src/i18n/locales/ua.json +86 -68
- package/src/types/overridable-extensions.ts +6 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import Group from "@tiptapify/components/Toolbar/Group.vue";
|
|
3
|
+
import Toggle from "@tiptapify/components/Toolbar/Toggle.vue";
|
|
4
|
+
import { computed, defineProps, PropType, Ref, ref } from 'vue'
|
|
5
|
+
import { useI18n } from "vue-i18n";
|
|
6
|
+
|
|
7
|
+
import { ToolbarItemSections } from "@tiptapify/components/Toolbar/items";
|
|
8
|
+
|
|
9
|
+
const props = defineProps({
|
|
10
|
+
variantBtn: { type: String, default () { return 'elevated' }},
|
|
11
|
+
items: { type: Object as PropType<ToolbarItemSections>, default() { return {} }},
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const { t } = useI18n();
|
|
15
|
+
|
|
16
|
+
const toolbarItemsRef: Ref<ToolbarItemSections> = ref(computed(() => props.items).value)
|
|
17
|
+
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<VToolbarItems class="py-2">
|
|
22
|
+
<template v-for="(toolbarSection, sectionKey) in toolbarItemsRef" :key="sectionKey">
|
|
23
|
+
<Group v-if="toolbarSection.group" :variant="variantBtn" :toolbar-section="toolbarSection" />
|
|
24
|
+
|
|
25
|
+
<Toggle v-else-if="toolbarSection.toggle" :variant="variantBtn" :toolbar-section="toolbarSection" />
|
|
26
|
+
|
|
27
|
+
<VBtn
|
|
28
|
+
v-else
|
|
29
|
+
v-for="(toolbarItem, itemKey) in toolbarSection.items"
|
|
30
|
+
:key="itemKey"
|
|
31
|
+
:variant="variantBtn"
|
|
32
|
+
v-bind="toolbarItem.props"
|
|
33
|
+
v-on="toolbarItem.attrs"
|
|
34
|
+
class="menu-button"
|
|
35
|
+
size="32"
|
|
36
|
+
elevation="4"
|
|
37
|
+
rounded="sm"
|
|
38
|
+
>
|
|
39
|
+
<VTooltip :text="t(toolbarItem.tooltip)" location="top" activator="parent" />
|
|
40
|
+
|
|
41
|
+
<VIcon v-if="toolbarItem.icon" :icon="toolbarItem.icon" size="16" />
|
|
42
|
+
<span v-else class="menu-item-title">
|
|
43
|
+
{{ t(toolbarItem.name) }}
|
|
44
|
+
</span>
|
|
45
|
+
</VBtn>
|
|
46
|
+
|
|
47
|
+
<div class="menu-divider"></div>
|
|
48
|
+
</template>
|
|
49
|
+
</VToolbarItems>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<style lang="scss" scoped>
|
|
53
|
+
:deep(.v-btn-group) {
|
|
54
|
+
height: 32px !important;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.menu-item-title {
|
|
58
|
+
font-size: 14px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.menu-button {
|
|
62
|
+
margin: 0 1px;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.menu-divider {
|
|
66
|
+
margin: 0 4px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.menu-divider:nth-last-child(1) {
|
|
70
|
+
display: none;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.v-toolbar-items {
|
|
74
|
+
flex-wrap: wrap;
|
|
75
|
+
row-gap: 5px;
|
|
76
|
+
}
|
|
77
|
+
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import ImageDialog from "@tiptapify/extensions/components/ImageDialog.vue";
|
|
2
|
+
import LinkDialog from "@tiptapify/extensions/components/LinkDialog.vue";
|
|
3
|
+
import PreviewDialog from "@tiptapify/extensions/components/PreviewDialog.vue";
|
|
4
|
+
import ShowSourceDialog from "@tiptapify/extensions/components/ShowSourceDialog.vue";
|
|
5
|
+
import { extensionsComponents } from "@tiptapify/types/overridable-extensions";
|
|
6
|
+
import { computed } from "vue";
|
|
7
|
+
|
|
8
|
+
export function getDefaultComponents(variantField: string): extensionsComponents {
|
|
9
|
+
return {
|
|
10
|
+
image: {
|
|
11
|
+
component: ImageDialog,
|
|
12
|
+
props: {
|
|
13
|
+
variantField: computed(() => variantField).value,
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
link: {
|
|
17
|
+
component: LinkDialog,
|
|
18
|
+
props: {
|
|
19
|
+
variantField: computed(() => variantField).value,
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
preview: {
|
|
23
|
+
component: PreviewDialog,
|
|
24
|
+
},
|
|
25
|
+
showSource: {
|
|
26
|
+
component: ShowSourceDialog,
|
|
27
|
+
props: {
|
|
28
|
+
variantField: computed(() => variantField).value,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -30,19 +30,6 @@ export function getFormatItems(editor: Editor) {
|
|
|
30
30
|
click: () => editor.chain().focus().toggleItalic().run()
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
strike: {
|
|
34
|
-
name: 'strike',
|
|
35
|
-
tooltip: 'format.strike',
|
|
36
|
-
icon: mdi.mdiFormatStrikethroughVariant,
|
|
37
|
-
enabled: true,
|
|
38
|
-
props: {
|
|
39
|
-
disabled: computed(() => !editor.can().chain().focus().toggleStrike().run()),
|
|
40
|
-
color: computed(() => editor.isActive('strike') ? 'primary' : ''),
|
|
41
|
-
},
|
|
42
|
-
attrs: {
|
|
43
|
-
click: () => editor.chain().focus().toggleStrike().run()
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
33
|
underline: {
|
|
47
34
|
name: 'underline',
|
|
48
35
|
tooltip: 'format.underline',
|
|
@@ -56,17 +43,17 @@ export function getFormatItems(editor: Editor) {
|
|
|
56
43
|
click: () => editor.chain().focus().toggleUnderline().run()
|
|
57
44
|
}
|
|
58
45
|
},
|
|
59
|
-
|
|
60
|
-
name: '
|
|
61
|
-
tooltip: 'format.
|
|
62
|
-
icon: mdi.
|
|
46
|
+
strike: {
|
|
47
|
+
name: 'strike',
|
|
48
|
+
tooltip: 'format.strike',
|
|
49
|
+
icon: mdi.mdiFormatStrikethroughVariant,
|
|
63
50
|
enabled: true,
|
|
64
51
|
props: {
|
|
65
|
-
disabled: computed(() => !editor.can().chain().focus().
|
|
66
|
-
color: computed(() => editor.isActive('
|
|
52
|
+
disabled: computed(() => !editor.can().chain().focus().toggleStrike().run()),
|
|
53
|
+
color: computed(() => editor.isActive('strike') ? 'primary' : ''),
|
|
67
54
|
},
|
|
68
55
|
attrs: {
|
|
69
|
-
click: () => editor.chain().focus().
|
|
56
|
+
click: () => editor.chain().focus().toggleStrike().run()
|
|
70
57
|
}
|
|
71
58
|
}
|
|
72
59
|
}
|
|
@@ -62,7 +62,7 @@ export function getFormatExtraItems(editor: Editor) {
|
|
|
62
62
|
icon: mdi.mdiCommentQuote,
|
|
63
63
|
enabled: true,
|
|
64
64
|
props: {
|
|
65
|
-
disabled: computed(() => !editor.can().chain().focus().toggleBlockquote().run()),
|
|
65
|
+
disabled: computed(() => !editor.can().chain().focus().toggleBlockquote().run() || editor.isActive('codeBlock') || editor.isActive('code')),
|
|
66
66
|
color: computed(() => editor.isActive('blockquote') ? 'primary' : ''),
|
|
67
67
|
},
|
|
68
68
|
attrs: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as mdi from "@mdi/js";
|
|
2
2
|
import { Editor } from "@tiptap/vue-3";
|
|
3
3
|
import TableBuilder from "@tiptapify/extensions/components/TableBuilder.vue";
|
|
4
|
-
import { computed, markRaw
|
|
4
|
+
import { computed, markRaw } from "vue";
|
|
5
5
|
|
|
6
6
|
export function getMediaItems(editor: Editor) {
|
|
7
7
|
return {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as mdi from "@mdi/js";
|
|
2
2
|
import { Editor } from "@tiptap/vue-3";
|
|
3
3
|
import { fonts } from "@tiptapify/components/Toolbar/fonts";
|
|
4
|
-
import
|
|
4
|
+
import StyleColor from "@tiptapify/extensions/components/StyleColor.vue";
|
|
5
|
+
import { computed, markRaw, ref } from "vue";
|
|
5
6
|
|
|
6
7
|
interface MDIIcons {
|
|
7
8
|
[key: string]: string
|
|
8
9
|
}
|
|
9
10
|
const mdiIcons = mdi as MDIIcons
|
|
10
11
|
|
|
11
|
-
export function getStyleItems(editor: Editor, fontMeasure: string, customHeadingLevels: Array<number> = []) {
|
|
12
|
+
export function getStyleItems(editor: Editor, theme: any, fontMeasure: string, customHeadingLevels: Array<number> = []) {
|
|
12
13
|
const headingLevels = ref([1, 2, 3, 4, 5, 6])
|
|
13
14
|
if (customHeadingLevels.length) {
|
|
14
15
|
customHeadingLevels.forEach(level => {
|
|
@@ -72,6 +73,9 @@ export function getStyleItems(editor: Editor, fontMeasure: string, customHeading
|
|
|
72
73
|
icon: mdi.mdiFormatFont,
|
|
73
74
|
modelValue: false,
|
|
74
75
|
enabled: true,
|
|
76
|
+
props: {
|
|
77
|
+
disabled: computed(() => !editor.can().chain().focus().unsetFontFamily().run()),
|
|
78
|
+
},
|
|
75
79
|
attrs: {
|
|
76
80
|
click: () => editor.chain().focus().unsetFontFamily().run()
|
|
77
81
|
},
|
|
@@ -98,6 +102,9 @@ export function getStyleItems(editor: Editor, fontMeasure: string, customHeading
|
|
|
98
102
|
icon: mdi.mdiFormatSize,
|
|
99
103
|
modelValue: false,
|
|
100
104
|
enabled: true,
|
|
105
|
+
props: {
|
|
106
|
+
disabled: computed(() => !editor.can().chain().focus().unsetFontSize().run()),
|
|
107
|
+
},
|
|
101
108
|
attrs: {
|
|
102
109
|
click: () => editor.chain().focus().unsetFontSize().run()
|
|
103
110
|
},
|
|
@@ -123,6 +130,9 @@ export function getStyleItems(editor: Editor, fontMeasure: string, customHeading
|
|
|
123
130
|
icon: mdi.mdiFormatLineHeight,
|
|
124
131
|
modelValue: null,
|
|
125
132
|
enabled: true,
|
|
133
|
+
props: {
|
|
134
|
+
disabled: computed(() => !editor.can().chain().focus().unsetLineHeight().run()),
|
|
135
|
+
},
|
|
126
136
|
attrs: {
|
|
127
137
|
click: () => editor.chain().focus().unsetLineHeight().run()
|
|
128
138
|
},
|
|
@@ -141,6 +151,54 @@ export function getStyleItems(editor: Editor, fontMeasure: string, customHeading
|
|
|
141
151
|
}
|
|
142
152
|
}
|
|
143
153
|
})
|
|
154
|
+
},
|
|
155
|
+
highlight: {
|
|
156
|
+
name: 'highlight',
|
|
157
|
+
tooltip: 'style.color.highlight',
|
|
158
|
+
icon: mdi.mdiFormatColorFill,
|
|
159
|
+
icon2: mdi.mdiColorHelper,
|
|
160
|
+
enabled: true,
|
|
161
|
+
props: {
|
|
162
|
+
disabled: computed(() => !editor.can().chain().focus().toggleHighlight().run()),
|
|
163
|
+
},
|
|
164
|
+
icon2Props: {
|
|
165
|
+
disabled: computed(() => !editor.can().chain().focus().toggleHighlight().run()),
|
|
166
|
+
color: computed(() => {
|
|
167
|
+
const defaultColor = theme.global.current.value.dark ? '#fff' : '#000'
|
|
168
|
+
return editor.getAttributes('highlight').color || defaultColor
|
|
169
|
+
}),
|
|
170
|
+
style: 'filter: drop-shadow(rgba(0, 0, 0, .75) 1px 1px 2px);'
|
|
171
|
+
},
|
|
172
|
+
component: markRaw(StyleColor),
|
|
173
|
+
componentProps: {
|
|
174
|
+
fontColor: false,
|
|
175
|
+
backgroundColor: true,
|
|
176
|
+
color: computed(() => editor.getAttributes('highlight').color || ''),
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
color: {
|
|
180
|
+
name: 'color',
|
|
181
|
+
tooltip: 'style.color.text',
|
|
182
|
+
icon: mdi.mdiFormatColorText,
|
|
183
|
+
icon2: mdi.mdiColorHelper,
|
|
184
|
+
enabled: true,
|
|
185
|
+
props: {
|
|
186
|
+
disabled: computed(() => !editor.can().chain().focus().toggleHighlight().run()),
|
|
187
|
+
},
|
|
188
|
+
icon2Props: {
|
|
189
|
+
disabled: computed(() => !editor.can().chain().focus().toggleHighlight().run()),
|
|
190
|
+
color: computed(() => {
|
|
191
|
+
const defaultColor = theme.global.current.value.dark ? '#fff' : '#000'
|
|
192
|
+
return editor.getAttributes('textStyle').color || defaultColor
|
|
193
|
+
}),
|
|
194
|
+
style: 'filter: drop-shadow(rgba(0, 0, 0, .75) 1px 1px 2px);'
|
|
195
|
+
},
|
|
196
|
+
component: markRaw(StyleColor),
|
|
197
|
+
componentProps: {
|
|
198
|
+
fontColor: true,
|
|
199
|
+
backgroundColor: false,
|
|
200
|
+
color: computed(() => editor.getAttributes('textStyle').color || ''),
|
|
201
|
+
}
|
|
144
202
|
}
|
|
145
203
|
}
|
|
146
204
|
}
|
|
@@ -6,7 +6,7 @@ import { getListItems } from "@tiptapify/components/Toolbar/items/list";
|
|
|
6
6
|
import { getMediaItems } from "@tiptapify/components/Toolbar/items/media";
|
|
7
7
|
import { getMiscItems } from "@tiptapify/components/Toolbar/items/misc";
|
|
8
8
|
import { getStyleItems } from "@tiptapify/components/Toolbar/items/style";
|
|
9
|
-
import { ComputedRef,
|
|
9
|
+
import { ComputedRef, ref } from "vue";
|
|
10
10
|
|
|
11
11
|
interface ToolbarItemAttrs {
|
|
12
12
|
[key: string]: Function | any
|
|
@@ -20,12 +20,15 @@ export interface ToolbarItem {
|
|
|
20
20
|
name: string|number,
|
|
21
21
|
tooltip: string,
|
|
22
22
|
icon: string|ComputedRef<string>,
|
|
23
|
+
icon2?: string|ComputedRef<string>,
|
|
23
24
|
noI18n?: boolean,
|
|
24
25
|
enabled: boolean,
|
|
25
26
|
component?: any,
|
|
26
27
|
modelValue?: any,
|
|
27
28
|
group?: boolean,
|
|
28
29
|
toggle?: boolean,
|
|
30
|
+
icon2Props?: ToolbarItemProps,
|
|
31
|
+
componentProps?: ToolbarItemProps,
|
|
29
32
|
props?: ToolbarItemProps,
|
|
30
33
|
attrs?: ToolbarItemAttrs,
|
|
31
34
|
children?: ToolbarItems|ToolbarItem[],
|
|
@@ -47,11 +50,12 @@ export interface ToolbarItemSections {
|
|
|
47
50
|
|
|
48
51
|
export function toolbarItems(
|
|
49
52
|
editor: any,
|
|
53
|
+
theme: any,
|
|
50
54
|
fontMeasure: string,
|
|
51
55
|
items: { list: Array<string>, exclude: boolean },
|
|
52
56
|
customHeadingLevels: Array<number>
|
|
53
57
|
): ToolbarItemSections {
|
|
54
|
-
const styleItems = ref(getStyleItems(editor.value, fontMeasure, customHeadingLevels))
|
|
58
|
+
const styleItems = ref(getStyleItems(editor.value, theme, fontMeasure, customHeadingLevels))
|
|
55
59
|
const formatItems = ref(getFormatItems(editor.value))
|
|
56
60
|
const formatExtraItems = ref(getFormatExtraItems(editor.value))
|
|
57
61
|
const alignmentItems = ref(getAlignmentItems(editor.value))
|
|
@@ -64,8 +68,6 @@ export function toolbarItems(
|
|
|
64
68
|
/**
|
|
65
69
|
* todo
|
|
66
70
|
*
|
|
67
|
-
* font color, backgroundcolor
|
|
68
|
-
* tables
|
|
69
71
|
* media (image, video)
|
|
70
72
|
*/
|
|
71
73
|
style: { group: true, items: styleItems.value },
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
|
|
3
|
+
import * as mdi from "@mdi/js";
|
|
4
|
+
import { nextTick, ref, watch } from "vue";
|
|
5
|
+
import { useI18n } from "vue-i18n";
|
|
6
|
+
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
module: String,
|
|
9
|
+
fullscreen: { type: Boolean, default () { return false } },
|
|
10
|
+
maxWidth: { type: Number, default () { return 800 } },
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const { t } = useI18n();
|
|
14
|
+
|
|
15
|
+
defineExpose({ open, close })
|
|
16
|
+
const emits = defineEmits(['closeDialog'])
|
|
17
|
+
|
|
18
|
+
const dialog = ref<boolean>(false)
|
|
19
|
+
const movableHandler = ref(null)
|
|
20
|
+
|
|
21
|
+
function open() {
|
|
22
|
+
dialog.value = true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function close() {
|
|
26
|
+
dialog.value = false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function emitClose() {
|
|
30
|
+
emits('closeDialog')
|
|
31
|
+
|
|
32
|
+
close()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function dragElement(trigger: HTMLElement, container: HTMLElement) {
|
|
36
|
+
const coordinates = {
|
|
37
|
+
moveX: 0,
|
|
38
|
+
moveY: 0,
|
|
39
|
+
cursorX: 0,
|
|
40
|
+
cursorY: 0,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
trigger.onmousedown = dragMouseDown
|
|
44
|
+
|
|
45
|
+
function dragMouseDown(e: MouseEvent) {
|
|
46
|
+
e.preventDefault()
|
|
47
|
+
|
|
48
|
+
coordinates.cursorX = e.clientX
|
|
49
|
+
coordinates.cursorY = e.clientY
|
|
50
|
+
|
|
51
|
+
document.onmouseup = closeDragElement
|
|
52
|
+
document.onmousemove = elementDrag
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function elementDrag(e: MouseEvent) {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
|
|
58
|
+
coordinates.moveX = coordinates.cursorX - e.clientX
|
|
59
|
+
coordinates.moveY = coordinates.cursorY - e.clientY
|
|
60
|
+
coordinates.cursorX = e.clientX
|
|
61
|
+
coordinates.cursorY = e.clientY
|
|
62
|
+
|
|
63
|
+
const parentOffsetLeft = container.parentNode.offsetLeft
|
|
64
|
+
const parentOffsetTop = container.parentNode.offsetTop
|
|
65
|
+
|
|
66
|
+
let left = container.offsetLeft - coordinates.moveX
|
|
67
|
+
if (left < (parentOffsetLeft * -1)) {
|
|
68
|
+
left = (parentOffsetLeft * -1)
|
|
69
|
+
}
|
|
70
|
+
if (left >= parentOffsetLeft) {
|
|
71
|
+
left = parentOffsetLeft
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let top = container.offsetTop - coordinates.moveY
|
|
75
|
+
if (top < (parentOffsetTop * -1)) {
|
|
76
|
+
top = (parentOffsetTop * -1)
|
|
77
|
+
}
|
|
78
|
+
if (top >= parentOffsetTop) {
|
|
79
|
+
top = parentOffsetTop
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
container.style.left = `${left}px`
|
|
83
|
+
container.style.top = `${top}px`
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function closeDragElement() {
|
|
87
|
+
document.onmouseup = null
|
|
88
|
+
document.onmousemove = null
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
watch(() => dialog.value, async () => {
|
|
93
|
+
await nextTick()
|
|
94
|
+
|
|
95
|
+
if (!movableHandler.value) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (dialog.value && !props.fullscreen) {
|
|
100
|
+
dragElement(movableHandler.value.$el as HTMLElement, movableHandler.value.$el.parentNode as HTMLElement)
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<template>
|
|
106
|
+
<VDialog v-model="dialog" :max-width="maxWidth" :fullscreen="fullscreen" absolute @click:outside="emitClose">
|
|
107
|
+
<VCard>
|
|
108
|
+
<VCardTitle ref="movableHandler" :class="`d-flex ${!fullscreen ? 'tiptapify-movable-handler' : ''}`" style="user-select: none;">
|
|
109
|
+
<VLabel>
|
|
110
|
+
{{ t(`dialog.${module}.title`) }}
|
|
111
|
+
</VLabel>
|
|
112
|
+
|
|
113
|
+
<VSpacer />
|
|
114
|
+
|
|
115
|
+
<VBtn density="compact" class="tiptapify-dialog-close" variant="elevated" elevation="4" icon @click="emitClose">
|
|
116
|
+
<VIcon size="x-small" :icon="mdi.mdiClose" />
|
|
117
|
+
</VBtn>
|
|
118
|
+
</VCardTitle>
|
|
119
|
+
|
|
120
|
+
<VDivider />
|
|
121
|
+
|
|
122
|
+
<slot name="content" />
|
|
123
|
+
|
|
124
|
+
<slot name="actions" />
|
|
125
|
+
</VCard>
|
|
126
|
+
</VDialog>
|
|
127
|
+
</template>
|
|
128
|
+
|
|
129
|
+
<style lang="scss" scoped>
|
|
130
|
+
:deep(.v-overlay__content) {
|
|
131
|
+
position: fixed;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.tiptapify-movable-handler, :deep(.tiptapify-movable-handler > *) {
|
|
135
|
+
cursor: move;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.tiptapify-dialog-close:hover {
|
|
139
|
+
cursor: pointer;
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
@@ -69,7 +69,7 @@ export function editorExtensions (placeholder: string, slashCommands: boolean) {
|
|
|
69
69
|
Dropcursor,
|
|
70
70
|
Typography,
|
|
71
71
|
Underline,
|
|
72
|
-
Highlight,
|
|
72
|
+
Highlight.configure({ multicolor: true }),
|
|
73
73
|
TiptapifyLink.configure({
|
|
74
74
|
openOnClick: false,
|
|
75
75
|
defaultProtocol: 'https'
|
|
@@ -89,12 +89,8 @@ export function editorExtensions (placeholder: string, slashCommands: boolean) {
|
|
|
89
89
|
},
|
|
90
90
|
})
|
|
91
91
|
.configure({ lowlight }),
|
|
92
|
-
Selection.configure({
|
|
93
|
-
|
|
94
|
-
}),
|
|
95
|
-
TextAlign.configure({
|
|
96
|
-
types: ['heading', 'paragraph'],
|
|
97
|
-
}),
|
|
92
|
+
Selection.configure({ className: 'selection' }),
|
|
93
|
+
TextAlign.configure({ types: ['heading', 'paragraph'] }),
|
|
98
94
|
Placeholder.configure({ placeholder }),
|
|
99
95
|
CharacterCount,
|
|
100
96
|
ViewSource,
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
|
|
3
|
-
import * as mdi from '@mdi/js'
|
|
4
3
|
import { Editor } from "@tiptap/vue-3";
|
|
4
|
+
import Dialog from "@tiptapify/components/UI/Dialog.vue";
|
|
5
5
|
|
|
6
6
|
import { useI18n } from 'vue-i18n'
|
|
7
7
|
import { computed, inject, onMounted, onUnmounted, Ref, ref } from 'vue'
|
|
8
8
|
|
|
9
|
-
import helpers from '@tiptapify/utils/helpers'
|
|
10
|
-
|
|
11
9
|
defineProps({
|
|
12
10
|
variantBtn: { type: String, default() { return 'elevated' }},
|
|
13
11
|
variantField: { type: String, default() { return 'solo' }}
|
|
14
12
|
})
|
|
15
13
|
|
|
16
|
-
const { ucFirst } = helpers
|
|
17
|
-
|
|
18
14
|
const editor = inject('tiptapifyEditor') as Ref<Editor>
|
|
19
15
|
const { t } = useI18n()
|
|
20
16
|
|
|
@@ -27,7 +23,7 @@ const generateImageAttrs = () => ({
|
|
|
27
23
|
|
|
28
24
|
const attrs = ref(generateImageAttrs())
|
|
29
25
|
|
|
30
|
-
const dialog = ref
|
|
26
|
+
const dialog = ref(null)
|
|
31
27
|
|
|
32
28
|
const isDisabled = computed(() => {
|
|
33
29
|
const { src } = attrs.value
|
|
@@ -64,7 +60,7 @@ function clear() {
|
|
|
64
60
|
}
|
|
65
61
|
|
|
66
62
|
function close() {
|
|
67
|
-
dialog.value
|
|
63
|
+
dialog.value.close()
|
|
68
64
|
|
|
69
65
|
attrs.value = generateImageAttrs()
|
|
70
66
|
}
|
|
@@ -75,7 +71,7 @@ const showTiptapifyImage = (event: CustomEvent) => {
|
|
|
75
71
|
attrs.value.width = event.detail.image?.width
|
|
76
72
|
attrs.value.height = event.detail.image?.height
|
|
77
73
|
|
|
78
|
-
dialog.value
|
|
74
|
+
dialog.value.open()
|
|
79
75
|
}
|
|
80
76
|
|
|
81
77
|
onMounted(() => {
|
|
@@ -88,55 +84,47 @@ onUnmounted(() => {
|
|
|
88
84
|
</script>
|
|
89
85
|
|
|
90
86
|
<template>
|
|
91
|
-
<
|
|
92
|
-
<
|
|
93
|
-
<VToolbar class="px-6" density="compact">
|
|
94
|
-
<span class="headline">{{ ucFirst(t('dialog.image.title')) }}</span>
|
|
95
|
-
|
|
96
|
-
<VSpacer />
|
|
97
|
-
|
|
98
|
-
<VBtn class="mx-0" icon @click="close">
|
|
99
|
-
<VIcon :icon="mdi.mdiClose" />
|
|
100
|
-
</VBtn>
|
|
101
|
-
</VToolbar>
|
|
102
|
-
|
|
87
|
+
<Dialog ref="dialog" module="image" :max-width="800">
|
|
88
|
+
<template #content>
|
|
103
89
|
<VCardText>
|
|
104
90
|
<VRow>
|
|
105
91
|
<VCol cols="12">
|
|
106
|
-
<VTextField v-model="attrs.src"
|
|
92
|
+
<VTextField v-model="attrs.src" density="compact" variant="outlined" :label="t('dialog.image.src')" />
|
|
107
93
|
</VCol>
|
|
108
94
|
|
|
109
95
|
<VCol cols="12" md="6">
|
|
110
|
-
<VTextField v-model="attrs.alt"
|
|
96
|
+
<VTextField v-model="attrs.alt" density="compact" variant="outlined" :label="t('dialog.image.alt')" />
|
|
111
97
|
</VCol>
|
|
112
98
|
|
|
113
99
|
<VCol cols="12" md="3">
|
|
114
|
-
<VTextField v-model="attrs.width" type="number"
|
|
100
|
+
<VTextField v-model="attrs.width" type="number" density="compact" variant="outlined" :precision="0" :min="1" :label="t('dialog.image.width')" />
|
|
115
101
|
</VCol>
|
|
116
102
|
|
|
117
103
|
<VCol cols="12" md="3">
|
|
118
|
-
<VTextField v-model="attrs.height" type="number"
|
|
104
|
+
<VTextField v-model="attrs.height" type="number" density="compact" variant="outlined" :precision="0" :min="1" :label="t('dialog.image.height')" />
|
|
119
105
|
</VCol>
|
|
120
106
|
</VRow>
|
|
121
107
|
</VCardText>
|
|
108
|
+
</template>
|
|
122
109
|
|
|
110
|
+
<template #actions>
|
|
123
111
|
<VCardActions>
|
|
124
112
|
<VRow>
|
|
125
113
|
<VCol class="d-flex justify-start">
|
|
126
114
|
<VBtn color="warning" v-if="editor.isActive('image')" :variant="variantBtn" :disabled="isDisabled" @click="clear">
|
|
127
|
-
{{
|
|
115
|
+
{{ t('dialog.clear') }}
|
|
128
116
|
</VBtn>
|
|
129
117
|
</VCol>
|
|
130
118
|
<VCol class="d-flex justify-end">
|
|
131
119
|
<VBtn :variant="variantBtn" @click="close" class="mr-2">
|
|
132
|
-
{{
|
|
120
|
+
{{ t('dialog.close') }}
|
|
133
121
|
</VBtn>
|
|
134
122
|
<VBtn color="primary" :variant="variantBtn" :disabled="isDisabled" @click="apply">
|
|
135
|
-
{{
|
|
123
|
+
{{ t('dialog.apply') }}
|
|
136
124
|
</VBtn>
|
|
137
125
|
</VCol>
|
|
138
126
|
</VRow>
|
|
139
127
|
</VCardActions>
|
|
140
|
-
</
|
|
141
|
-
</
|
|
128
|
+
</template>
|
|
129
|
+
</Dialog>
|
|
142
130
|
</template>
|