pimelon-ui 0.0.98

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.
Files changed (93) hide show
  1. package/license.md +0 -0
  2. package/package.json +75 -0
  3. package/readme.md +0 -0
  4. package/src/components/Alert.vue +57 -0
  5. package/src/components/Autocomplete.vue +176 -0
  6. package/src/components/Avatar.vue +62 -0
  7. package/src/components/Badge.vue +42 -0
  8. package/src/components/Button.vue +155 -0
  9. package/src/components/Card.vue +37 -0
  10. package/src/components/DatePicker.vue +252 -0
  11. package/src/components/Dialog.vue +216 -0
  12. package/src/components/Dropdown.vue +145 -0
  13. package/src/components/ErrorMessage.vue +24 -0
  14. package/src/components/FeatherIcon.vue +59 -0
  15. package/src/components/FileUploader.vue +220 -0
  16. package/src/components/GreenCheckIcon.vue +16 -0
  17. package/src/components/Input.vue +214 -0
  18. package/src/components/Link.vue +28 -0
  19. package/src/components/ListItem.vue +28 -0
  20. package/src/components/LoadingIndicator.vue +27 -0
  21. package/src/components/LoadingText.vue +21 -0
  22. package/src/components/Popover.vue +253 -0
  23. package/src/components/Resource.vue +21 -0
  24. package/src/components/TextEditor/FontColor.vue +108 -0
  25. package/src/components/TextEditor/InsertImage.vue +74 -0
  26. package/src/components/TextEditor/InsertLink.vue +67 -0
  27. package/src/components/TextEditor/InsertVideo.vue +94 -0
  28. package/src/components/TextEditor/MentionList.vue +95 -0
  29. package/src/components/TextEditor/Menu.vue +99 -0
  30. package/src/components/TextEditor/TextEditor.vue +275 -0
  31. package/src/components/TextEditor/TextEditorBubbleMenu.vue +69 -0
  32. package/src/components/TextEditor/TextEditorFixedMenu.vue +72 -0
  33. package/src/components/TextEditor/TextEditorFloatingMenu.vue +55 -0
  34. package/src/components/TextEditor/commands.js +272 -0
  35. package/src/components/TextEditor/icons/align-center.vue +14 -0
  36. package/src/components/TextEditor/icons/align-justify.vue +14 -0
  37. package/src/components/TextEditor/icons/align-left.vue +14 -0
  38. package/src/components/TextEditor/icons/align-right.vue +14 -0
  39. package/src/components/TextEditor/icons/arrow-go-back-line.vue +14 -0
  40. package/src/components/TextEditor/icons/arrow-go-forward-line.vue +14 -0
  41. package/src/components/TextEditor/icons/bold.vue +14 -0
  42. package/src/components/TextEditor/icons/code-view.vue +14 -0
  43. package/src/components/TextEditor/icons/double-quotes-r.vue +14 -0
  44. package/src/components/TextEditor/icons/font-color.vue +14 -0
  45. package/src/components/TextEditor/icons/format-clear.vue +14 -0
  46. package/src/components/TextEditor/icons/h-1.vue +14 -0
  47. package/src/components/TextEditor/icons/h-2.vue +14 -0
  48. package/src/components/TextEditor/icons/h-3.vue +14 -0
  49. package/src/components/TextEditor/icons/h-4.vue +14 -0
  50. package/src/components/TextEditor/icons/h-5.vue +14 -0
  51. package/src/components/TextEditor/icons/h-6.vue +14 -0
  52. package/src/components/TextEditor/icons/image-add-line.vue +14 -0
  53. package/src/components/TextEditor/icons/italic.vue +14 -0
  54. package/src/components/TextEditor/icons/link.vue +14 -0
  55. package/src/components/TextEditor/icons/list-ordered.vue +14 -0
  56. package/src/components/TextEditor/icons/list-unordered.vue +14 -0
  57. package/src/components/TextEditor/icons/readme.md +1 -0
  58. package/src/components/TextEditor/icons/separator.vue +14 -0
  59. package/src/components/TextEditor/icons/strikethrough.vue +14 -0
  60. package/src/components/TextEditor/icons/table-2.vue +14 -0
  61. package/src/components/TextEditor/icons/text.vue +11 -0
  62. package/src/components/TextEditor/icons/underline.vue +14 -0
  63. package/src/components/TextEditor/icons/video-add-line.vue +14 -0
  64. package/src/components/TextEditor/image-extension.js +152 -0
  65. package/src/components/TextEditor/index.js +6 -0
  66. package/src/components/TextEditor/mention.js +72 -0
  67. package/src/components/TextEditor/utils.js +11 -0
  68. package/src/components/TextEditor/video-extension.js +60 -0
  69. package/src/components/Toast.vue +83 -0
  70. package/src/components/Tooltip.vue +36 -0
  71. package/src/components/toast.js +98 -0
  72. package/src/directives/onOutsideClick.js +34 -0
  73. package/src/directives/visibility.js +24 -0
  74. package/src/index.js +56 -0
  75. package/src/resources/documentResource.js +194 -0
  76. package/src/resources/index.js +4 -0
  77. package/src/resources/listResource.js +312 -0
  78. package/src/resources/local.js +16 -0
  79. package/src/resources/plugin.js +105 -0
  80. package/src/resources/resources.js +215 -0
  81. package/src/style.css +15 -0
  82. package/src/utils/call.js +98 -0
  83. package/src/utils/config.js +9 -0
  84. package/src/utils/debounce.js +15 -0
  85. package/src/utils/file-to-base64.js +9 -0
  86. package/src/utils/markdown.js +29 -0
  87. package/src/utils/melonRequest.js +105 -0
  88. package/src/utils/pageMeta.js +52 -0
  89. package/src/utils/plugin.js +24 -0
  90. package/src/utils/request.js +49 -0
  91. package/src/utils/socketio.js +11 -0
  92. package/src/utils/tailwind.config.js +117 -0
  93. package/src/utils/vite-dev-server.js +14 -0
