@ditojs/admin 2.3.1 → 2.4.0
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 +2098 -1961
- package/dist/dito-admin.umd.js +4 -4
- package/dist/style.css +1 -1
- package/package.json +5 -5
- package/src/components/DitoContainer.vue +7 -1
- package/src/components/DitoDialog.vue +1 -0
- package/src/components/DitoHeader.vue +6 -5
- package/src/components/DitoMenu.vue +177 -0
- package/src/components/DitoRoot.vue +112 -5
- package/src/components/DitoSchema.vue +7 -6
- package/src/components/DitoSidebar.vue +11 -49
- package/src/components/DitoTableHead.vue +1 -0
- package/src/components/index.js +1 -0
- package/src/mixins/TypeMixin.js +9 -11
- package/src/styles/_button.scss +4 -4
- package/src/styles/_scroll.scss +0 -1
- package/src/styles/_settings.scss +20 -10
- package/src/types/DitoTypeButton.vue +0 -1
- package/src/types/DitoTypeCheckbox.vue +0 -1
- package/src/types/DitoTypeComputed.vue +0 -1
- package/src/types/DitoTypeMarkup.vue +1 -1
- package/src/types/DitoTypeNumber.vue +0 -1
- package/src/types/DitoTypeProgress.vue +0 -1
- package/src/types/DitoTypeSwitch.vue +0 -1
- package/src/types/DitoTypeText.vue +0 -1
- package/src/types/DitoTypeTextarea.vue +0 -1
- package/src/types/DitoTypeUpload.vue +21 -12
- package/src/utils/schema.js +42 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ditojs/admin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
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,8 +33,8 @@
|
|
|
33
33
|
"not ie_mob > 0"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@ditojs/ui": "^2.
|
|
37
|
-
"@ditojs/utils": "^2.
|
|
36
|
+
"@ditojs/ui": "^2.4.0",
|
|
37
|
+
"@ditojs/utils": "^2.4.0",
|
|
38
38
|
"@kyvg/vue3-notification": "^2.9.0",
|
|
39
39
|
"@lk77/vue3-color": "^3.0.6",
|
|
40
40
|
"@tiptap/core": "^2.0.3",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"vue-upload-component": "^3.1.8"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@ditojs/build": "^2.
|
|
77
|
+
"@ditojs/build": "^2.4.0",
|
|
78
78
|
"@vitejs/plugin-vue": "^4.1.0",
|
|
79
79
|
"@vue/compiler-sfc": "^3.2.47",
|
|
80
80
|
"pug": "^3.0.2",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"vite": "^4.3.1"
|
|
84
84
|
},
|
|
85
85
|
"types": "types",
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "11402f86e31da1b8ebd0a6ea5c984d3abf12d7be",
|
|
87
87
|
"scripts": {
|
|
88
88
|
"build": "vite build",
|
|
89
89
|
"watch": "yarn build --mode 'development' --watch",
|
|
@@ -248,7 +248,7 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
248
248
|
--justify: flex-end;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
&:not(#{$self}--
|
|
251
|
+
&:not(#{$self}--alone-in-row) {
|
|
252
252
|
// Now only apply alignment if there are neighbouring components no the
|
|
253
253
|
// same row that also align.
|
|
254
254
|
// Look ahead:
|
|
@@ -260,6 +260,12 @@ export default DitoComponent.component('DitoContainer', {
|
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
&--drop-target {
|
|
264
|
+
background: $content-color-background;
|
|
265
|
+
border-radius: $border-radius;
|
|
266
|
+
z-index: $drag-overlay-z-index + 1;
|
|
267
|
+
}
|
|
268
|
+
|
|
263
269
|
&--omit-padding {
|
|
264
270
|
padding: 0;
|
|
265
271
|
|
|
@@ -20,7 +20,7 @@ nav.dito-header
|
|
|
20
20
|
v-if="isLoading"
|
|
21
21
|
)
|
|
22
22
|
//- Teleport target for `.dito-schema-header`:
|
|
23
|
-
.dito-
|
|
23
|
+
.dito-header__menu
|
|
24
24
|
slot
|
|
25
25
|
</template>
|
|
26
26
|
|
|
@@ -77,15 +77,16 @@ export default DitoComponent.component('DitoHeader', {
|
|
|
77
77
|
@import '../styles/_imports';
|
|
78
78
|
|
|
79
79
|
.dito-header {
|
|
80
|
+
position: relative;
|
|
80
81
|
background: $color-black;
|
|
81
|
-
font-size: $
|
|
82
|
-
line-height: $
|
|
83
|
-
z-index: $
|
|
82
|
+
font-size: $header-font-size;
|
|
83
|
+
line-height: $header-line-height;
|
|
84
|
+
z-index: $header-z-index;
|
|
84
85
|
@include user-select(none);
|
|
85
86
|
|
|
86
87
|
span {
|
|
87
88
|
display: inline-block;
|
|
88
|
-
padding: $
|
|
89
|
+
padding: $header-padding;
|
|
89
90
|
color: $color-white;
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
<template lang="pug">
|
|
2
|
+
ul.dito-menu(
|
|
3
|
+
v-resize="onResize"
|
|
4
|
+
:style="{ '--width': width ? `${width}px` : null }"
|
|
5
|
+
)
|
|
6
|
+
li(
|
|
7
|
+
v-for="item in items"
|
|
8
|
+
)
|
|
9
|
+
template(
|
|
10
|
+
v-if="shouldRenderSchema(item)"
|
|
11
|
+
)
|
|
12
|
+
a.dito-link(
|
|
13
|
+
:href="getItemHref(item)"
|
|
14
|
+
:class="getItemClass(item, 'dito-sub-menu-link')"
|
|
15
|
+
@click.prevent.stop="onClickItem(item)"
|
|
16
|
+
) {{ getLabel(item) }}
|
|
17
|
+
DitoMenu(
|
|
18
|
+
v-if="item.items"
|
|
19
|
+
:class="getItemClass(item, 'dito-sub-menu')"
|
|
20
|
+
:items="item.items"
|
|
21
|
+
)
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script>
|
|
25
|
+
import DitoComponent from '../DitoComponent.js'
|
|
26
|
+
|
|
27
|
+
// @vue/component
|
|
28
|
+
export default DitoComponent.component('DitoMenu', {
|
|
29
|
+
props: {
|
|
30
|
+
items: {
|
|
31
|
+
type: [Object, Array],
|
|
32
|
+
default: () => []
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
data() {
|
|
37
|
+
return {
|
|
38
|
+
width: 0
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
methods: {
|
|
43
|
+
onResize({ contentRect: { width } }) {
|
|
44
|
+
if (width) {
|
|
45
|
+
this.width = width
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
getItemClass(item, subMenuClass) {
|
|
50
|
+
return {
|
|
51
|
+
[subMenuClass]: !!item.items,
|
|
52
|
+
'dito-active': this.isActiveItem(item)
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
getItemPath(item) {
|
|
57
|
+
return item?.path
|
|
58
|
+
? `/${item.path}`
|
|
59
|
+
: item.items
|
|
60
|
+
? this.getItemPath(Object.values(item.items)[0])
|
|
61
|
+
: null
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
getItemHref(item) {
|
|
65
|
+
const path = this.getItemPath(item)
|
|
66
|
+
return path ? this.$router.resolve(path).href : null
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
isActiveItem(item) {
|
|
70
|
+
return (
|
|
71
|
+
this.$route.path.startsWith(this.getItemPath(item)) ||
|
|
72
|
+
item.items && Object.values(item.items).some(this.isActiveItem)
|
|
73
|
+
)
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
onClickItem(item) {
|
|
77
|
+
const path = this.getItemPath(item)
|
|
78
|
+
if (path) {
|
|
79
|
+
this.$router.push({ path, force: true })
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
</script>
|
|
85
|
+
|
|
86
|
+
<style lang="scss">
|
|
87
|
+
@use 'sass:color';
|
|
88
|
+
@import '../styles/_imports';
|
|
89
|
+
|
|
90
|
+
.dito-menu {
|
|
91
|
+
$item-height: $menu-font-size + 2 * $menu-padding-ver;
|
|
92
|
+
|
|
93
|
+
border-right: $border-style;
|
|
94
|
+
padding: 0 $menu-spacing;
|
|
95
|
+
|
|
96
|
+
li {
|
|
97
|
+
&:has(.dito-sub-menu:not(.dito-active)) {
|
|
98
|
+
// Pop-out sub-menus on hover:
|
|
99
|
+
&:hover {
|
|
100
|
+
.dito-sub-menu-link {
|
|
101
|
+
background: $color-lightest;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.dito-sub-menu {
|
|
105
|
+
display: block;
|
|
106
|
+
position: absolute;
|
|
107
|
+
width: var(--width);
|
|
108
|
+
z-index: $header-z-index;
|
|
109
|
+
transform: translateX(calc(var(--width) + 2 * $menu-spacing))
|
|
110
|
+
translateY(-$item-height);
|
|
111
|
+
|
|
112
|
+
li:first-child {
|
|
113
|
+
.dito-link {
|
|
114
|
+
margin-top: 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&::before {
|
|
119
|
+
// Fill the gap to not loose the hover when moving over it.
|
|
120
|
+
content: '';
|
|
121
|
+
position: absolute;
|
|
122
|
+
top: 0;
|
|
123
|
+
left: -2 * $menu-spacing;
|
|
124
|
+
width: 2 * $menu-spacing;
|
|
125
|
+
height: $item-height;
|
|
126
|
+
opacity: 0;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// .dito-sub-menu-link,
|
|
131
|
+
.dito-sub-menu {
|
|
132
|
+
box-shadow: $shadow-window;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.dito-link {
|
|
139
|
+
display: block;
|
|
140
|
+
padding: $menu-padding;
|
|
141
|
+
line-height: $menu-line-height;
|
|
142
|
+
border-radius: $border-radius;
|
|
143
|
+
margin-top: $menu-spacing;
|
|
144
|
+
|
|
145
|
+
&:focus:not(:active, .dito-active) {
|
|
146
|
+
box-shadow: $shadow-focus;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
&:hover {
|
|
150
|
+
background: rgba(255, 255, 255, 0.5);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
&.dito-active {
|
|
154
|
+
color: $color-white;
|
|
155
|
+
background: $color-active;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.dito-sub-menu-link {
|
|
160
|
+
&.dito-active {
|
|
161
|
+
background: color.adjust($color-active, $alpha: -0.3);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.dito-sub-menu {
|
|
166
|
+
display: none;
|
|
167
|
+
border-right: 0;
|
|
168
|
+
padding: 0;
|
|
169
|
+
border-radius: $border-radius;
|
|
170
|
+
background: $color-lightest;
|
|
171
|
+
|
|
172
|
+
&.dito-active {
|
|
173
|
+
display: block;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
</style>
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
position="top right"
|
|
6
6
|
classes="dito-notification"
|
|
7
7
|
)
|
|
8
|
+
Transition(name="dito-drag")
|
|
9
|
+
.dito-drag-overlay(
|
|
10
|
+
v-if="isDraggingFiles"
|
|
11
|
+
)
|
|
8
12
|
TransitionGroup(name="dito-dialog")
|
|
9
13
|
DitoDialog(
|
|
10
14
|
v-for="(dialog, key) in dialogs"
|
|
@@ -16,7 +20,7 @@
|
|
|
16
20
|
:settings="dialog.settings"
|
|
17
21
|
@remove="removeDialog(key)"
|
|
18
22
|
)
|
|
19
|
-
|
|
23
|
+
DitoSidebar
|
|
20
24
|
main.dito-page.dito-scroll-parent
|
|
21
25
|
DitoHeader(
|
|
22
26
|
:spinner="options.spinner"
|
|
@@ -43,7 +47,7 @@ import DitoDialog from './DitoDialog.vue'
|
|
|
43
47
|
import DomMixin from '../mixins/DomMixin.js'
|
|
44
48
|
import {
|
|
45
49
|
processView,
|
|
46
|
-
|
|
50
|
+
resolveViews,
|
|
47
51
|
processSchemaComponents
|
|
48
52
|
} from '../utils/schema.js'
|
|
49
53
|
|
|
@@ -69,7 +73,8 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
69
73
|
removeRoutes: null,
|
|
70
74
|
dialogs: {},
|
|
71
75
|
allowLogin: false,
|
|
72
|
-
loadingCount: 0
|
|
76
|
+
loadingCount: 0,
|
|
77
|
+
isDraggingFiles: false
|
|
73
78
|
}
|
|
74
79
|
},
|
|
75
80
|
|
|
@@ -91,6 +96,8 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
91
96
|
},
|
|
92
97
|
|
|
93
98
|
async mounted() {
|
|
99
|
+
this.setupDragAndDrop()
|
|
100
|
+
|
|
94
101
|
tippyDelegate(this.$el, {
|
|
95
102
|
target: '.dito-info',
|
|
96
103
|
onCreate(instance) {
|
|
@@ -103,6 +110,7 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
103
110
|
})
|
|
104
111
|
}
|
|
105
112
|
})
|
|
113
|
+
|
|
106
114
|
// Clear the label marked as active on all mouse and keyboard events, except
|
|
107
115
|
// the ones that DitoLabel itself intercepts.
|
|
108
116
|
this.domOn(document, {
|
|
@@ -118,6 +126,7 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
})
|
|
129
|
+
|
|
121
130
|
try {
|
|
122
131
|
this.allowLogin = false
|
|
123
132
|
if (await this.fetchUser()) {
|
|
@@ -132,6 +141,81 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
132
141
|
},
|
|
133
142
|
|
|
134
143
|
methods: {
|
|
144
|
+
setupDragAndDrop() {
|
|
145
|
+
// This code only happens the visual effects around dragging and dropping
|
|
146
|
+
// files into a `DitoTypeUpload` component. The actual uploading is
|
|
147
|
+
// handled by the `DitoTypeUpload` component itself.
|
|
148
|
+
|
|
149
|
+
let dragCount = 0
|
|
150
|
+
let uploads = []
|
|
151
|
+
|
|
152
|
+
const toggleDropTargetClass = enabled => {
|
|
153
|
+
for (const upload of uploads) {
|
|
154
|
+
upload.closest('.dito-container').classList.toggle(
|
|
155
|
+
'dito-container--drop-target',
|
|
156
|
+
enabled
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
if (!enabled) {
|
|
160
|
+
uploads = []
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const setDraggingFiles = enabled => {
|
|
165
|
+
this.isDraggingFiles = enabled
|
|
166
|
+
if (enabled) {
|
|
167
|
+
toggleDropTargetClass(true)
|
|
168
|
+
} else {
|
|
169
|
+
setTimeout(() => toggleDropTargetClass(false), 250)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
this.domOn(document, {
|
|
174
|
+
dragenter: event => {
|
|
175
|
+
if (!dragCount && event.dataTransfer) {
|
|
176
|
+
uploads = document.querySelectorAll('.dito-upload')
|
|
177
|
+
const hasUploads = uploads.length > 0
|
|
178
|
+
event.dataTransfer.effectAllowed = hasUploads ? 'copy' : 'none'
|
|
179
|
+
if (hasUploads) {
|
|
180
|
+
setDraggingFiles(true)
|
|
181
|
+
} else {
|
|
182
|
+
event.preventDefault()
|
|
183
|
+
event.stopPropagation()
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
dragCount++
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
dragleave: event => {
|
|
191
|
+
dragCount--
|
|
192
|
+
if (!dragCount && event.dataTransfer) {
|
|
193
|
+
setDraggingFiles(false)
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
dragover: event => {
|
|
198
|
+
if (event.dataTransfer) {
|
|
199
|
+
const canDrop = event.target.closest(
|
|
200
|
+
'.dito-container:has(.dito-upload)'
|
|
201
|
+
)
|
|
202
|
+
event.dataTransfer.dropEffect = canDrop ? 'copy' : 'none'
|
|
203
|
+
if (!canDrop) {
|
|
204
|
+
event.preventDefault()
|
|
205
|
+
event.stopPropagation()
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
drop: event => {
|
|
211
|
+
dragCount = 0
|
|
212
|
+
if (event.dataTransfer) {
|
|
213
|
+
setDraggingFiles(false)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
},
|
|
218
|
+
|
|
135
219
|
notify({ type = 'info', title, text } = {}) {
|
|
136
220
|
title ||= (
|
|
137
221
|
{
|
|
@@ -328,7 +412,7 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
328
412
|
|
|
329
413
|
async resolveViews() {
|
|
330
414
|
try {
|
|
331
|
-
this.resolvedViews = await
|
|
415
|
+
this.resolvedViews = await resolveViews(this.unresolvedViews)
|
|
332
416
|
} catch (error) {
|
|
333
417
|
if (!error.request) {
|
|
334
418
|
console.error(error)
|
|
@@ -350,7 +434,7 @@ export default DitoComponent.component('DitoRoot', {
|
|
|
350
434
|
path: '/',
|
|
351
435
|
components: {}
|
|
352
436
|
},
|
|
353
|
-
...routes
|
|
437
|
+
...routes.flat()
|
|
354
438
|
])
|
|
355
439
|
this.$router.replace(fullPath)
|
|
356
440
|
}
|
|
@@ -389,4 +473,27 @@ function addRoutes(router, routes) {
|
|
|
389
473
|
background: $content-color-background;
|
|
390
474
|
}
|
|
391
475
|
}
|
|
476
|
+
|
|
477
|
+
.dito-drag-overlay {
|
|
478
|
+
position: fixed;
|
|
479
|
+
top: 0;
|
|
480
|
+
left: 0;
|
|
481
|
+
z-index: $drag-overlay-z-index;
|
|
482
|
+
width: 100%;
|
|
483
|
+
height: 100%;
|
|
484
|
+
background: rgba(0, 0, 0, 0.25);
|
|
485
|
+
pointer-events: none;
|
|
486
|
+
backdrop-filter: blur(8px);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.dito-drag-enter-active,
|
|
490
|
+
.dito-drag-leave-active {
|
|
491
|
+
transition: opacity 0.25s, backdrop-filter 0.25s;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.dito-drag-enter-from,
|
|
495
|
+
.dito-drag-leave-to {
|
|
496
|
+
opacity: 0;
|
|
497
|
+
backdrop-filter: blur(0);
|
|
498
|
+
}
|
|
392
499
|
</style>
|
|
@@ -5,7 +5,7 @@ slot(name="before")
|
|
|
5
5
|
)
|
|
6
6
|
.dito-schema-content(:class="{ 'dito-scroll': scrollable }")
|
|
7
7
|
Teleport(
|
|
8
|
-
to=".dito-
|
|
8
|
+
to=".dito-header__menu"
|
|
9
9
|
:disabled="!headerInMenu"
|
|
10
10
|
)
|
|
11
11
|
.dito-schema-header(
|
|
@@ -118,6 +118,7 @@ import { getStoreAccessor } from '../utils/accessor.js'
|
|
|
118
118
|
export default DitoComponent.component('DitoSchema', {
|
|
119
119
|
mixins: [ItemMixin],
|
|
120
120
|
components: { TransitionHeight },
|
|
121
|
+
inheritAttrs: false,
|
|
121
122
|
|
|
122
123
|
provide() {
|
|
123
124
|
return {
|
|
@@ -787,13 +788,13 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
787
788
|
&--menu {
|
|
788
789
|
// Align the tabs on top of to the header menu.
|
|
789
790
|
position: absolute;
|
|
790
|
-
height: $
|
|
791
|
-
padding: 0 $
|
|
791
|
+
height: $header-height;
|
|
792
|
+
padding: 0 $header-padding-hor;
|
|
792
793
|
max-width: $content-width;
|
|
793
794
|
top: 0;
|
|
794
795
|
left: 0;
|
|
795
796
|
right: 0;
|
|
796
|
-
z-index: $
|
|
797
|
+
z-index: $header-z-index;
|
|
797
798
|
// Turn off pointer events so that DitoTrail keeps receiving events...
|
|
798
799
|
pointer-events: none;
|
|
799
800
|
// ...but allow interaction with the tabs and buttons (e.g. clipboard)
|
|
@@ -801,8 +802,8 @@ export default DitoComponent.component('DitoSchema', {
|
|
|
801
802
|
.dito-tabs,
|
|
802
803
|
.dito-buttons {
|
|
803
804
|
pointer-events: auto;
|
|
804
|
-
line-height: $
|
|
805
|
-
font-size: $
|
|
805
|
+
line-height: $header-line-height;
|
|
806
|
+
font-size: $header-font-size;
|
|
806
807
|
}
|
|
807
808
|
}
|
|
808
809
|
}
|
|
@@ -1,78 +1,40 @@
|
|
|
1
1
|
<template lang="pug">
|
|
2
2
|
nav.dito-sidebar.dito-scroll-parent
|
|
3
|
-
h1
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
v-for="view in views"
|
|
7
|
-
)
|
|
8
|
-
RouterLink(
|
|
9
|
-
v-if="shouldRenderSchema(view)"
|
|
10
|
-
v-slot="{ isActive, href, route }"
|
|
11
|
-
custom
|
|
12
|
-
:to="`/${view.path}`"
|
|
13
|
-
)
|
|
14
|
-
a.dito-link(
|
|
15
|
-
:href="href"
|
|
16
|
-
:class="{ 'dito-active': isActive }"
|
|
17
|
-
@click.prevent="onClickLink(route)"
|
|
18
|
-
) {{ getLabel(view) }}
|
|
3
|
+
h1
|
|
4
|
+
RouterLink.dito-link(to="/") {{ appState.title }}
|
|
5
|
+
DitoMenu.dito-scroll(:items="views")
|
|
19
6
|
</template>
|
|
20
7
|
|
|
21
8
|
<script>
|
|
22
9
|
import DitoComponent from '../DitoComponent.js'
|
|
23
10
|
|
|
24
11
|
// @vue/component
|
|
25
|
-
export default DitoComponent.component('
|
|
26
|
-
methods: {
|
|
27
|
-
onClickLink(route) {
|
|
28
|
-
this.$router.push({ ...route, force: true })
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
})
|
|
12
|
+
export default DitoComponent.component('DitoSidebar', {})
|
|
32
13
|
</script>
|
|
33
14
|
|
|
34
15
|
<style lang="scss">
|
|
35
16
|
@import '../styles/_imports';
|
|
36
17
|
|
|
37
18
|
.dito-sidebar {
|
|
19
|
+
@include user-select(none);
|
|
20
|
+
|
|
38
21
|
flex: initial;
|
|
39
22
|
font-size: $menu-font-size;
|
|
40
23
|
white-space: nowrap;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
ul {
|
|
44
|
-
background: $color-lighter;
|
|
45
|
-
border-right: $border-style;
|
|
46
|
-
}
|
|
24
|
+
background: $color-lighter;
|
|
47
25
|
|
|
48
|
-
a,
|
|
49
26
|
h1 {
|
|
50
27
|
display: block;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
h1 {
|
|
54
|
-
padding: $menu-padding;
|
|
55
|
-
line-height: $menu-line-height;
|
|
28
|
+
line-height: $header-line-height;
|
|
56
29
|
font-weight: bold;
|
|
57
30
|
background: $color-darker;
|
|
58
31
|
border-right: $border-width solid $color-darkest;
|
|
59
32
|
color: $color-white;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
.dito-link {
|
|
63
|
-
padding: $menu-padding;
|
|
64
|
-
line-height: $menu-line-height;
|
|
65
33
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
34
|
+
.dito-link {
|
|
35
|
+
display: block;
|
|
36
|
+
padding: $header-padding;
|
|
69
37
|
}
|
|
70
38
|
}
|
|
71
39
|
}
|
|
72
|
-
|
|
73
|
-
.dito-link {
|
|
74
|
-
&:focus:not(:active, .dito-active) {
|
|
75
|
-
box-shadow: $shadow-focus;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
40
|
</style>
|
package/src/components/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// convention is in order of encountered hierarchy in the DOM.
|
|
5
5
|
|
|
6
6
|
export { default as DitoRoot } from './DitoRoot.vue'
|
|
7
|
+
export { default as DitoMenu } from './DitoMenu.vue'
|
|
7
8
|
export { default as DitoSidebar } from './DitoSidebar.vue'
|
|
8
9
|
export { default as DitoHeader } from './DitoHeader.vue'
|
|
9
10
|
export { default as DitoAccount } from './DitoAccount.vue'
|
package/src/mixins/TypeMixin.js
CHANGED
|
@@ -239,17 +239,15 @@ export default {
|
|
|
239
239
|
|
|
240
240
|
// @overridable
|
|
241
241
|
focusElement() {
|
|
242
|
-
const [element] = asArray(this.$refs.element)
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
})
|
|
252
|
-
}
|
|
242
|
+
const [element = this.$el] = asArray(this.$refs.element)
|
|
243
|
+
this.$nextTick(() => {
|
|
244
|
+
element.focus?.()
|
|
245
|
+
// If the element is disabled, `focus()` will likely not have the
|
|
246
|
+
// desired effect. Use `scrollIntoView()` if available:
|
|
247
|
+
if (!element.focus || this.disabled) {
|
|
248
|
+
;(element.$el || element).scrollIntoView?.()
|
|
249
|
+
}
|
|
250
|
+
})
|
|
253
251
|
},
|
|
254
252
|
|
|
255
253
|
focus() {
|
package/src/styles/_button.scss
CHANGED
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
&.dito-buttons-large {
|
|
116
116
|
--button-margin: 3px;
|
|
117
117
|
|
|
118
|
-
font-size: $
|
|
118
|
+
font-size: $header-font-size;
|
|
119
119
|
flex-flow: row wrap;
|
|
120
120
|
justify-content: center;
|
|
121
121
|
padding-bottom: $content-padding;
|
|
@@ -149,9 +149,9 @@
|
|
|
149
149
|
// For now, nothing for these:
|
|
150
150
|
// .dito-button-create:empty::before,
|
|
151
151
|
// .dito-button-add:empty::before
|
|
152
|
-
|
|
153
|
-
.dito-button-
|
|
154
|
-
@extend %icon-
|
|
152
|
+
|
|
153
|
+
.dito-button-upload:empty::before {
|
|
154
|
+
@extend %icon-upload;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
.dito-button-delete:empty::before,
|