tiptapify 0.0.1 → 0.0.4

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.
@@ -1,651 +0,0 @@
1
- <script setup lang="ts">
2
- import LinkDialog from "@tiptapify/components/extensions/components/LinkDialog.vue";
3
- import { useEditor } from "@tiptapify/composable/useEditor";
4
- import { computed, defineProps, ref } from 'vue'
5
- import * as mdi from '@mdi/js'
6
- import { useI18n } from "vue-i18n";
7
-
8
- const props = defineProps({
9
- variant: String,
10
- })
11
-
12
- const { t } = useI18n();
13
-
14
- const { editor } = useEditor()
15
- const editorInstance = ref(editor.getInstance())
16
-
17
- const toolbarLinkButton = ref(null)
18
-
19
- const fonts = [
20
- {
21
- name: 'Inter',
22
- fontFamily: 'Inter'
23
- },
24
- {
25
- name: 'Comic Sans',
26
- fontFamily: 'Comic Sans MS, Comic Sans'
27
- },
28
- {
29
- name: 'Serif',
30
- fontFamily: 'serif'
31
- },
32
- {
33
- name: 'Monospace',
34
- fontFamily: 'monospace'
35
- },
36
- {
37
- name: 'Cursive',
38
- fontFamily: 'cursive'
39
- },
40
- ]
41
-
42
- const fontSizes = [
43
- 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 32, 48, 64, 96
44
- ]
45
-
46
- const lineHeights = [
47
- 1, 1.5, 2, 3, 4
48
- ]
49
-
50
- const allMenuItems = ref([
51
- /**
52
- * todo
53
- *
54
- * font color, backgroundcolor
55
- * tables
56
- * unsetmarks, clearnodes
57
- * media (image, video)
58
- * unsetmarks, clearnodes
59
- */
60
- {
61
- name: 'heading',
62
- tooltip: 'style.heading',
63
- icon: 'FormatHeaderPound',
64
- modelValue: null,
65
- enabled: true,
66
- clearable: true,
67
- attrs: {
68
- click: () => editorInstance.value.chain().focus().setParagraph().run()
69
- },
70
- props: {
71
- color: computed(() => editorInstance.value.isActive('heading') ? 'primary' : ''),
72
- },
73
- children: [
74
- {
75
- name: 'H1',
76
- icon: 'FormatHeader1',
77
- enabled: true,
78
- props: {
79
- color: computed(() => {
80
- return editorInstance.value.isActive('heading', { level: 1 }) ? 'primary' : ''
81
- }),
82
- },
83
- attrs: {
84
- click: () => editorInstance.value.chain().focus().toggleHeading({ level: 1 }).run()
85
- }
86
- },
87
- {
88
- name: 'H2',
89
- icon: 'FormatHeader2',
90
- enabled: true,
91
- props: {
92
- color: computed(() => editorInstance.value.isActive('heading', { level: 2 }) ? 'primary' : ''),
93
- },
94
- attrs: {
95
- click: () => editorInstance.value.chain().focus().toggleHeading({ level: 2 }).run()
96
- }
97
- },
98
- {
99
- name: 'H3',
100
- icon: 'FormatHeader3',
101
- enabled: true,
102
- props: {
103
- color: computed(() => editorInstance.value.isActive('heading', { level: 3 }) ? 'primary' : ''),
104
- },
105
- attrs: {
106
- click: () => editorInstance.value.chain().focus().toggleHeading({ level: 3 }).run()
107
- }
108
- },
109
- {
110
- name: 'H4',
111
- icon: 'FormatHeader4',
112
- enabled: true,
113
- props: {
114
- color: computed(() => editorInstance.value.isActive('heading', { level: 4 }) ? 'primary' : ''),
115
- },
116
- attrs: {
117
- click: () => editorInstance.value.chain().focus().toggleHeading({ level: 4 }).run()
118
- }
119
- },
120
- {
121
- name: 'H5',
122
- icon: 'FormatHeader5',
123
- enabled: true,
124
- props: {
125
- color: computed(() => editorInstance.value.isActive('heading', { level: 5 }) ? 'primary' : ''),
126
- },
127
- attrs: {
128
- click: () => editorInstance.value.chain().focus().toggleHeading({ level: 5 }).run()
129
- }
130
- },
131
- {
132
- name: 'H6',
133
- icon: 'FormatHeader6',
134
- enabled: true,
135
- props: {
136
- color: computed(() => editorInstance.value.isActive('heading', { level: 6 }) ? 'primary' : ''),
137
- },
138
- attrs: {
139
- click: () => editorInstance.value.chain().focus().toggleHeading({ level: 6 }).run()
140
- }
141
- },
142
- ],
143
- },
144
- {
145
- name: 'font-family',
146
- tooltip: 'style.fontFamily',
147
- icon: 'FormatFont',
148
- modelValue: null,
149
- enabled: true,
150
- clearable: true,
151
- attrs: {
152
- click: () => editorInstance.value.chain().focus().unsetFontFamily().run()
153
- },
154
- children: fonts.map((font) => {
155
- return {
156
- name: font.name,
157
- icon: '',
158
- enabled: true,
159
- props: {
160
- color: computed(() => editorInstance.value.isActive('textStyle', { fontFamily: font.fontFamily }) ? 'primary' : ''),
161
- style: `font-family: ${font.fontFamily};`
162
- },
163
- attrs: {
164
- click: () => editorInstance.value.chain().focus().setFontFamily(font.fontFamily).run()
165
- }
166
- }
167
- })
168
- },
169
- {
170
- name: 'font-size',
171
- tooltip: 'style.fontSize',
172
- icon: 'FormatSize',
173
- modelValue: computed(() => editorInstance.value.getAttributes('textStyle').fontSize || null),
174
- enabled: true,
175
- clearable: true,
176
- attrs: {
177
- click: () => editorInstance.value.chain().focus().unsetFontSize().run()
178
- },
179
- children: fontSizes.map((fontSize) => {
180
- return {
181
- name: `${fontSize}px`,
182
- icon: '',
183
- enabled: true,
184
- props: {
185
- color: computed(() => editorInstance.value.isActive('textStyle', { fontSizes: fontSize }) ? 'primary' : ''),
186
- },
187
- attrs: {
188
- click: () => editorInstance.value.chain().focus().setFontSize(`${fontSize}px`).run()
189
- }
190
- }
191
- })
192
- },
193
- {
194
- name: 'line-height',
195
- tooltip: 'style.lineHeight',
196
- icon: 'FormatLineHeight',
197
- modelValue: null,
198
- enabled: true,
199
- clearable: true,
200
- attrs: {
201
- click: () => editorInstance.value.chain().focus().unsetLineHeight().run()
202
- },
203
- children: lineHeights.map((lineHeight) => {
204
- return {
205
- name: lineHeight,
206
- icon: '',
207
- enabled: true,
208
- props: {
209
- color: computed(() => editorInstance.value.isActive('textStyle', { lineHeights: lineHeight }) ? 'primary' : ''),
210
- },
211
- attrs: {
212
- click: () => editorInstance.value.chain().focus().setLineHeight(lineHeight).run()
213
- }
214
- }
215
- })
216
- },
217
- {
218
- name: '|'
219
- },
220
- {
221
- name: 'bold',
222
- tooltip: 'format.bold',
223
- icon: 'FormatBold',
224
- enabled: true,
225
- props: {
226
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleBold().run()),
227
- color: computed(() => editorInstance.value.isActive('bold') ? 'primary' : ''),
228
- },
229
- attrs: {
230
- click: () => editorInstance.value.chain().focus().toggleBold().run()
231
- }
232
- },
233
- {
234
- name: 'italic',
235
- tooltip: 'format.italic',
236
- icon: 'FormatItalic',
237
- enabled: true,
238
- props: {
239
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleItalic().run()),
240
- color: computed(() => editorInstance.value.isActive('italic') ? 'primary' : ''),
241
- },
242
- attrs: {
243
- click: () => editorInstance.value.chain().focus().toggleItalic().run()
244
- }
245
- },
246
- {
247
- name: 'strike',
248
- tooltip: 'format.strike',
249
- icon: 'FormatStrikethroughVariant',
250
- enabled: true,
251
- props: {
252
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleStrike().run()),
253
- color: computed(() => editorInstance.value.isActive('strike') ? 'primary' : ''),
254
- },
255
- attrs: {
256
- click: () => editorInstance.value.chain().focus().toggleStrike().run()
257
- }
258
- },
259
- {
260
- name: 'underline',
261
- tooltip: 'format.underline',
262
- icon: 'FormatUnderline',
263
- enabled: true,
264
- props: {
265
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleUnderline().run()),
266
- color: computed(() => editorInstance.value.isActive('underline') ? 'primary' : ''),
267
- },
268
- attrs: {
269
- click: () => editorInstance.value.chain().focus().toggleUnderline().run()
270
- }
271
- },
272
- {
273
- name: 'highlight',
274
- tooltip: 'format.highlight',
275
- icon: 'Marker',
276
- enabled: true,
277
- props: {
278
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleHighlight().run()),
279
- color: computed(() => editorInstance.value.isActive('highlight') ? 'primary' : ''),
280
- },
281
- attrs: {
282
- click: () => editorInstance.value.chain().focus().toggleHighlight().run()
283
- }
284
- },
285
- {
286
- name: '|'
287
- },
288
- {
289
- name: 'code',
290
- tooltip: 'format.code',
291
- icon: 'Xml',
292
- enabled: true,
293
- props: {
294
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleCode().run()),
295
- color: computed(() => editorInstance.value.isActive('code') ? 'primary' : ''),
296
- },
297
- attrs: {
298
- click: () => editorInstance.value.chain().focus().toggleCode().run()
299
- }
300
- },
301
- {
302
- name: 'codeblock_syntax',
303
- tooltip: 'format.codeblock_syntax',
304
- icon: 'CodeBlockBraces',
305
- enabled: true,
306
- props: {
307
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleCodeBlock().run()),
308
- color: computed(() => editorInstance.value.isActive('codeblock-lowlight') ? 'primary' : ''),
309
- },
310
- attrs: {
311
- click: () => editorInstance.value.chain().focus().toggleCodeBlock().run()
312
- }
313
- },
314
- {
315
- name: 'blockquote',
316
- tooltip: 'format.blockquote',
317
- icon: 'CommentQuote',
318
- enabled: true,
319
- props: {
320
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleBlockquote().run()),
321
- color: computed(() => editorInstance.value.isActive('blockquote') ? 'primary' : ''),
322
- },
323
- attrs: {
324
- click: () => editorInstance.value.chain().focus().toggleBlockquote().run()
325
- }
326
- },
327
- {
328
- name: '|'
329
- },
330
- {
331
- name: 'sup',
332
- tooltip: 'format.sup',
333
- icon: 'FormatSuperscript',
334
- enabled: true,
335
- props: {
336
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleSuperscript().run()),
337
- color: computed(() => editorInstance.value.isActive('superscript') ? 'primary' : ''),
338
- },
339
- attrs: {
340
- click: () => editorInstance.value.chain().focus().toggleSuperscript().run()
341
- }
342
- },
343
- {
344
- name: 'sub',
345
- tooltip: 'format.sub',
346
- icon: 'FormatSubscript',
347
- enabled: true,
348
- props: {
349
- disabled: computed(() => !editorInstance.value.can().chain().focus().toggleSubscript().run()),
350
- color: computed(() => editorInstance.value.isActive('subscript') ? 'primary' : ''),
351
- },
352
- attrs: {
353
- click: () => editorInstance.value.chain().focus().toggleSubscript().run()
354
- }
355
- },
356
- {
357
- name: '|'
358
- },
359
- {
360
- name: 'alignment',
361
- tooltip: 'alignment',
362
- icon: '',
363
- enabled: true,
364
- group: true,
365
- children: [
366
- {
367
- name: 'alignments.left',
368
- tooltip: 'alignments.left',
369
- icon: 'FormatAlignLeft',
370
- enabled: true,
371
- props: {
372
- color: computed(() => editorInstance.value.isActive('text-align', { align: 'left' }) ? 'primary' : ''),
373
- },
374
- attrs: {
375
- click: () => editorInstance.value.chain().focus().toggleTextAlign('left').run()
376
- }
377
- },
378
- {
379
- name: 'alignments.center',
380
- tooltip: 'alignments.center',
381
- icon: 'FormatAlignCenter',
382
- enabled: true,
383
- props: {
384
- color: computed(() => editorInstance.value.isActive('text-align', { align: 'center' }) ? 'primary' : ''),
385
- },
386
- attrs: {
387
- click: () => editorInstance.value.chain().focus().toggleTextAlign('center').run()
388
- }
389
- },
390
- {
391
- name: 'alignments.right',
392
- tooltip: 'alignments.right',
393
- icon: 'FormatAlignRight',
394
- enabled: true,
395
- props: {
396
- color: computed(() => editorInstance.value.isActive('text-align', { align: 'right' }) ? 'primary' : ''),
397
- },
398
- attrs: {
399
- click: () => editorInstance.value.chain().focus().toggleTextAlign('right').run()
400
- }
401
- },
402
- {
403
- name: 'alignments.justify',
404
- tooltip: 'alignments.justify',
405
- icon: 'FormatAlignJustify',
406
- enabled: true,
407
- props: {
408
- color: computed(() => editorInstance.value.isActive('text-align', { align: 'justify' }) ? 'primary' : ''),
409
- },
410
- attrs: {
411
- click: () => editorInstance.value.chain().focus().toggleTextAlign('justify').run()
412
- }
413
- },
414
- ]
415
- },
416
- {
417
- name: '|'
418
- },
419
- {
420
- name: 'list',
421
- tooltip: 'list',
422
- icon: 'FormatListGroup',
423
- enabled: true,
424
- group: true,
425
- children: [
426
- {
427
- name: 'lists.bullet',
428
- tooltip: 'lists.bullet',
429
- icon: 'FormatListBulleted',
430
- enabled: true,
431
- props: {
432
- color: computed(() => editorInstance.value.isActive('bulletList') ? 'primary' : ''),
433
- },
434
- attrs: {
435
- click: () => editorInstance.value.chain().focus().toggleBulletList().run()
436
- }
437
- },
438
- {
439
- name: 'lists.numbered',
440
- tooltip: 'lists.numbered',
441
- icon: 'FormatListNumbered',
442
- enabled: true,
443
- props: {
444
- color: computed(() => editorInstance.value.isActive('orderedList') ? 'primary' : ''),
445
- },
446
- attrs: {
447
- click: () => editorInstance.value.chain().focus().toggleOrderedList().run()
448
- }
449
- },
450
- {
451
- name: 'lists.task',
452
- tooltip: 'lists.task',
453
- icon: 'FormatListChecks',
454
- enabled: true,
455
- props: {
456
- color: computed(() => editorInstance.value.isActive('taskList') ? 'primary' : ''),
457
- },
458
- attrs: {
459
- click: () => editorInstance.value.chain().focus().toggleTaskList().run()
460
- }
461
- },
462
- {
463
- name: 'lists.indent',
464
- tooltip: 'lists.indent',
465
- icon: 'FormatIndentIncrease',
466
- enabled: true,
467
- props: {
468
- disabled: computed(() => !editorInstance.value.isActive('listItem')),
469
- },
470
- attrs: {
471
- click: () => editorInstance.value.chain().focus().sinkListItem().run()
472
- }
473
- },
474
- {
475
- name: 'lists.outdent',
476
- tooltip: 'lists.outdent',
477
- icon: 'FormatIndentDecrease',
478
- enabled: true,
479
- props: {
480
- disabled: computed(() => !editorInstance.value.isActive('listItem')),
481
- },
482
- attrs: {
483
- click: () => editorInstance.value.chain().focus().liftListItem().run()
484
- }
485
- },
486
- ]
487
- },
488
- {
489
- name: '|'
490
- },
491
- {
492
- name: 'format.link',
493
- tooltip: 'format.link',
494
- icon: computed(() => !editorInstance.value.isActive('link') ? 'Link' : 'LinkOff'),
495
- enabled: true,
496
- props: {
497
- color: computed(() => editorInstance.value.isActive('link') ? 'primary' : ''),
498
- },
499
- attrs: {
500
- click: computed(() => {
501
- return editorInstance.value.isActive('link')
502
- ? editorInstance.value.chain().focus().unsetLink().run
503
- : toolbarLinkButton.value?.open
504
- })
505
- }
506
- },
507
- {
508
- name: '|'
509
- },
510
- {
511
- name: 'undo',
512
- tooltip: 'action.undo',
513
- icon: 'Undo',
514
- enabled: true,
515
- props: {
516
- disabled: computed(() => !editorInstance.value.can().chain().focus().undo().run()),
517
- },
518
- attrs: {
519
- click: () => editorInstance.value.chain().focus().undo().run()
520
- }
521
- },
522
- {
523
- name: 'redo',
524
- tooltip: 'action.redo',
525
- icon: 'Redo',
526
- enabled: true,
527
- props: {
528
- disabled: computed(() => !editorInstance.value.can().chain().focus().redo().run()),
529
- },
530
- attrs: {
531
- click: () => editorInstance.value.chain().focus().redo().run()
532
- }
533
- },
534
- {
535
- name: '|'
536
- },
537
- {
538
- name: 'line',
539
- tooltip: 'format.line',
540
- icon: 'Minus',
541
- enabled: true,
542
- props: {},
543
- attrs: {
544
- click: () => editorInstance.value.chain().focus().setHorizontalRule().run()
545
- }
546
- },
547
- {
548
- name: 'break',
549
- tooltip: 'format.break',
550
- icon: 'FormatPageBreak',
551
- enabled: true,
552
- props: {},
553
- attrs: {
554
- click: () => editorInstance.value.chain().focus().setHardBreak().run()
555
- }
556
- },
557
- ])
558
-
559
- function getIcon(icon: string) {
560
- return `${mdi[`mdi${icon}`]}`
561
- }
562
- </script>
563
-
564
- <template>
565
- <div v-if="editor" class="d-flex flex-wrap gap-x-4 gap-y-2 tiptapify-menu">
566
- <template v-for="(menuItem, key) in allMenuItems" :key="key">
567
- <VDivider v-if="menuItem.name === '|'" vertical class="menu-divider" />
568
-
569
- <template v-else-if="menuItem.enabled">
570
- <template v-if="menuItem.children">
571
- <VBtnToggle v-if="menuItem.group" :variant="variant">
572
- <VBtn
573
- v-for="(item, key) of menuItem.children"
574
- v-bind="{ ...props, ...item.props}" v-on="item.attrs" size="32"
575
- :key="`${item.name}-${key}`"
576
- >
577
- <VTooltip :text="t(item.name)" location="top" activator="parent" />
578
-
579
- <VIcon v-if="item.icon" :icon="getIcon(item.icon)" size="small" />
580
- <span v-else class="menu-item-title">
581
- {{ t(menuItem.name) }}
582
- </span>
583
- </VBtn>
584
- </VBtnToggle>
585
-
586
- <VMenu v-else>
587
- <template #activator="{ props: menuProps }">
588
- <VBtn :variant="variant" v-bind="menuProps" size="32" class="menu-button">
589
- <VTooltip :text="t(menuItem.tooltip)" location="top" activator="parent" />
590
-
591
- <VIcon v-if="menuItem.icon" :icon="getIcon(menuItem.icon)" size="small" />
592
- <span v-else class="menu-item-title">
593
- {{ t(menuItem.name) }}
594
- </span>
595
- </VBtn>
596
- </template>
597
-
598
- <VList v-model="menuItem.modelValue">
599
- <template v-for="(item, itemKey) in menuItem.children" :key="itemKey">
600
- <VListItem :value="item.name" density="compact" v-bind="item.props" v-on="item.attrs">
601
- <VTooltip v-if="item.tooltip" :text="t(item.tooltip)" location="top" activator="parent" />
602
-
603
- <VListItemTitle>
604
- <VIcon v-if="item.icon" :icon="getIcon(item.icon)" size="small" />
605
- <span v-else class="menu-item-title">
606
- {{ t(item.name) }}
607
- </span>
608
- </VListItemTitle>
609
- </VListItem>
610
- </template>
611
- </VList>
612
- </VMenu>
613
- </template>
614
-
615
- <VBtn v-else :variant="variant" v-bind="menuItem.props" v-on="menuItem.attrs" class="menu-button" size="32">
616
- <VTooltip :text="t(menuItem.tooltip)" location="top" activator="parent" />
617
-
618
- <VIcon v-if="menuItem.icon" :icon="getIcon(menuItem.icon)" size="16" />
619
- <span v-else class="menu-item-title">
620
- {{ t(menuItem.name) }}
621
- </span>
622
- </VBtn>
623
- </template>
624
- </template>
625
-
626
- <LinkDialog ref="toolbarLinkButton" />
627
- </div>
628
- </template>
629
-
630
- <style lang="scss" scoped>
631
- .tiptapify-menu {
632
- padding: 8px;
633
- border-bottom: var(--border);
634
- }
635
-
636
- :deep(.v-btn-group) {
637
- height: 32px !important;
638
- }
639
-
640
- .menu-item-title {
641
- font-size: 14px;
642
- }
643
-
644
- .menu-button {
645
- margin: 0 1px;
646
- }
647
-
648
- .v-divider.menu-divider {
649
- margin: 0 10px;
650
- }
651
- </style>