@ditojs/admin 2.9.1 → 2.9.3
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/dist/dito-admin.es.js +1446 -1424
- package/dist/dito-admin.umd.js +6 -6
- package/dist/style.css +1 -1
- package/package.json +11 -11
- package/src/DitoAdmin.js +2 -2
- package/src/components/DitoClipboard.vue +7 -3
- package/src/components/DitoHeader.vue +3 -101
- package/src/components/DitoNotifications.vue +159 -0
- package/src/components/DitoRoot.vue +4 -52
- package/src/components/DitoSchema.vue +1 -1
- package/src/components/DitoSpinner.vue +46 -43
- package/src/components/DitoTrail.vue +119 -0
- package/src/components/DitoView.vue +9 -5
- package/src/components/index.js +3 -0
- package/src/mixins/RouteMixin.js +3 -3
- package/src/mixins/SourceMixin.js +14 -6
- package/src/styles/_settings.scss +1 -0
- package/src/styles/style.scss +0 -1
- package/src/styles/_notifications.scss +0 -54
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dito.js Admin is a schema based admin interface for Dito.js Server, featuring auto-generated views and forms and built with Vue.js",
|
|
6
6
|
"repository": "https://github.com/ditojs/dito/tree/master/packages/admin",
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"not ie_mob > 0"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@ditojs/ui": "^2.9.
|
|
36
|
+
"@ditojs/ui": "^2.9.3",
|
|
37
37
|
"@ditojs/utils": "^2.9.0",
|
|
38
|
-
"@kyvg/vue3-notification": "^2.9.
|
|
38
|
+
"@kyvg/vue3-notification": "^2.9.1",
|
|
39
39
|
"@lk77/vue3-color": "^3.0.6",
|
|
40
40
|
"@tiptap/core": "^2.0.3",
|
|
41
41
|
"@tiptap/extension-blockquote": "^2.0.3",
|
|
@@ -62,28 +62,28 @@
|
|
|
62
62
|
"codeflask": "^1.4.1",
|
|
63
63
|
"filesize": "^10.0.7",
|
|
64
64
|
"filesize-parser": "^1.5.0",
|
|
65
|
-
"focus-trap": "^7.4.
|
|
65
|
+
"focus-trap": "^7.4.1",
|
|
66
66
|
"nanoid": "^4.0.2",
|
|
67
67
|
"sortablejs": "^1.15.0",
|
|
68
68
|
"tinycolor2": "^1.6.0",
|
|
69
69
|
"tippy.js": "^6.3.7",
|
|
70
70
|
"type-fest": "^3.10.0",
|
|
71
|
-
"vue": "^3.2
|
|
72
|
-
"vue-multiselect": "^3.0.0-beta.
|
|
73
|
-
"vue-router": "^4.
|
|
71
|
+
"vue": "^3.3.2",
|
|
72
|
+
"vue-multiselect": "^3.0.0-beta.2",
|
|
73
|
+
"vue-router": "^4.2.0",
|
|
74
74
|
"vue-upload-component": "^3.1.8"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@ditojs/build": "^2.9.0",
|
|
78
|
-
"@vitejs/plugin-vue": "^4.2.
|
|
79
|
-
"@vue/compiler-sfc": "^3.2
|
|
78
|
+
"@vitejs/plugin-vue": "^4.2.3",
|
|
79
|
+
"@vue/compiler-sfc": "^3.3.2",
|
|
80
80
|
"pug": "^3.0.2",
|
|
81
81
|
"sass": "1.62.1",
|
|
82
82
|
"typescript": "^5.0.4",
|
|
83
|
-
"vite": "^4.3.
|
|
83
|
+
"vite": "^4.3.7"
|
|
84
84
|
},
|
|
85
85
|
"types": "types",
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "8855fb3de01a12a456a622cc17c0c03ffdbf7eab",
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "vite build",
|
|
89
89
|
"watch": "yarn build --mode 'development' --watch",
|
package/src/DitoAdmin.js
CHANGED
|
@@ -199,8 +199,8 @@ export default class DitoAdmin {
|
|
|
199
199
|
app.config.errorHandler = console.error
|
|
200
200
|
|
|
201
201
|
app.use(VueNotifications, {
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
componentName: 'VueNotifications',
|
|
203
|
+
name: 'notify'
|
|
204
204
|
})
|
|
205
205
|
|
|
206
206
|
app.directive('resize', ResizeDirective)
|
|
@@ -82,6 +82,11 @@ export default DitoComponent.component('DitoClipboard', {
|
|
|
82
82
|
},
|
|
83
83
|
|
|
84
84
|
methods: {
|
|
85
|
+
checkClipboardData(clipboardData) {
|
|
86
|
+
const { $schema, ...data } = clipboardData || {}
|
|
87
|
+
return $schema === this.schema.name ? data : null
|
|
88
|
+
},
|
|
89
|
+
|
|
85
90
|
async getClipboardData(report) {
|
|
86
91
|
// Use the internal clipboard as fallback.
|
|
87
92
|
let { clipboardData } = this.appState
|
|
@@ -101,12 +106,11 @@ export default DitoComponent.component('DitoClipboard', {
|
|
|
101
106
|
}
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
|
-
|
|
105
|
-
return $schema === this.schema.name ? data : null
|
|
109
|
+
return this.checkClipboardData(clipboardData)
|
|
106
110
|
},
|
|
107
111
|
|
|
108
112
|
async updatePaste() {
|
|
109
|
-
this.pasteEnabled = !!this.appState.clipboardData
|
|
113
|
+
this.pasteEnabled = !!this.checkClipboardData(this.appState.clipboardData)
|
|
110
114
|
if (!this.pasteEnabled && this.appState.agent.chrome) {
|
|
111
115
|
// See if the clipboard content is valid JSON data that is compatible
|
|
112
116
|
// with the current target schema, and only then activate the pasting:
|
|
@@ -1,23 +1,10 @@
|
|
|
1
1
|
<template lang="pug">
|
|
2
2
|
nav.dito-header
|
|
3
|
-
|
|
4
|
-
ul
|
|
5
|
-
li(
|
|
6
|
-
v-for="(component, index) in trail"
|
|
7
|
-
)
|
|
8
|
-
template(
|
|
9
|
-
v-if="index === trail.length - 1"
|
|
10
|
-
)
|
|
11
|
-
span(:class="getBreadcrumbClass(component)")
|
|
12
|
-
| {{ component.breadcrumb }}
|
|
13
|
-
RouterLink.dito-breadcrumb(
|
|
14
|
-
v-else
|
|
15
|
-
:to="component.path"
|
|
16
|
-
)
|
|
17
|
-
span(:class="getBreadcrumbClass(component)")
|
|
18
|
-
| {{ component.breadcrumb }}
|
|
3
|
+
DitoTrail
|
|
19
4
|
DitoSpinner(
|
|
20
5
|
v-if="isLoading"
|
|
6
|
+
:size="spinner?.size"
|
|
7
|
+
:color="spinner?.color"
|
|
21
8
|
)
|
|
22
9
|
//- Teleport target for `.dito-schema-header`:
|
|
23
10
|
.dito-header__teleport
|
|
@@ -26,12 +13,9 @@ nav.dito-header
|
|
|
26
13
|
|
|
27
14
|
<script>
|
|
28
15
|
import DitoComponent from '../DitoComponent.js'
|
|
29
|
-
import DitoSpinner from './DitoSpinner.vue'
|
|
30
16
|
|
|
31
17
|
// @vue/component
|
|
32
18
|
export default DitoComponent.component('DitoHeader', {
|
|
33
|
-
components: { DitoSpinner },
|
|
34
|
-
|
|
35
19
|
props: {
|
|
36
20
|
spinner: {
|
|
37
21
|
type: Object,
|
|
@@ -41,34 +25,6 @@ export default DitoComponent.component('DitoHeader', {
|
|
|
41
25
|
type: Boolean,
|
|
42
26
|
default: false
|
|
43
27
|
}
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
computed: {
|
|
47
|
-
trail() {
|
|
48
|
-
return this.appState.routeComponents.filter(
|
|
49
|
-
component => !!component.routeRecord
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
|
|
54
|
-
created() {
|
|
55
|
-
const {
|
|
56
|
-
size = '8px',
|
|
57
|
-
color = '#999'
|
|
58
|
-
} = this.spinner || {}
|
|
59
|
-
// TODO: This is a hack to set the default props for the DitoSpinner.
|
|
60
|
-
// Pass them on through the template instead!
|
|
61
|
-
const { props } = DitoSpinner
|
|
62
|
-
props.size.default = size
|
|
63
|
-
props.color.default = color
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
methods: {
|
|
67
|
-
getBreadcrumbClass(component) {
|
|
68
|
-
return {
|
|
69
|
-
'dito-dirty': component.isDirty
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
28
|
}
|
|
73
29
|
})
|
|
74
30
|
</script>
|
|
@@ -106,60 +62,6 @@ export default DitoComponent.component('DitoHeader', {
|
|
|
106
62
|
}
|
|
107
63
|
}
|
|
108
64
|
|
|
109
|
-
.dito-trail {
|
|
110
|
-
display: flex;
|
|
111
|
-
box-sizing: border-box;
|
|
112
|
-
height: 3em;
|
|
113
|
-
|
|
114
|
-
ul {
|
|
115
|
-
display: flex;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
li {
|
|
119
|
-
white-space: nowrap;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
a {
|
|
123
|
-
position: relative;
|
|
124
|
-
display: block;
|
|
125
|
-
|
|
126
|
-
$angle: 33deg;
|
|
127
|
-
|
|
128
|
-
&:hover {
|
|
129
|
-
span {
|
|
130
|
-
color: $color-light;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
&::before,
|
|
135
|
-
&::after {
|
|
136
|
-
position: absolute;
|
|
137
|
-
content: '';
|
|
138
|
-
width: 1px;
|
|
139
|
-
height: 0.75em;
|
|
140
|
-
right: -0.25em;
|
|
141
|
-
background: $color-white;
|
|
142
|
-
opacity: 0.5;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
&::before {
|
|
146
|
-
top: 50%;
|
|
147
|
-
transform: rotate($angle);
|
|
148
|
-
transform-origin: top;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
&::after {
|
|
152
|
-
bottom: 50%;
|
|
153
|
-
transform: rotate(-$angle);
|
|
154
|
-
transform-origin: bottom;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.dito-spinner {
|
|
160
|
-
margin-top: $header-padding-ver;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
65
|
.dito-dirty {
|
|
164
66
|
&::after {
|
|
165
67
|
content: '';
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
.dito-notifications
|
|
3
|
+
.dito-header
|
|
4
|
+
span
|
|
5
|
+
.dito-notifications__inner
|
|
6
|
+
VueNotifications(
|
|
7
|
+
ref="notifications"
|
|
8
|
+
classes="dito-notification"
|
|
9
|
+
position=""
|
|
10
|
+
width=""
|
|
11
|
+
)
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script>
|
|
15
|
+
import DitoComponent from '../DitoComponent.js'
|
|
16
|
+
import { asArray, stripTags } from '@ditojs/utils'
|
|
17
|
+
|
|
18
|
+
// @vue/component
|
|
19
|
+
export default DitoComponent.component('DitoNotifications', {
|
|
20
|
+
notifications() {
|
|
21
|
+
return this.isMounted && this.$refs.notifications
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
methods: {
|
|
25
|
+
notify({ type = 'info', title, text } = {}) {
|
|
26
|
+
title ||= (
|
|
27
|
+
{
|
|
28
|
+
warning: 'Warning',
|
|
29
|
+
error: 'Error',
|
|
30
|
+
info: 'Information',
|
|
31
|
+
success: 'Success'
|
|
32
|
+
}[type] ||
|
|
33
|
+
'Notification'
|
|
34
|
+
)
|
|
35
|
+
text = `<p>${
|
|
36
|
+
asArray(text).join('</p> <p>')
|
|
37
|
+
}</p>`.replace(/\n|\r\n|\r/g, '<br>')
|
|
38
|
+
const log = (
|
|
39
|
+
{
|
|
40
|
+
warning: 'warn',
|
|
41
|
+
error: 'error',
|
|
42
|
+
info: 'log',
|
|
43
|
+
success: 'log'
|
|
44
|
+
}[type] ||
|
|
45
|
+
'error'
|
|
46
|
+
)
|
|
47
|
+
// eslint-disable-next-line no-console
|
|
48
|
+
console[log](stripTags(text))
|
|
49
|
+
const { notifications = true } = this.api
|
|
50
|
+
if (notifications) {
|
|
51
|
+
// Calculate display-duration for the notification based on its content
|
|
52
|
+
// and the setting of the `durationFactor` configuration. It defines the
|
|
53
|
+
// amount of milliseconds multiplied with the amount of characters
|
|
54
|
+
// displayed in the notification, plus 40 (40 + title + message):
|
|
55
|
+
const { durationFactor = 20 } = notifications
|
|
56
|
+
const duration = (40 + text.length + title.length) * durationFactor
|
|
57
|
+
this.$notify({ type, title, text, duration })
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
destroyAll() {
|
|
62
|
+
this.notifications.destroyAll()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
<style lang="scss">
|
|
69
|
+
@use 'sass:color';
|
|
70
|
+
@import '../styles/_imports';
|
|
71
|
+
|
|
72
|
+
@mixin type($background) {
|
|
73
|
+
background: color.adjust($background, $lightness: 5%);
|
|
74
|
+
color: $color-white;
|
|
75
|
+
border-left: 12px solid color.adjust($background, $lightness: -10%);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.dito-notifications {
|
|
79
|
+
$notification-width: 300px;
|
|
80
|
+
|
|
81
|
+
flex: 1;
|
|
82
|
+
z-index: $z-index-notifications;
|
|
83
|
+
box-sizing: border-box;
|
|
84
|
+
margin-left: $form-spacing;
|
|
85
|
+
// For the `@container` rule to work:
|
|
86
|
+
container-type: inline-size;
|
|
87
|
+
|
|
88
|
+
.dito-header {
|
|
89
|
+
span {
|
|
90
|
+
padding-left: 0;
|
|
91
|
+
padding-right: 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&__inner {
|
|
96
|
+
position: relative;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.vue-notification-group {
|
|
100
|
+
position: absolute;
|
|
101
|
+
left: 0;
|
|
102
|
+
top: 0;
|
|
103
|
+
width: $notification-width;
|
|
104
|
+
|
|
105
|
+
@container (width < #{$notification-width + $content-padding}) {
|
|
106
|
+
left: unset;
|
|
107
|
+
right: $content-padding;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.vue-notification-wrapper {
|
|
112
|
+
overflow: visible;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.dito-notification {
|
|
116
|
+
padding: 8px;
|
|
117
|
+
margin: $content-padding 0;
|
|
118
|
+
font-size: inherit;
|
|
119
|
+
color: $color-white;
|
|
120
|
+
border-radius: $border-radius;
|
|
121
|
+
box-shadow: $shadow-window;
|
|
122
|
+
|
|
123
|
+
.notification-title {
|
|
124
|
+
font-weight: bold;
|
|
125
|
+
padding-bottom: 8px;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.notification-content {
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
word-break: break-all;
|
|
131
|
+
|
|
132
|
+
p {
|
|
133
|
+
margin: 0;
|
|
134
|
+
|
|
135
|
+
& + p {
|
|
136
|
+
margin-top: 8px;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
&,
|
|
142
|
+
&.info {
|
|
143
|
+
@include type($color-active);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
&.success {
|
|
147
|
+
@include type($color-success);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&.warning {
|
|
151
|
+
@include type($color-warning);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
&.error {
|
|
155
|
+
@include type($color-error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
</style>
|
|
@@ -4,11 +4,6 @@
|
|
|
4
4
|
:data-agent-platform="appState.agent.platform"
|
|
5
5
|
:data-agent-version="appState.agent.versionNumber"
|
|
6
6
|
)
|
|
7
|
-
VueNotifications.dito-notifications(
|
|
8
|
-
ref="notifications"
|
|
9
|
-
position="top right"
|
|
10
|
-
classes="dito-notification"
|
|
11
|
-
)
|
|
12
7
|
Transition(name="dito-drag")
|
|
13
8
|
.dito-drag-overlay(
|
|
14
9
|
v-if="isDraggingFiles"
|
|
@@ -43,12 +38,12 @@
|
|
|
43
38
|
@click="rootComponent.login()"
|
|
44
39
|
)
|
|
45
40
|
span Login
|
|
46
|
-
|
|
41
|
+
DitoNotifications(ref="notifications")
|
|
47
42
|
</template>
|
|
48
43
|
|
|
49
44
|
<script>
|
|
50
45
|
import { delegate as tippyDelegate } from 'tippy.js'
|
|
51
|
-
import {
|
|
46
|
+
import { mapConcurrently } from '@ditojs/utils'
|
|
52
47
|
import DitoComponent from '../DitoComponent.js'
|
|
53
48
|
import DomMixin from '../mixins/DomMixin.js'
|
|
54
49
|
import DitoUser from '../DitoUser.js'
|
|
@@ -90,7 +85,7 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
90
85
|
|
|
91
86
|
computed: {
|
|
92
87
|
notifications() {
|
|
93
|
-
return this.$refs.notifications
|
|
88
|
+
return this.isMounted && this.$refs.notifications
|
|
94
89
|
},
|
|
95
90
|
|
|
96
91
|
isLoading() {
|
|
@@ -239,39 +234,7 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
239
234
|
},
|
|
240
235
|
|
|
241
236
|
notify({ type = 'info', title, text } = {}) {
|
|
242
|
-
title
|
|
243
|
-
{
|
|
244
|
-
warning: 'Warning',
|
|
245
|
-
error: 'Error',
|
|
246
|
-
info: 'Information',
|
|
247
|
-
success: 'Success'
|
|
248
|
-
}[type] ||
|
|
249
|
-
'Notification'
|
|
250
|
-
)
|
|
251
|
-
text = `<p>${
|
|
252
|
-
asArray(text).join('</p> <p>')
|
|
253
|
-
}</p>`.replace(/\n|\r\n|\r/g, '<br>')
|
|
254
|
-
const log = (
|
|
255
|
-
{
|
|
256
|
-
warning: 'warn',
|
|
257
|
-
error: 'error',
|
|
258
|
-
info: 'log',
|
|
259
|
-
success: 'log'
|
|
260
|
-
}[type] ||
|
|
261
|
-
'error'
|
|
262
|
-
)
|
|
263
|
-
// eslint-disable-next-line no-console
|
|
264
|
-
console[log](stripTags(text))
|
|
265
|
-
const { notifications = true } = this.api
|
|
266
|
-
if (notifications) {
|
|
267
|
-
// Calculate display-duration for the notification based on its content
|
|
268
|
-
// and the setting of the `durationFactor` configuration. It defines the
|
|
269
|
-
// amount of milliseconds multiplied with the amount of characters
|
|
270
|
-
// displayed in the notification, plus 40 (40 + title + message):
|
|
271
|
-
const { durationFactor = 20 } = notifications
|
|
272
|
-
const duration = (40 + text.length + title.length) * durationFactor
|
|
273
|
-
this.$notify({ type, title, text, duration })
|
|
274
|
-
}
|
|
237
|
+
this.notifications.notify({ type, title, text })
|
|
275
238
|
},
|
|
276
239
|
|
|
277
240
|
closeNotifications() {
|
|
@@ -509,17 +472,6 @@ function addRoutes(router, routes) {
|
|
|
509
472
|
}
|
|
510
473
|
}
|
|
511
474
|
|
|
512
|
-
.dito-fill {
|
|
513
|
-
flex: 1;
|
|
514
|
-
|
|
515
|
-
.dito-header {
|
|
516
|
-
span {
|
|
517
|
-
padding-left: 0;
|
|
518
|
-
padding-right: 0;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
475
|
.dito-account,
|
|
524
476
|
.dito-login {
|
|
525
477
|
cursor: pointer;
|
|
@@ -757,7 +757,7 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
757
757
|
}
|
|
758
758
|
|
|
759
759
|
&:has(> .dito-schema-content + .dito-edit-buttons) {
|
|
760
|
-
// Display the edit buttons to the right of the schema:
|
|
760
|
+
// Display the inlined edit buttons to the right of the schema:
|
|
761
761
|
display: flex;
|
|
762
762
|
flex-direction: row;
|
|
763
763
|
align-items: stretch;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
<template lang="pug">
|
|
2
2
|
.dito-spinner(
|
|
3
3
|
v-show="loading"
|
|
4
|
+
:style="{ '--color': color, '--size': size, '--margin': margin }"
|
|
4
5
|
)
|
|
5
|
-
|
|
6
|
-
.
|
|
7
|
-
.
|
|
8
|
-
.v-pulse.v-pulse3(:style="[spinnerStyle, spinnerDelay3]")
|
|
6
|
+
.dito-spinner__pulse.dito-spinner__pulse1
|
|
7
|
+
.dito-spinner__pulse.dito-spinner__pulse2
|
|
8
|
+
.dito-spinner__pulse.dito-spinner__pulse3
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
11
|
<script>
|
|
12
|
-
|
|
12
|
+
import DitoComponent from '../DitoComponent.js'
|
|
13
|
+
|
|
14
|
+
// @vue/component
|
|
15
|
+
export default DitoComponent.component('DitoSpinner', {
|
|
13
16
|
props: {
|
|
14
17
|
loading: {
|
|
15
18
|
type: Boolean,
|
|
@@ -17,54 +20,54 @@ export default {
|
|
|
17
20
|
},
|
|
18
21
|
color: {
|
|
19
22
|
type: String,
|
|
20
|
-
default:
|
|
23
|
+
default: null
|
|
21
24
|
},
|
|
22
25
|
size: {
|
|
23
26
|
type: String,
|
|
24
|
-
default:
|
|
27
|
+
default: null
|
|
25
28
|
},
|
|
26
29
|
margin: {
|
|
27
30
|
type: String,
|
|
28
|
-
default:
|
|
29
|
-
},
|
|
30
|
-
radius: {
|
|
31
|
-
type: String,
|
|
32
|
-
default: '100%'
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
data() {
|
|
37
|
-
// TODO: Convert to using only classes
|
|
38
|
-
return {
|
|
39
|
-
spinnerStyle: {
|
|
40
|
-
backgroundColor: this.color,
|
|
41
|
-
width: this.size,
|
|
42
|
-
height: this.size,
|
|
43
|
-
margin: this.margin,
|
|
44
|
-
borderRadius: this.radius,
|
|
45
|
-
display: 'inline-block',
|
|
46
|
-
animationName: 'v-pulseStretchDelay',
|
|
47
|
-
animationDuration: '0.75s',
|
|
48
|
-
animationIterationCount: 'infinite',
|
|
49
|
-
animationTimingFunction: 'cubic-bezier(.2,.68,.18,1.08)',
|
|
50
|
-
animationFillMode: 'both'
|
|
51
|
-
},
|
|
52
|
-
spinnerDelay1: {
|
|
53
|
-
animationDelay: '0.12s'
|
|
54
|
-
},
|
|
55
|
-
spinnerDelay2: {
|
|
56
|
-
animationDelay: '0.24s'
|
|
57
|
-
},
|
|
58
|
-
spinnerDelay3: {
|
|
59
|
-
animationDelay: '0.36s'
|
|
60
|
-
}
|
|
31
|
+
default: null
|
|
61
32
|
}
|
|
62
33
|
}
|
|
63
|
-
}
|
|
34
|
+
})
|
|
64
35
|
</script>
|
|
65
36
|
|
|
66
37
|
<style lang="scss">
|
|
67
|
-
|
|
38
|
+
.dito-spinner {
|
|
39
|
+
--color: #999999;
|
|
40
|
+
--size: 8px;
|
|
41
|
+
--margin: 2px;
|
|
42
|
+
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
|
|
46
|
+
&__pulse {
|
|
47
|
+
display: inline-block;
|
|
48
|
+
background: var(--color);
|
|
49
|
+
width: var(--size);
|
|
50
|
+
height: var(--size);
|
|
51
|
+
margin: var(--margin);
|
|
52
|
+
border-radius: 100%;
|
|
53
|
+
animation: dito-spinner-pulse 0.75s cubic-bezier(0.2, 0.68, 0.18, 1.08) 0s
|
|
54
|
+
infinite both;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&__pulse1 {
|
|
58
|
+
animation-delay: 0.12s;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__pulse2 {
|
|
62
|
+
animation-delay: 0.24s;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&__pulse3 {
|
|
66
|
+
animation-delay: 0.36s;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@keyframes dito-spinner-pulse {
|
|
68
71
|
0%,
|
|
69
72
|
80% {
|
|
70
73
|
transform: scale(1);
|
|
@@ -77,7 +80,7 @@ export default {
|
|
|
77
80
|
}
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
@keyframes
|
|
83
|
+
@keyframes dito-spinner-pulse {
|
|
81
84
|
0%,
|
|
82
85
|
80% {
|
|
83
86
|
transform: scale(1);
|