@@ -0,0 +1,99 @@
1
+ <template>
2
+ <div class="inline-flex bg-white px-1 py-1">
3
+ <div class="inline-flex items-center gap-1">
4
+ <template v-for="button in buttons" :key="button.label">
5
+ <div
6
+ class="h-4 w-[2px] border-l"
7
+ v-if="button.type === 'separator'"
8
+ ></div>
9
+ <div class="shrink-0" v-else-if="button.map">
10
+ <Popover>
11
+ <template #target="{ togglePopover }">
12
+ <button
13
+ class="rounded px-2 py-1 text-base font-medium text-gray-800 transition-colors hover:bg-gray-100"
14
+ @click="togglePopover"
15
+ :set="
16
+ (activeBtn =
17
+ button.find((b) => b.isActive(editor)) || button[0])
18
+ "
19
+ >
20
+ <component
21
+ v-if="activeBtn.icon"
22
+ :is="activeBtn.icon"
23
+ class="h-4 w-4"
24
+ />
25
+ <span v-else>
26
+ {{ activeBtn.label }}
27
+ </span>
28
+ </button>
29
+ </template>
30
+ <template #body="{ close }">
31
+ <ul class="rounded border bg-white p-1 shadow-md">
32
+ <li
33
+ class="w-full"
34
+ v-for="option in button"
35
+ v-show="option.isDisabled ? !option.isDisabled(editor) : true"
36
+ >
37
+ <button
38
+ class="w-full rounded px-2 py-1 text-left text-base hover:bg-gray-50"
39
+ @click="
40
+ () => {
41
+ onButtonClick(option)
42
+ close()
43
+ }
44
+ "
45
+ >
46
+ {{ option.label }}
47
+ </button>
48
+ </li>
49
+ </ul>
50
+ </template>
51
+ </Popover>
52
+ </div>
53
+ <component v-else :is="button.component || 'div'" v-bind="{ editor }">
54
+ <template v-slot="componentSlotProps">
55
+ <button
56
+ class="flex rounded p-1 text-gray-800 transition-colors"
57
+ :class="
58
+ button.isActive(editor) || componentSlotProps?.isActive
59
+ ? 'bg-gray-100'
60
+ : 'hover:bg-gray-100'
61
+ "
62
+ @click="
63
+ componentSlotProps?.onClick
64
+ ? componentSlotProps.onClick(button)
65
+ : onButtonClick(button)
66
+ "
67
+ :title="button.label"
68
+ >
69
+ <component v-if="button.icon" :is="button.icon" class="h-4 w-4" />
70
+ <span
71
+ class="inline-block h-4 min-w-[1rem] text-sm leading-4"
72
+ v-else
73
+ >
74
+ {{ button.text }}
75
+ </span>
76
+ </button>
77
+ </template>
78
+ </component>
79
+ </template>
80
+ </div>
81
+ </div>
82
+ </template>
83
+ <script>
84
+ import Popover from '../Popover.vue'
85
+
86
+ export default {
87
+ name: 'TipTapMenu',
88
+ props: ['buttons'],
89
+ inject: ['editor'],
90
+ components: {
91
+ Popover,
92
+ },
93
+ methods: {
94
+ onButtonClick(button) {
95
+ button.action(this.editor)
96
+ },
97
+ },
98
+ }
99
+ </script>
@@ -0,0 +1,275 @@
1
+ <template>
2
+ <div class="relative w-full" :class="$attrs.class" v-if="editor">
3
+ <TextEditorBubbleMenu :buttons="bubbleMenu" />
4
+ <TextEditorFixedMenu
5
+ class="w-full overflow-x-auto rounded-t-lg border border-gray-200"
6
+ :buttons="fixedMenu"
7
+ />
8
+ <TextEditorFloatingMenu :buttons="floatingMenu" />
9
+ <slot name="top" />
10
+ <slot name="editor" :editor="editor">
11
+ <editor-content :editor="editor" />
12
+ </slot>
13
+ <slot name="bottom" />
14
+ </div>
15
+ </template>
16
+
17
+ <script>
18
+ import { normalizeClass } from 'vue'
19
+ import { computed } from '@vue/reactivity'
20
+ import { Editor, EditorContent } from '@tiptap/vue-3'
21
+ import StarterKit from '@tiptap/starter-kit'
22
+ import Placeholder from '@tiptap/extension-placeholder'
23
+ import TextAlign from '@tiptap/extension-text-align'
24
+ import Table from '@tiptap/extension-table'
25
+ import TableCell from '@tiptap/extension-table-cell'
26
+ import TableHeader from '@tiptap/extension-table-header'
27
+ import TableRow from '@tiptap/extension-table-row'
28
+ import Image from './image-extension'
29
+ import Video from './video-extension'
30
+ import Link from '@tiptap/extension-link'
31
+ import Typography from '@tiptap/extension-typography'
32
+ import TextStyle from '@tiptap/extension-text-style'
33
+ import Highlight from '@tiptap/extension-highlight'
34
+ import { Color } from '@tiptap/extension-color'
35
+ import configureMention from './mention'
36
+ import TextEditorFixedMenu from './TextEditorFixedMenu.vue'
37
+ import TextEditorBubbleMenu from './TextEditorBubbleMenu.vue'
38
+ import TextEditorFloatingMenu from './TextEditorFloatingMenu.vue'
39
+ import { detectMarkdown, markdownToHTML } from '../../utils/markdown'
40
+ import { DOMParser } from 'prosemirror-model'
41
+
42
+ export default {
43
+ name: 'TextEditor',
44
+ inheritAttrs: false,
45
+ components: {
46
+ EditorContent,
47
+ TextEditorFixedMenu,
48
+ TextEditorBubbleMenu,
49
+ TextEditorFloatingMenu,
50
+ },
51
+ props: {
52
+ content: {
53
+ type: String,
54
+ default: null,
55
+ },
56
+ placeholder: {
57
+ type: String,
58
+ default: '',
59
+ },
60
+ editorClass: {
61
+ type: [String, Array, Object],
62
+ default: '',
63
+ },
64
+ editable: {
65
+ type: Boolean,
66
+ default: true,
67
+ },
68
+ bubbleMenu: {
69
+ type: [Boolean, Array],
70
+ default: false,
71
+ },
72
+ fixedMenu: {
73
+ type: [Boolean, Array],
74
+ default: false,
75
+ },
76
+ floatingMenu: {
77
+ type: [Boolean, Array],
78
+ default: false,
79
+ },
80
+ extensions: {
81
+ type: Array,
82
+ default: () => [],
83
+ },
84
+ starterkitOptions: {
85
+ type: Object,
86
+ default: () => ({}),
87
+ },
88
+ mentions: {
89
+ type: Array,
90
+ default: () => [],
91
+ },
92
+ },
93
+ emits: ['change'],
94
+ expose: ['editor'],
95
+ provide() {
96
+ return {
97
+ editor: computed(() => this.editor),
98
+ }
99
+ },
100
+ data() {
101
+ return {
102
+ editor: null,
103
+ }
104
+ },
105
+ watch: {
106
+ content(val) {
107
+ let currentHTML = this.editor.getHTML()
108
+ if (currentHTML !== val) {
109
+ this.editor.commands.setContent(val)
110
+ }
111
+ },
112
+ editable(value) {
113
+ this.editor.setEditable(value)
114
+ },
115
+ editorProps: {
116
+ deep: true,
117
+ handler(value) {
118
+ if (this.editor) {
119
+ this.editor.setOptions({
120
+ editorProps: value,
121
+ })
122
+ }
123
+ },
124
+ },
125
+ },
126
+ mounted() {
127
+ this.editor = new Editor({
128
+ content: this.content || null,
129
+ editorProps: this.editorProps,
130
+ editable: this.editable,
131
+ extensions: [
132
+ StarterKit.configure({
133
+ ...this.starterkitOptions,
134
+ }),
135
+ Table.configure({
136
+ resizable: true,
137
+ }),
138
+ TableRow,
139
+ TableHeader,
140
+ TableCell,
141
+ Typography,
142
+ TextAlign.configure({
143
+ types: ['heading', 'paragraph'],
144
+ }),
145
+ TextStyle,
146
+ Color,
147
+ Highlight.configure({ multicolor: true }),
148
+ Image,
149
+ Video,
150
+ Link.configure({
151
+ openOnClick: false,
152
+ }),
153
+ Placeholder.configure({
154
+ showOnlyWhenEditable: false,
155
+ placeholder: () => {
156
+ return this.placeholder
157
+ },
158
+ }),
159
+ configureMention(this.mentions),
160
+ ...(this.extensions || []),
161
+ ],
162
+ onUpdate: ({ editor }) => {
163
+ this.$emit('change', editor.getHTML())
164
+ },
165
+ })
166
+ },
167
+ beforeUnmount() {
168
+ this.editor.destroy()
169
+ this.editor = null
170
+ },
171
+ computed: {
172
+ editorProps() {
173
+ return {
174
+ attributes: {
175
+ class: normalizeClass([
176
+ 'prose prose-p:my-1 prose-table:table-fixed prose-td:p-2 prose-th:p-2 prose-td:border prose-th:border prose-td:border-gray-300 prose-th:border-gray-300 prose-td:relative prose-th:relative prose-th:bg-gray-100',
177
+ this.editorClass,
178
+ ]),
179
+ },
180
+ clipboardTextParser: (text, $context) => {
181
+ if (!detectMarkdown(text)) return
182
+ if (
183
+ !confirm(
184
+ 'Do you want to convert markdown content to HTML before pasting?'
185
+ )
186
+ )
187
+ return
188
+
189
+ let dom = document.createElement('div')
190
+ dom.innerHTML = markdownToHTML(text)
191
+ let parser =
192
+ this.editor.view.someProp('clipboardParser') ||
193
+ this.editor.view.someProp('domParser') ||
194
+ DOMParser.fromSchema(this.editor.schema)
195
+ return parser.parseSlice(dom, {
196
+ preserveWhitespace: true,
197
+ context: $context,
198
+ })
199
+ },
200
+ }
201
+ },
202
+ },
203
+ }
204
+ </script>
205
+ <style>
206
+ .ProseMirror {
207
+ outline: none;
208
+ caret-color: theme('colors.blue.600');
209
+ word-break: break-word;
210
+ }
211
+
212
+ /* Firefox */
213
+ .ProseMirror-focused:focus-visible {
214
+ outline: none;
215
+ }
216
+
217
+ /* Placeholder */
218
+ .ProseMirror:not(.ProseMirror-focused) p.is-editor-empty:first-child::before {
219
+ content: attr(data-placeholder);
220
+ float: left;
221
+ color: theme('colors.gray.500');
222
+ pointer-events: none;
223
+ height: 0;
224
+ }
225
+
226
+ .ProseMirror-selectednode video,
227
+ img.ProseMirror-selectednode {
228
+ border: 2px solid theme('colors.blue.300');
229
+ }
230
+
231
+ /* Mentions */
232
+ .mention {
233
+ font-weight: 600;
234
+ box-decoration-break: clone;
235
+ }
236
+
237
+ /* Table styles */
238
+ .prose table p {
239
+ margin: 0;
240
+ }
241
+
242
+ /* Prosemirror specific table styles */
243
+ .ProseMirror table .selectedCell:after {
244
+ z-index: 2;
245
+ position: absolute;
246
+ content: '';
247
+ left: 0;
248
+ right: 0;
249
+ top: 0;
250
+ bottom: 0;
251
+ pointer-events: none;
252
+ background: theme('colors.blue.200');
253
+ opacity: 0.3;
254
+ }
255
+
256
+ .ProseMirror table .column-resize-handle {
257
+ position: absolute;
258
+ right: -1px;
259
+ top: 0;
260
+ bottom: -2px;
261
+ width: 4px;
262
+ background-color: theme('colors.blue.200');
263
+ pointer-events: none;
264
+ }
265
+
266
+ .resize-cursor {
267
+ cursor: ew-resize;
268
+ cursor: col-resize;
269
+ }
270
+
271
+ .ProseMirror mark {
272
+ border-radius: 3px;
273
+ padding: 0 2px;
274
+ }
275
+ </style>
@@ -0,0 +1,69 @@
1
+ <template>
2
+ <BubbleMenu
3
+ v-if="bubbleMenuButtons"
4
+ class="bubble-menu rounded-md shadow-sm"
5
+ :tippy-options="{ duration: 100 }"
6
+ :editor="editor"
7
+ >
8
+ <Menu
9
+ class="rounded-md border border-gray-100 shadow-lg"
10
+ :buttons="bubbleMenuButtons"
11
+ />
12
+ </BubbleMenu>
13
+ </template>
14
+ <script>
15
+ import { BubbleMenu } from '@tiptap/vue-3'
16
+ import { createEditorButton } from './utils'
17
+ import Menu from './Menu.vue'
18
+
19
+ export default {
20
+ name: 'TextEditorBubbleMenu',
21
+ props: ['buttons'],
22
+ components: { BubbleMenu, Menu },
23
+ inject: ['editor'],
24
+ computed: {
25
+ bubbleMenuButtons() {
26
+ if (!this.buttons) return false
27
+
28
+ let buttons
29
+ if (Array.isArray(this.buttons)) {
30
+ buttons = this.buttons
31
+ } else {
32
+ buttons = [
33
+ 'Paragraph',
34
+ 'Heading 2',
35
+ 'Heading 3',
36
+ 'Separator',
37
+ 'Bold',
38
+ 'Italic',
39
+ 'Link',
40
+ 'Separator',
41
+ 'Bullet List',
42
+ 'Numbered List',
43
+ 'Separator',
44
+ 'Image',
45
+ 'Video',
46
+ 'Blockquote',
47
+ 'Code',
48
+ [
49
+ 'InsertTable',
50
+ 'AddColumnBefore',
51
+ 'AddColumnAfter',
52
+ 'DeleteColumn',
53
+ 'AddRowBefore',
54
+ 'AddRowAfter',
55
+ 'DeleteRow',
56
+ 'MergeCells',
57
+ 'SplitCell',
58
+ 'ToggleHeaderColumn',
59
+ 'ToggleHeaderRow',
60
+ 'ToggleHeaderCell',
61
+ 'DeleteTable',
62
+ ],
63
+ ]
64
+ }
65
+ return buttons.map(createEditorButton)
66
+ },
67
+ },
68
+ }
69
+ </script>
@@ -0,0 +1,72 @@
1
+ <template>
2
+ <Menu v-if="fixedMenuButtons" :buttons="fixedMenuButtons" />
3
+ </template>
4
+ <script>
5
+ import Menu from './Menu.vue'
6
+ import { createEditorButton } from './utils'
7
+
8
+ export default {
9
+ name: 'TextEditorFixedMenu',
10
+ props: ['buttons'],
11
+ components: { Menu },
12
+ inject: ['editor'],
13
+ computed: {
14
+ fixedMenuButtons() {
15
+ if (!this.buttons) return false
16
+ let buttons
17
+ if (Array.isArray(this.buttons)) {
18
+ buttons = this.buttons
19
+ } else {
20
+ buttons = [
21
+ [
22
+ 'Heading 1',
23
+ 'Heading 2',
24
+ 'Heading 3',
25
+ 'Heading 4',
26
+ 'Heading 5',
27
+ 'Heading 6',
28
+ ],
29
+ 'Paragraph',
30
+ 'Separator',
31
+ 'Bold',
32
+ 'Italic',
33
+ 'Separator',
34
+ 'Bullet List',
35
+ 'Numbered List',
36
+ 'Separator',
37
+ 'Align Left',
38
+ 'Align Center',
39
+ 'Align Right',
40
+ 'FontColor',
41
+ 'Separator',
42
+ 'Image',
43
+ 'Video',
44
+ 'Link',
45
+ 'Blockquote',
46
+ 'Code',
47
+ 'Horizontal Rule',
48
+ [
49
+ 'InsertTable',
50
+ 'AddColumnBefore',
51
+ 'AddColumnAfter',
52
+ 'DeleteColumn',
53
+ 'AddRowBefore',
54
+ 'AddRowAfter',
55
+ 'DeleteRow',
56
+ 'MergeCells',
57
+ 'SplitCell',
58
+ 'ToggleHeaderColumn',
59
+ 'ToggleHeaderRow',
60
+ 'ToggleHeaderCell',
61
+ 'DeleteTable',
62
+ ],
63
+ 'Separator',
64
+ 'Undo',
65
+ 'Redo',
66
+ ]
67
+ }
68
+ return buttons.map(createEditorButton)
69
+ },
70
+ },
71
+ }
72
+ </script>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <FloatingMenu
3
+ v-if="floatingMenuButtons"
4
+ :tippy-options="{ duration: 100 }"
5
+ :editor="editor"
6
+ class="flex"
7
+ >
8
+ <button
9
+ v-for="button in floatingMenuButtons"
10
+ :key="button.label"
11
+ class="flex rounded p-1 text-gray-800 transition-colors"
12
+ :class="button.isActive(editor) ? 'bg-gray-100' : 'hover:bg-gray-100'"
13
+ @click="() => button.action(editor)"
14
+ :title="button.label"
15
+ >
16
+ <component v-if="button.icon" :is="button.icon" class="h-4 w-4" />
17
+ <span class="inline-block h-4 min-w-[1rem] text-sm leading-4" v-else>
18
+ {{ button.text }}
19
+ </span>
20
+ </button>
21
+ </FloatingMenu>
22
+ </template>
23
+ <script>
24
+ import { FloatingMenu } from '@tiptap/vue-3'
25
+ import { createEditorButton } from './utils'
26
+
27
+ export default {
28
+ name: 'TextEditorFloatingMenu',
29
+ props: ['buttons'],
30
+ components: { FloatingMenu },
31
+ inject: ['editor'],
32
+ computed: {
33
+ floatingMenuButtons() {
34
+ if (!this.buttons) return false
35
+
36
+ let buttons
37
+ if (Array.isArray(this.buttons)) {
38
+ buttons = this.buttons
39
+ } else {
40
+ buttons = [
41
+ 'Paragraph',
42
+ 'Heading 2',
43
+ 'Heading 3',
44
+ 'Bullet List',
45
+ 'Numbered List',
46
+ 'Blockquote',
47
+ 'Code',
48
+ 'Horizontal Rule',
49
+ ]
50
+ }
51
+ return buttons.map(createEditorButton)
52
+ },
53
+ },
54
+ }
55
+ </script>