pimelon-ui 0.0.57 → 0.0.84
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/package.json +5 -2
- package/src/components/Autocomplete.vue +51 -21
- package/src/components/Avatar.vue +1 -0
- package/src/components/Badge.vue +15 -19
- package/src/components/Button.vue +4 -0
- package/src/components/Dialog.vue +29 -4
- package/src/components/Dropdown.vue +15 -10
- package/src/components/ErrorMessage.vue +10 -1
- package/src/components/Input.vue +77 -47
- package/src/components/TextEditor/InsertImage.vue +8 -6
- package/src/components/TextEditor/InsertLink.vue +67 -0
- package/src/components/TextEditor/InsertVideo.vue +94 -0
- package/src/components/TextEditor/MentionList.vue +17 -15
- package/src/components/TextEditor/Menu.vue +31 -71
- package/src/components/TextEditor/TextEditor.vue +66 -156
- package/src/components/TextEditor/TextEditorBubbleMenu.vue +69 -0
- package/src/components/TextEditor/TextEditorFixedMenu.vue +71 -0
- package/src/components/TextEditor/TextEditorFloatingMenu.vue +55 -0
- package/src/components/TextEditor/commands.js +12 -2
- package/src/components/TextEditor/icons/video-add-line.vue +14 -0
- package/src/components/TextEditor/index.js +4 -0
- package/src/components/TextEditor/utils.js +11 -0
- package/src/components/TextEditor/video-extension.js +60 -0
- package/src/components/Toast.vue +1 -1
- package/src/directives/onOutsideClick.js +17 -11
- package/src/directives/visibility.js +24 -0
- package/src/index.js +2 -1
- package/src/resources/documentResource.js +192 -0
- package/src/resources/index.js +3 -0
- package/src/resources/listResource.js +300 -0
- package/src/resources/local.js +10 -0
- package/src/resources/plugin.js +111 -0
- package/src/resources/resources.js +194 -0
- package/src/utils/markdown.js +29 -0
- package/src/utils/plugin.js +2 -2
- package/src/utils/socketio.js +1 -1
- package/src/utils/tailwind.config.js +7 -0
- package/src/utils/resources.js +0 -661
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pimelon-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.84",
|
|
4
4
|
"description": "A set of components and utilities for rapid UI development",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "npx prettier --check ./src",
|
|
8
8
|
"prettier": "npx prettier -w ./src",
|
|
9
9
|
"prepare": "husky install",
|
|
10
|
-
"bump-and-release": "yarn version --patch && git push && git push --tags"
|
|
10
|
+
"bump-and-release": "git pull --rebase origin main && yarn version --patch && git push && git push --tags"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"src"
|
|
@@ -33,10 +33,13 @@
|
|
|
33
33
|
"@tiptap/extension-table-row": "^2.0.0-beta.22",
|
|
34
34
|
"@tiptap/extension-text-align": "^2.0.0-beta.31",
|
|
35
35
|
"@tiptap/starter-kit": "^2.0.0-beta.191",
|
|
36
|
+
"@tiptap/suggestion": "^2.0.0-beta.195",
|
|
36
37
|
"@tiptap/vue-3": "^2.0.0-beta.96",
|
|
37
38
|
"autoprefixer": "^10.4.2",
|
|
38
39
|
"feather-icons": "^4.28.0",
|
|
40
|
+
"idb-keyval": "^6.2.0",
|
|
39
41
|
"postcss": "^8.4.5",
|
|
42
|
+
"showdown": "^2.1.0",
|
|
40
43
|
"socket.io-client": "^4.5.1",
|
|
41
44
|
"tailwindcss": "^3.0.12",
|
|
42
45
|
"tippy.js": "^6.3.7"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
</template>
|
|
32
32
|
<template #body>
|
|
33
33
|
<ComboboxOptions
|
|
34
|
-
class="max-h-[
|
|
34
|
+
class="max-h-[15rem] overflow-y-auto rounded-md rounded-t-none bg-white px-1.5 pb-1.5 shadow-md"
|
|
35
35
|
static
|
|
36
36
|
v-show="isComboboxOpen"
|
|
37
37
|
>
|
|
@@ -52,24 +52,36 @@
|
|
|
52
52
|
/>
|
|
53
53
|
<Button icon="x" @click="selectedValue = null" />
|
|
54
54
|
</div>
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
:value="option"
|
|
60
|
-
v-slot="{ active, selected }"
|
|
55
|
+
<div
|
|
56
|
+
v-for="group in groups"
|
|
57
|
+
:key="group.key"
|
|
58
|
+
v-show="group.items.length > 0"
|
|
61
59
|
>
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
<div
|
|
61
|
+
v-if="group.group && !group.hideLabel"
|
|
62
|
+
class="px-2 py-1 text-xs font-semibold uppercase tracking-wider text-gray-500"
|
|
63
|
+
>
|
|
64
|
+
{{ group.group }}
|
|
65
|
+
</div>
|
|
66
|
+
<ComboboxOption
|
|
67
|
+
as="template"
|
|
68
|
+
v-for="option in group.items"
|
|
69
|
+
:key="option.value"
|
|
70
|
+
:value="option"
|
|
71
|
+
v-slot="{ active, selected }"
|
|
67
72
|
>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
<li
|
|
74
|
+
:class="[
|
|
75
|
+
'rounded-md px-2.5 py-1.5 text-base',
|
|
76
|
+
{ 'bg-gray-100': active },
|
|
77
|
+
]"
|
|
78
|
+
>
|
|
79
|
+
{{ option.label }}
|
|
80
|
+
</li>
|
|
81
|
+
</ComboboxOption>
|
|
82
|
+
</div>
|
|
71
83
|
<li
|
|
72
|
-
v-if="
|
|
84
|
+
v-if="groups.length == 0"
|
|
73
85
|
class="rounded-md px-2.5 py-1.5 text-base text-gray-600"
|
|
74
86
|
>
|
|
75
87
|
No results found
|
|
@@ -119,11 +131,31 @@ export default {
|
|
|
119
131
|
this.$emit(this.valuePropPassed ? 'change' : 'update:modelValue', val)
|
|
120
132
|
},
|
|
121
133
|
},
|
|
122
|
-
|
|
134
|
+
groups() {
|
|
135
|
+
if (!this.options || this.options.length == 0) return []
|
|
136
|
+
|
|
137
|
+
let groups = this.options[0]?.group
|
|
138
|
+
? this.options
|
|
139
|
+
: [{ group: '', items: this.options }]
|
|
140
|
+
|
|
141
|
+
return groups
|
|
142
|
+
.map((group, i) => {
|
|
143
|
+
return {
|
|
144
|
+
key: i,
|
|
145
|
+
group: group.group,
|
|
146
|
+
hideLabel: group.hideLabel || false,
|
|
147
|
+
items: this.filterOptions(group.items),
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
.filter((group) => group.items.length > 0)
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
methods: {
|
|
154
|
+
filterOptions(options) {
|
|
123
155
|
if (!this.query) {
|
|
124
|
-
return
|
|
156
|
+
return options
|
|
125
157
|
}
|
|
126
|
-
return
|
|
158
|
+
return options.filter((option) => {
|
|
127
159
|
let searchTexts = [option.label, option.value]
|
|
128
160
|
return searchTexts.some((text) =>
|
|
129
161
|
(text || '')
|
|
@@ -133,8 +165,6 @@ export default {
|
|
|
133
165
|
)
|
|
134
166
|
})
|
|
135
167
|
},
|
|
136
|
-
},
|
|
137
|
-
methods: {
|
|
138
168
|
displayValue(option) {
|
|
139
169
|
if (typeof option === 'string') {
|
|
140
170
|
return option
|
package/src/components/Badge.vue
CHANGED
|
@@ -7,29 +7,28 @@
|
|
|
7
7
|
</span>
|
|
8
8
|
</template>
|
|
9
9
|
<script>
|
|
10
|
+
const DEFAULT_COLOR_MAP = {
|
|
11
|
+
Pending: 'yellow',
|
|
12
|
+
Running: 'yellow',
|
|
13
|
+
Success: 'green',
|
|
14
|
+
Failure: 'red',
|
|
15
|
+
Active: 'green',
|
|
16
|
+
Broken: 'red',
|
|
17
|
+
Updating: 'blue',
|
|
18
|
+
Rejected: 'red',
|
|
19
|
+
Published: 'green',
|
|
20
|
+
Approved: 'green',
|
|
21
|
+
}
|
|
22
|
+
|
|
10
23
|
export default {
|
|
11
24
|
name: 'Badge',
|
|
12
25
|
props: ['color', 'status', 'colorMap'],
|
|
13
|
-
data: {
|
|
14
|
-
defaultColorMap: {
|
|
15
|
-
Pending: 'yellow',
|
|
16
|
-
Running: 'yellow',
|
|
17
|
-
Success: 'green',
|
|
18
|
-
Failure: 'red',
|
|
19
|
-
Active: 'green',
|
|
20
|
-
Broken: 'red',
|
|
21
|
-
Updating: 'blue',
|
|
22
|
-
Rejected: 'red',
|
|
23
|
-
Published: 'green',
|
|
24
|
-
Approved: 'green',
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
26
|
computed: {
|
|
28
27
|
classes() {
|
|
29
28
|
let color = this.getBadgeColor()
|
|
30
29
|
|
|
31
30
|
let cssClasses = {
|
|
32
|
-
gray: 'text-gray-700 bg-gray-
|
|
31
|
+
gray: 'text-gray-700 bg-gray-100',
|
|
33
32
|
green: 'text-green-700 bg-green-50',
|
|
34
33
|
red: 'text-red-700 bg-red-50',
|
|
35
34
|
yellow: 'text-yellow-700 bg-yellow-50',
|
|
@@ -46,10 +45,7 @@ export default {
|
|
|
46
45
|
return color
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
let statusColorMap = Object.assign(
|
|
50
|
-
this.defaultColorMap,
|
|
51
|
-
this.colorMap || {}
|
|
52
|
-
)
|
|
48
|
+
let statusColorMap = Object.assign(DEFAULT_COLOR_MAP, this.colorMap || {})
|
|
53
49
|
color = statusColorMap[this.status] || 'gray'
|
|
54
50
|
|
|
55
51
|
return color
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
:class="buttonClasses"
|
|
5
5
|
@click="handleClick"
|
|
6
6
|
:disabled="isDisabled"
|
|
7
|
+
:aria-label="ariaLabel"
|
|
7
8
|
>
|
|
8
9
|
<LoadingIndicator
|
|
9
10
|
v-if="loading"
|
|
@@ -136,6 +137,9 @@ export default {
|
|
|
136
137
|
isDisabled() {
|
|
137
138
|
return this.disabled || this.loading
|
|
138
139
|
},
|
|
140
|
+
ariaLabel() {
|
|
141
|
+
return this.icon ? this.label : null
|
|
142
|
+
},
|
|
139
143
|
},
|
|
140
144
|
methods: {
|
|
141
145
|
handleClick() {
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
@close="open = false"
|
|
11
11
|
>
|
|
12
12
|
<div
|
|
13
|
-
class="flex min-h-screen flex-col items-center
|
|
13
|
+
class="flex min-h-screen flex-col items-center px-4 pt-4 pb-20 text-center"
|
|
14
|
+
:class="dialogPositionClasses"
|
|
14
15
|
>
|
|
15
16
|
<TransitionChild
|
|
16
17
|
as="template"
|
|
@@ -36,7 +37,20 @@
|
|
|
36
37
|
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
|
37
38
|
>
|
|
38
39
|
<div
|
|
39
|
-
class="my-8 inline-block w-full
|
|
40
|
+
class="my-8 inline-block w-full transform overflow-hidden rounded-lg bg-white text-left align-middle shadow-xl transition-all"
|
|
41
|
+
:class="{
|
|
42
|
+
'max-w-7xl': options.size === '7xl',
|
|
43
|
+
'max-w-6xl': options.size === '6xl',
|
|
44
|
+
'max-w-5xl': options.size === '5xl',
|
|
45
|
+
'max-w-4xl': options.size === '4xl',
|
|
46
|
+
'max-w-3xl': options.size === '3xl',
|
|
47
|
+
'max-w-2xl': options.size === '2xl',
|
|
48
|
+
'max-w-xl': options.size === 'xl',
|
|
49
|
+
'max-w-md': options.size === 'md',
|
|
50
|
+
'max-w-lg': options.size === 'lg' || !options.size,
|
|
51
|
+
'max-w-sm': options.size === 'sm',
|
|
52
|
+
'max-w-xs': options.size === 'xs',
|
|
53
|
+
}"
|
|
40
54
|
>
|
|
41
55
|
<slot name="body">
|
|
42
56
|
<slot name="body-main">
|
|
@@ -76,7 +90,10 @@
|
|
|
76
90
|
</DialogTitle>
|
|
77
91
|
|
|
78
92
|
<slot name="body-content">
|
|
79
|
-
<p
|
|
93
|
+
<p
|
|
94
|
+
class="text-base text-gray-600"
|
|
95
|
+
v-if="options.message"
|
|
96
|
+
>
|
|
80
97
|
{{ options.message }}
|
|
81
98
|
</p>
|
|
82
99
|
</slot>
|
|
@@ -118,7 +135,8 @@ import {
|
|
|
118
135
|
TransitionChild,
|
|
119
136
|
TransitionRoot,
|
|
120
137
|
} from '@headlessui/vue'
|
|
121
|
-
import
|
|
138
|
+
import Button from './Button.vue'
|
|
139
|
+
import FeatherIcon from './FeatherIcon.vue'
|
|
122
140
|
|
|
123
141
|
export default {
|
|
124
142
|
name: 'Dialog',
|
|
@@ -187,6 +205,13 @@ export default {
|
|
|
187
205
|
}
|
|
188
206
|
return icon
|
|
189
207
|
},
|
|
208
|
+
dialogPositionClasses() {
|
|
209
|
+
let position = this.options?.position || 'center'
|
|
210
|
+
return {
|
|
211
|
+
'justify-center': position === 'center',
|
|
212
|
+
'pt-[20vh]': position === 'top',
|
|
213
|
+
}
|
|
214
|
+
},
|
|
190
215
|
},
|
|
191
216
|
}
|
|
192
217
|
</script>
|
|
@@ -42,15 +42,18 @@
|
|
|
42
42
|
]"
|
|
43
43
|
@click="item.onClick"
|
|
44
44
|
>
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
<component :is="item.component" v-if="item.component" />
|
|
46
|
+
<template v-else>
|
|
47
|
+
<FeatherIcon
|
|
48
|
+
v-if="item.icon"
|
|
49
|
+
:name="item.icon"
|
|
50
|
+
class="mr-2 h-4 w-4 flex-shrink-0 text-gray-500"
|
|
51
|
+
aria-hidden="true"
|
|
52
|
+
/>
|
|
53
|
+
<span class="whitespace-nowrap">
|
|
54
|
+
{{ item.label }}
|
|
55
|
+
</span>
|
|
56
|
+
</template>
|
|
54
57
|
</button>
|
|
55
58
|
</MenuItem>
|
|
56
59
|
</div>
|
|
@@ -61,7 +64,7 @@
|
|
|
61
64
|
|
|
62
65
|
<script>
|
|
63
66
|
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
|
|
64
|
-
import
|
|
67
|
+
import FeatherIcon from './FeatherIcon.vue'
|
|
65
68
|
|
|
66
69
|
export default {
|
|
67
70
|
name: 'NewDropdown',
|
|
@@ -79,10 +82,12 @@ export default {
|
|
|
79
82
|
if (!onClick && option.route && this.$router) {
|
|
80
83
|
onClick = () => this.$router.push(option.route)
|
|
81
84
|
}
|
|
85
|
+
|
|
82
86
|
return {
|
|
83
87
|
label: option.label,
|
|
84
88
|
icon: option.icon,
|
|
85
89
|
group: option.group,
|
|
90
|
+
component: option.component,
|
|
86
91
|
onClick,
|
|
87
92
|
}
|
|
88
93
|
},
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
v-if="message"
|
|
4
4
|
class="whitespace-pre-line text-sm text-red-600"
|
|
5
5
|
role="alert"
|
|
6
|
-
v-html="
|
|
6
|
+
v-html="errorMessage"
|
|
7
7
|
></div>
|
|
8
8
|
</template>
|
|
9
9
|
|
|
@@ -11,5 +11,14 @@
|
|
|
11
11
|
export default {
|
|
12
12
|
name: 'ErrorMessage',
|
|
13
13
|
props: ['message'],
|
|
14
|
+
computed: {
|
|
15
|
+
errorMessage() {
|
|
16
|
+
if (!this.message) return ''
|
|
17
|
+
if (this.message instanceof Error) {
|
|
18
|
+
return this.message.messages || this.message.message
|
|
19
|
+
}
|
|
20
|
+
return this.message
|
|
21
|
+
},
|
|
22
|
+
},
|
|
14
23
|
}
|
|
15
24
|
</script>
|
package/src/components/Input.vue
CHANGED
|
@@ -6,55 +6,70 @@
|
|
|
6
6
|
>
|
|
7
7
|
{{ label }}
|
|
8
8
|
</span>
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
type
|
|
13
|
-
)
|
|
14
|
-
"
|
|
15
|
-
v-bind="inputAttributes"
|
|
16
|
-
class="border-gray-400 placeholder-gray-500"
|
|
17
|
-
ref="input"
|
|
18
|
-
:class="[
|
|
19
|
-
{
|
|
20
|
-
'form-input block w-full': type != 'checkbox',
|
|
21
|
-
'form-checkbox': type == 'checkbox',
|
|
22
|
-
},
|
|
23
|
-
inputClass,
|
|
24
|
-
]"
|
|
25
|
-
:type="type || 'text'"
|
|
26
|
-
:disabled="disabled"
|
|
27
|
-
:placeholder="placeholder"
|
|
28
|
-
:value="passedInputValue"
|
|
29
|
-
/>
|
|
30
|
-
<textarea
|
|
31
|
-
v-if="type === 'textarea'"
|
|
32
|
-
v-bind="inputAttributes"
|
|
33
|
-
:placeholder="placeholder"
|
|
34
|
-
class="placeholder-gray-500"
|
|
35
|
-
:class="['form-textarea block w-full resize-none', inputClass]"
|
|
36
|
-
ref="input"
|
|
37
|
-
:value="passedInputValue"
|
|
38
|
-
:disabled="disabled"
|
|
39
|
-
:rows="rows || 3"
|
|
40
|
-
></textarea>
|
|
41
|
-
<select
|
|
42
|
-
v-bind="inputAttributes"
|
|
43
|
-
class="form-select block w-full"
|
|
44
|
-
ref="input"
|
|
45
|
-
v-if="type === 'select'"
|
|
46
|
-
:disabled="disabled"
|
|
9
|
+
<div
|
|
10
|
+
class="relative flex"
|
|
11
|
+
:class="{ 'items-center': isNormalInput || type == 'select' }"
|
|
47
12
|
>
|
|
48
|
-
<
|
|
49
|
-
v-
|
|
50
|
-
:
|
|
51
|
-
|
|
52
|
-
:
|
|
53
|
-
|
|
13
|
+
<FeatherIcon
|
|
14
|
+
v-if="iconLeft && type != 'checkbox'"
|
|
15
|
+
:name="iconLeft"
|
|
16
|
+
class="absolute mx-2 h-4 w-4 text-gray-600"
|
|
17
|
+
:class="{ 'mt-2': type == 'textarea' }"
|
|
18
|
+
/>
|
|
19
|
+
<input
|
|
20
|
+
v-if="isNormalInput"
|
|
21
|
+
v-bind="inputAttributes"
|
|
22
|
+
class="border-gray-400 placeholder-gray-500"
|
|
23
|
+
ref="input"
|
|
24
|
+
:class="[
|
|
25
|
+
{
|
|
26
|
+
'form-input block w-full': type != 'checkbox',
|
|
27
|
+
'form-checkbox': type == 'checkbox',
|
|
28
|
+
'pl-8': iconLeft && type != 'checkbox',
|
|
29
|
+
},
|
|
30
|
+
inputClass,
|
|
31
|
+
]"
|
|
32
|
+
:type="type || 'text'"
|
|
33
|
+
:disabled="disabled"
|
|
34
|
+
:placeholder="placeholder"
|
|
35
|
+
:value="passedInputValue"
|
|
36
|
+
/>
|
|
37
|
+
<textarea
|
|
38
|
+
v-if="type === 'textarea'"
|
|
39
|
+
v-bind="inputAttributes"
|
|
40
|
+
:placeholder="placeholder"
|
|
41
|
+
class="placeholder-gray-500"
|
|
42
|
+
:class="[
|
|
43
|
+
'form-textarea block w-full resize-none',
|
|
44
|
+
inputClass,
|
|
45
|
+
{
|
|
46
|
+
'pl-8': iconLeft,
|
|
47
|
+
},
|
|
48
|
+
]"
|
|
49
|
+
ref="input"
|
|
50
|
+
:value="passedInputValue"
|
|
51
|
+
:disabled="disabled"
|
|
52
|
+
:rows="rows || 3"
|
|
53
|
+
></textarea>
|
|
54
|
+
<select
|
|
55
|
+
v-if="type === 'select'"
|
|
56
|
+
v-bind="inputAttributes"
|
|
57
|
+
class="form-select block w-full"
|
|
58
|
+
:class="{ 'pl-8': iconLeft }"
|
|
59
|
+
ref="input"
|
|
60
|
+
:disabled="disabled"
|
|
54
61
|
>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
<option
|
|
63
|
+
v-for="option in selectOptions"
|
|
64
|
+
:key="option.value"
|
|
65
|
+
:value="option.value"
|
|
66
|
+
:disabled="option.disabled || false"
|
|
67
|
+
:selected="passedInputValue === option.value"
|
|
68
|
+
>
|
|
69
|
+
{{ option.label }}
|
|
70
|
+
</option>
|
|
71
|
+
</select>
|
|
72
|
+
</div>
|
|
58
73
|
<span
|
|
59
74
|
v-if="label && type == 'checkbox'"
|
|
60
75
|
class="ml-2 inline-block text-base leading-4"
|
|
@@ -66,11 +81,13 @@
|
|
|
66
81
|
|
|
67
82
|
<script>
|
|
68
83
|
import { debounce } from 'pimelon-ui'
|
|
84
|
+
import FeatherIcon from './FeatherIcon.vue'
|
|
69
85
|
|
|
70
86
|
export default {
|
|
71
87
|
name: 'Input',
|
|
72
88
|
inheritAttrs: false,
|
|
73
89
|
expose: ['getInputValue'],
|
|
90
|
+
components: { FeatherIcon },
|
|
74
91
|
props: {
|
|
75
92
|
label: {
|
|
76
93
|
type: String,
|
|
@@ -116,6 +133,9 @@ export default {
|
|
|
116
133
|
placeholder: {
|
|
117
134
|
type: String,
|
|
118
135
|
},
|
|
136
|
+
iconLeft: {
|
|
137
|
+
type: String,
|
|
138
|
+
},
|
|
119
139
|
},
|
|
120
140
|
emits: ['input', 'change', 'update:modelValue'],
|
|
121
141
|
methods: {
|
|
@@ -173,6 +193,16 @@ export default {
|
|
|
173
193
|
})
|
|
174
194
|
.filter(Boolean)
|
|
175
195
|
},
|
|
196
|
+
isNormalInput() {
|
|
197
|
+
return [
|
|
198
|
+
'text',
|
|
199
|
+
'number',
|
|
200
|
+
'checkbox',
|
|
201
|
+
'email',
|
|
202
|
+
'password',
|
|
203
|
+
'date',
|
|
204
|
+
].includes(this.type)
|
|
205
|
+
},
|
|
176
206
|
},
|
|
177
207
|
}
|
|
178
208
|
</script>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<slot v-bind="{ openDialog
|
|
2
|
+
<slot v-bind="{ onClick: openDialog }"></slot>
|
|
3
3
|
<Dialog
|
|
4
4
|
:options="{ title: 'Add Image' }"
|
|
5
5
|
v-model="addImageDialog.show"
|
|
6
|
-
@after-leave="
|
|
6
|
+
@after-leave="reset"
|
|
7
7
|
>
|
|
8
8
|
<template #body-content>
|
|
9
9
|
<label
|
|
@@ -29,12 +29,14 @@
|
|
|
29
29
|
<Button appearance="primary" @click="addImage(addImageDialog.url)">
|
|
30
30
|
Insert Image
|
|
31
31
|
</Button>
|
|
32
|
+
<Button @click="reset"> Cancel </Button>
|
|
32
33
|
</template>
|
|
33
34
|
</Dialog>
|
|
34
35
|
</template>
|
|
35
36
|
<script>
|
|
36
37
|
import fileToBase64 from '../../utils/file-to-base64'
|
|
37
38
|
import Dialog from '../Dialog.vue'
|
|
39
|
+
import Button from '../Button.vue'
|
|
38
40
|
|
|
39
41
|
export default {
|
|
40
42
|
name: 'InsertImage',
|
|
@@ -45,7 +47,7 @@ export default {
|
|
|
45
47
|
addImageDialog: { url: '', file: null, show: false },
|
|
46
48
|
}
|
|
47
49
|
},
|
|
48
|
-
components: { Dialog },
|
|
50
|
+
components: { Button, Dialog },
|
|
49
51
|
methods: {
|
|
50
52
|
openDialog() {
|
|
51
53
|
this.addImageDialog.show = true
|
|
@@ -62,10 +64,10 @@ export default {
|
|
|
62
64
|
},
|
|
63
65
|
addImage(src) {
|
|
64
66
|
this.editor.chain().focus().setImage({ src }).run()
|
|
65
|
-
this.
|
|
67
|
+
this.reset()
|
|
66
68
|
},
|
|
67
|
-
|
|
68
|
-
this.addImageDialog =
|
|
69
|
+
reset() {
|
|
70
|
+
this.addImageDialog = this.$options.data().addImageDialog
|
|
69
71
|
},
|
|
70
72
|
},
|
|
71
73
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<slot v-bind="{ onClick: openDialog }"></slot>
|
|
3
|
+
<Dialog
|
|
4
|
+
:options="{ title: 'Set Link' }"
|
|
5
|
+
v-model="setLinkDialog.show"
|
|
6
|
+
@after-leave="reset"
|
|
7
|
+
>
|
|
8
|
+
<template #body-content>
|
|
9
|
+
<Input
|
|
10
|
+
type="text"
|
|
11
|
+
label="URL"
|
|
12
|
+
v-model="setLinkDialog.url"
|
|
13
|
+
@keydown.enter="(e) => setLink(e.target.value)"
|
|
14
|
+
/>
|
|
15
|
+
</template>
|
|
16
|
+
<template #actions>
|
|
17
|
+
<Button appearance="primary" @click="setLink(setLinkDialog.url)">
|
|
18
|
+
Save
|
|
19
|
+
</Button>
|
|
20
|
+
</template>
|
|
21
|
+
</Dialog>
|
|
22
|
+
</template>
|
|
23
|
+
<script>
|
|
24
|
+
import Dialog from '../Dialog.vue'
|
|
25
|
+
import Button from '../Button.vue'
|
|
26
|
+
import Input from '../Input.vue'
|
|
27
|
+
|
|
28
|
+
export default {
|
|
29
|
+
name: 'InsertLink',
|
|
30
|
+
props: ['editor'],
|
|
31
|
+
components: { Button, Input, Dialog },
|
|
32
|
+
data() {
|
|
33
|
+
return {
|
|
34
|
+
setLinkDialog: { url: '', show: false },
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
methods: {
|
|
38
|
+
openDialog() {
|
|
39
|
+
let existingURL = this.editor.getAttributes('link').href
|
|
40
|
+
if (existingURL) {
|
|
41
|
+
this.setLinkDialog.url = existingURL
|
|
42
|
+
}
|
|
43
|
+
this.setLinkDialog.show = true
|
|
44
|
+
},
|
|
45
|
+
setLink(url) {
|
|
46
|
+
// empty
|
|
47
|
+
if (url === '') {
|
|
48
|
+
this.editor.chain().focus().extendMarkRange('link').unsetLink().run()
|
|
49
|
+
} else {
|
|
50
|
+
// update link
|
|
51
|
+
this.editor
|
|
52
|
+
.chain()
|
|
53
|
+
.focus()
|
|
54
|
+
.extendMarkRange('link')
|
|
55
|
+
.setLink({ href: url })
|
|
56
|
+
.run()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.setLinkDialog.show = false
|
|
60
|
+
this.setLinkDialog.url = ''
|
|
61
|
+
},
|
|
62
|
+
reset() {
|
|
63
|
+
this.setLinkDialog = this.$options.data().setLinkDialog
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
</script>
|