@afeefa/vue-app 0.0.63 → 0.0.66
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/.afeefa/package/release/version.txt +1 -1
- package/package.json +1 -1
- package/src/components/ABreadcrumbs.vue +75 -18
- package/src/components/ADatePicker.vue +1 -1
- package/src/components/AIcon.vue +3 -6
- package/src/components/AIconButton.vue +1 -2
- package/src/components/AModal.vue +21 -3
- package/src/components/ARichTextArea.vue +95 -85
- package/src/components/ARow.vue +0 -7
- package/src/components/ATableRow.vue +4 -0
- package/src/components/flying-context/FlyingContextEvent.js +5 -0
- package/src/components/form/EditForm.vue +13 -3
- package/src/components/form/EditModal.vue +52 -35
- package/src/components/form/fields/FormFieldRichTextArea.vue +5 -3
- package/src/components/list/ListViewMixin.js +25 -2
- package/src/components/mixins/ClickOutsideMixin.js +5 -1
- package/src/components/search-select/SearchSelectList.vue +0 -1
- package/src/components/vue/Component.js +9 -2
- package/src/events.js +2 -0
- package/src-admin/bootstrap.js +1 -0
- package/src-admin/components/App.vue +58 -59
- package/src-admin/components/FlyingContext.vue +77 -0
- package/src-admin/components/FlyingContextContainer.vue +85 -0
- package/src-admin/components/Sidebar.vue +66 -0
- package/src-admin/components/SidebarItem.vue +59 -0
- package/src-admin/components/StickyFooter.vue +42 -0
- package/src-admin/components/StickyFooterContainer.vue +66 -0
- package/src-admin/components/StickyHeader.vue +73 -0
- package/src-admin/components/app/AppBarButtons.vue +0 -7
- package/src-admin/components/app/AppBarTitle.vue +55 -11
- package/src-admin/components/app/AppBarTitleContainer.vue +2 -3
- package/src-admin/components/controls/SearchSelectFormField.vue +1 -0
- package/src-admin/components/detail/DetailProperty.vue +20 -16
- package/src-admin/components/form/EditFormButtons.vue +25 -6
- package/src-admin/components/form/RemoveButton.vue +17 -8
- package/src-admin/components/index.js +6 -7
- package/src-admin/components/list/ListView.vue +22 -9
- package/src-admin/components/pages/EditPage.vue +17 -8
- package/src-admin/components/routes/DataRouteMixin.js +24 -15
- package/src-admin/config/routing.js +0 -11
- package/src-admin/config/vuetify.js +22 -2
- package/src-admin/directives/index.js +26 -0
- package/src-admin/styles.scss +21 -4
- package/src-admin/components/pages/CreatePage.vue +0 -114
- package/src-admin/components/pages/DetailPage.vue +0 -143
- package/src-admin/components/pages/EditPageMixin.js +0 -96
- package/src-admin/components/pages/ListPage.vue +0 -55
- package/src-admin/components/routes/CreateRoute.vue +0 -15
- package/src-admin/components/routes/DetailRoute.vue +0 -85
- package/src-admin/components/routes/EditRoute.vue +0 -78
- package/src-admin/components/routes/ListRoute.vue +0 -110
@@ -1,6 +1,7 @@
|
|
1
1
|
<template>
|
2
2
|
<a-modal
|
3
3
|
:title="title"
|
4
|
+
:beforeClose="beforeClose"
|
4
5
|
:show.sync="show_"
|
5
6
|
v-bind="$attrs"
|
6
7
|
>
|
@@ -10,16 +11,18 @@
|
|
10
11
|
|
11
12
|
<edit-form
|
12
13
|
v-if="show_"
|
14
|
+
ref="form"
|
13
15
|
:model="model"
|
16
|
+
:createModelToEdit="createModelToEdit"
|
14
17
|
>
|
15
|
-
<template #
|
18
|
+
<template #form="{modelToEdit, changed, valid}">
|
16
19
|
<slot
|
17
|
-
name="
|
18
|
-
:
|
20
|
+
name="form"
|
21
|
+
:modelToEdit="modelToEdit"
|
22
|
+
:changed="changed"
|
23
|
+
:valid="valid"
|
19
24
|
/>
|
20
|
-
</template>
|
21
25
|
|
22
|
-
<template #default="{changed, valid}">
|
23
26
|
<a-row
|
24
27
|
class="mt-8 mb-1 pb-1 gap-4"
|
25
28
|
right
|
@@ -31,25 +34,14 @@
|
|
31
34
|
Schließen
|
32
35
|
</v-btn>
|
33
36
|
|
34
|
-
<
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
</v-btn>
|
43
|
-
|
44
|
-
<v-icon
|
45
|
-
v-if="changed"
|
46
|
-
small
|
47
|
-
text
|
48
|
-
@click="reset"
|
49
|
-
>
|
50
|
-
{{ undoIcon }}
|
51
|
-
</v-icon>
|
52
|
-
</a-row>
|
37
|
+
<edit-form-buttons
|
38
|
+
:changed="changed"
|
39
|
+
:valid="valid"
|
40
|
+
small
|
41
|
+
:has="{reset: !!modelToEdit.id}"
|
42
|
+
@save="$emit('save', modelToEdit, ignoreChangesOnClose)"
|
43
|
+
@reset="$refs.form.reset()"
|
44
|
+
/>
|
53
45
|
</a-row>
|
54
46
|
</template>
|
55
47
|
</edit-form>
|
@@ -59,21 +51,26 @@
|
|
59
51
|
|
60
52
|
<script>
|
61
53
|
import { Component, Vue, Watch } from '@a-vue'
|
62
|
-
import {
|
54
|
+
import { DialogEvent } from '@a-vue/events'
|
63
55
|
|
64
56
|
@Component({
|
65
|
-
props: ['model', 'title', 'show']
|
57
|
+
props: ['model', 'createModelToEdit', 'title', 'show']
|
66
58
|
})
|
67
59
|
export default class EditModal extends Vue {
|
68
60
|
show_ = false
|
61
|
+
ignoreChangesOnClose_ = false
|
69
62
|
|
70
|
-
|
63
|
+
created () {
|
64
|
+
if (this.show) { // open on create with v-show
|
65
|
+
this.open()
|
66
|
+
}
|
67
|
+
}
|
71
68
|
|
72
69
|
/**
|
73
70
|
* visiblility changes from outside
|
74
71
|
* this will trigger the show_ watcher,
|
75
72
|
* forward the change to the modal and
|
76
|
-
* later emit
|
73
|
+
* later emit an open/close event
|
77
74
|
*/
|
78
75
|
@Watch('show')
|
79
76
|
showChanged () {
|
@@ -90,7 +87,6 @@ export default class EditModal extends Vue {
|
|
90
87
|
@Watch('show_')
|
91
88
|
show_Changed () {
|
92
89
|
if (this.show_) {
|
93
|
-
this.reset()
|
94
90
|
this.$emit('open')
|
95
91
|
} else {
|
96
92
|
this.$emit('close')
|
@@ -101,16 +97,37 @@ export default class EditModal extends Vue {
|
|
101
97
|
this.show_ = true
|
102
98
|
}
|
103
99
|
|
104
|
-
|
105
|
-
|
100
|
+
async beforeClose () {
|
101
|
+
// run only if show_ is true to prevent double checks with a-modal
|
102
|
+
if (this.show_ && this.$refs.form.changed && !this.ignoreChangesOnClose_) {
|
103
|
+
const result = await this.$events.dispatch(new DialogEvent(DialogEvent.SHOW, {
|
104
|
+
title: 'Änderungen verwerfen?',
|
105
|
+
message: 'Im Formular sind nicht gespeicherte Änderungen. Sollen diese verworfen werden?',
|
106
|
+
yesButton: 'Verwerfen'
|
107
|
+
}))
|
108
|
+
if (result !== DialogEvent.RESULT_YES) {
|
109
|
+
return false
|
110
|
+
}
|
111
|
+
}
|
112
|
+
return true
|
106
113
|
}
|
107
114
|
|
108
|
-
|
109
|
-
this
|
115
|
+
async close () {
|
116
|
+
const result = await this.beforeClose()
|
117
|
+
if (!result) {
|
118
|
+
return
|
119
|
+
}
|
120
|
+
|
121
|
+
this.show_ = false
|
110
122
|
}
|
111
123
|
|
112
|
-
|
113
|
-
|
124
|
+
/**
|
125
|
+
* hook to allow to leave a just created (saved) model
|
126
|
+
*/
|
127
|
+
ignoreChangesOnClose () {
|
128
|
+
// this.$refs.form.forceUnchanged()
|
129
|
+
console.info('TODO switch form to forceUnchanged')
|
130
|
+
this.ignoreChangesOnClose_ = true
|
114
131
|
}
|
115
132
|
}
|
116
133
|
</script>
|
@@ -11,6 +11,7 @@ import { FilterSourceType } from './FilterSourceType'
|
|
11
11
|
'listAction',
|
12
12
|
'filterHistoryKey',
|
13
13
|
'loadOnlyIfKeyword',
|
14
|
+
'checkBeforeLoad',
|
14
15
|
{
|
15
16
|
filterSource: FilterSourceType.QUERY_STRING,
|
16
17
|
events: true,
|
@@ -64,9 +65,16 @@ export class ListViewMixin extends Vue {
|
|
64
65
|
.on('change', this.filtersChanged) // listen to change
|
65
66
|
|
66
67
|
this._filtersInitialized()
|
68
|
+
this.$emit('update:filters', this.filters)
|
69
|
+
this.$emit('update:listViewModel', this.listViewModel)
|
67
70
|
|
68
71
|
if (this.models) {
|
69
72
|
this.$emit('update:count', this.meta_.count_search)
|
73
|
+
|
74
|
+
this.$emit('onLoad', {
|
75
|
+
models: this.models_,
|
76
|
+
meta: this.meta_
|
77
|
+
})
|
70
78
|
} else {
|
71
79
|
this.load()
|
72
80
|
}
|
@@ -113,6 +121,16 @@ export class ListViewMixin extends Vue {
|
|
113
121
|
}
|
114
122
|
|
115
123
|
async load () {
|
124
|
+
if (this.checkBeforeLoad) {
|
125
|
+
const canLoad = await this.checkBeforeLoad()
|
126
|
+
if (!canLoad) {
|
127
|
+
if (this.meta_.used_filters) {
|
128
|
+
this.listViewModel.initFromUsedFilters(this.meta_.used_filters, this.meta_.count_search)
|
129
|
+
}
|
130
|
+
return
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
116
134
|
if (this._loadOnlyIfKeyword && !this.filters.q.value) {
|
117
135
|
this.models_ = []
|
118
136
|
this.meta_ = {}
|
@@ -132,7 +150,7 @@ export class ListViewMixin extends Vue {
|
|
132
150
|
|
133
151
|
if (!models) { // error happened
|
134
152
|
this.isLoading = false
|
135
|
-
this.$emit('update:isLoading',
|
153
|
+
this.$emit('update:isLoading', false)
|
136
154
|
return
|
137
155
|
}
|
138
156
|
|
@@ -144,8 +162,13 @@ export class ListViewMixin extends Vue {
|
|
144
162
|
}
|
145
163
|
|
146
164
|
this.isLoading = false
|
147
|
-
this.$emit('update:isLoading',
|
165
|
+
this.$emit('update:isLoading', false)
|
148
166
|
|
149
167
|
this.$emit('update:count', this.meta_.count_search)
|
168
|
+
|
169
|
+
this.$emit('onLoad', {
|
170
|
+
models,
|
171
|
+
meta
|
172
|
+
})
|
150
173
|
}
|
151
174
|
}
|
@@ -25,10 +25,14 @@ export class ClickOutsideMixin extends Vue {
|
|
25
25
|
// popup clicked
|
26
26
|
const thisIndex = getZIndex(this.$el)
|
27
27
|
const targetIndex = getZIndex(e.target)
|
28
|
-
if (targetIndex > thisIndex) {
|
28
|
+
if (targetIndex > 10 && targetIndex > thisIndex) { // sidebar === 6
|
29
29
|
return
|
30
30
|
}
|
31
31
|
|
32
|
+
this.com_onClickOutside()
|
32
33
|
this.$emit('click:outside')
|
33
34
|
}
|
35
|
+
|
36
|
+
com_onClickOutside () {
|
37
|
+
}
|
34
38
|
}
|
@@ -32,9 +32,16 @@ function propsWithDefaults (props) {
|
|
32
32
|
// property: { some object }, should be a normal vue props object
|
33
33
|
} else if (value && typeof value === 'object' && value.constructor === Object) {
|
34
34
|
normalizedProps[subProp] = value
|
35
|
-
// property: true, null, ...
|
35
|
+
// property: true, false, null, ...
|
36
36
|
} else {
|
37
|
-
|
37
|
+
if (typeof value === 'boolean') {
|
38
|
+
normalizedProps[subProp] = {
|
39
|
+
type: Boolean,
|
40
|
+
default: value
|
41
|
+
}
|
42
|
+
} else {
|
43
|
+
normalizedProps[subProp] = { default: value }
|
44
|
+
}
|
38
45
|
}
|
39
46
|
})
|
40
47
|
} else {
|
package/src/events.js
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
+
export { BaseEvent } from './plugins/event-bus/BaseEvent'
|
1
2
|
export { LoadingEvent } from './components/loading-indicator/LoadingEvent'
|
2
3
|
export { SaveEvent } from './components/save-indicator/SaveEvent'
|
3
4
|
export { AlertEvent } from './components/alert/AlertEvent'
|
4
5
|
export { DialogEvent } from './components/dialog/DialogEvent'
|
6
|
+
export { FlyingContextEvent } from './components/flying-context/FlyingContextEvent'
|
package/src-admin/bootstrap.js
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
<v-navigation-drawer
|
4
4
|
v-model="drawer"
|
5
5
|
app
|
6
|
-
fixeds
|
7
6
|
left
|
7
|
+
width="280"
|
8
|
+
class="menubar"
|
8
9
|
>
|
9
10
|
<v-container
|
10
11
|
flex-column
|
@@ -72,66 +73,47 @@
|
|
72
73
|
</v-container>
|
73
74
|
</v-navigation-drawer>
|
74
75
|
|
75
|
-
<
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
</v-list-item-content>
|
90
|
-
</v-list-item>
|
91
|
-
</v-list>
|
92
|
-
</v-navigation-drawer>
|
93
|
-
|
94
|
-
<v-app-bar
|
95
|
-
app
|
96
|
-
flat
|
97
|
-
dense
|
98
|
-
color="#FAFAFA"
|
99
|
-
>
|
100
|
-
<div class="d-flex align-start mt-n2">
|
76
|
+
<a-loading-indicator
|
77
|
+
fixed
|
78
|
+
top
|
79
|
+
left
|
80
|
+
class="loadingIndicator"
|
81
|
+
:isLoading="isLoading"
|
82
|
+
:color="loaderColor"
|
83
|
+
/>
|
84
|
+
|
85
|
+
<v-main id="v-main">
|
86
|
+
<a-row
|
87
|
+
start
|
88
|
+
class="topbar"
|
89
|
+
>
|
101
90
|
<v-app-bar-nav-icon
|
102
|
-
class="sidebarToggleButton mr-2 ml-
|
91
|
+
class="sidebarToggleButton mr-2 ml-4"
|
103
92
|
@click="toggleDrawer"
|
104
93
|
/>
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
fixed
|
110
|
-
top
|
111
|
-
left
|
112
|
-
class="loadingIndicator"
|
113
|
-
:isLoading="isLoading"
|
114
|
-
:color="loaderColor"
|
115
|
-
/>
|
116
|
-
</v-app-bar>
|
117
|
-
|
118
|
-
<v-main>
|
94
|
+
|
95
|
+
<a-breadcrumbs />
|
96
|
+
</a-row>
|
97
|
+
|
119
98
|
<v-container
|
120
99
|
fluid
|
121
|
-
class="pa-4"
|
100
|
+
class="pa-8 pt-4"
|
122
101
|
>
|
123
|
-
<
|
124
|
-
<app-bar-title-container class="flex-grow-1 mb-4" />
|
125
|
-
<app-bar-buttons class="mr-2 mb-4" />
|
126
|
-
</div>
|
102
|
+
<sticky-header />
|
127
103
|
|
128
104
|
<router-view :class="{isLoading}" />
|
129
105
|
</v-container>
|
106
|
+
|
107
|
+
<sticky-footer-container />
|
130
108
|
</v-main>
|
131
109
|
|
132
110
|
<a-dialog id="app" />
|
133
111
|
|
134
112
|
<a-save-indicator />
|
113
|
+
|
114
|
+
<sidebar />
|
115
|
+
|
116
|
+
<flying-context-container />
|
135
117
|
</div>
|
136
118
|
</template>
|
137
119
|
|
@@ -142,17 +124,24 @@ import { appConfig } from '@a-admin/config/AppConfig'
|
|
142
124
|
import { sleep } from '@a-vue/utils/timeout'
|
143
125
|
import AppBarButtons from './app/AppBarButtons'
|
144
126
|
import AppBarTitleContainer from './app/AppBarTitleContainer'
|
127
|
+
import FlyingContextContainer from './FlyingContextContainer'
|
128
|
+
import StickyFooterContainer from './StickyFooterContainer'
|
129
|
+
import Sidebar from './Sidebar'
|
130
|
+
import StickyHeader from './StickyHeader'
|
145
131
|
import '../styles.scss'
|
146
132
|
|
147
133
|
@Component({
|
148
134
|
components: {
|
149
135
|
AppBarButtons,
|
150
|
-
AppBarTitleContainer
|
136
|
+
AppBarTitleContainer,
|
137
|
+
FlyingContextContainer,
|
138
|
+
StickyFooterContainer,
|
139
|
+
Sidebar,
|
140
|
+
StickyHeader
|
151
141
|
}
|
152
142
|
})
|
153
143
|
export default class App extends Vue {
|
154
144
|
drawer = true
|
155
|
-
mainDrawer = false
|
156
145
|
isLoading = false
|
157
146
|
account = null
|
158
147
|
|
@@ -199,16 +188,6 @@ export default class App extends Vue {
|
|
199
188
|
this.drawer = !this.drawer
|
200
189
|
}
|
201
190
|
|
202
|
-
@Watch('drawer')
|
203
|
-
async drawerChanged () {
|
204
|
-
if (this.drawer) {
|
205
|
-
this.mainDrawer = false
|
206
|
-
} else {
|
207
|
-
await sleep(0.1)
|
208
|
-
this.mainDrawer = true
|
209
|
-
}
|
210
|
-
}
|
211
|
-
|
212
191
|
get hasAuthService () {
|
213
192
|
return !!appConfig.authService
|
214
193
|
}
|
@@ -244,4 +223,24 @@ export default class App extends Vue {
|
|
244
223
|
height: 36px !important;
|
245
224
|
margin-top: 1px;
|
246
225
|
}
|
226
|
+
|
227
|
+
.topbar {
|
228
|
+
position: relative;
|
229
|
+
width: 100%;
|
230
|
+
left: 0;
|
231
|
+
top: 0;
|
232
|
+
padding: .2rem 1rem;
|
233
|
+
}
|
234
|
+
|
235
|
+
.a-breadcrumbs {
|
236
|
+
margin-top: 7px;
|
237
|
+
}
|
238
|
+
|
239
|
+
.menubar {
|
240
|
+
// background: #666666 !important;
|
241
|
+
}
|
242
|
+
|
243
|
+
#sidebar {
|
244
|
+
// background: #F4F4F4 !important;
|
245
|
+
}
|
247
246
|
</style>
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="flyingContext">
|
3
|
+
<div :class="contextId">
|
4
|
+
<slot v-if="isVisible" />
|
5
|
+
</div>
|
6
|
+
</div>
|
7
|
+
</template>
|
8
|
+
|
9
|
+
<script>
|
10
|
+
import { Component, Watch, Vue } from '@a-vue'
|
11
|
+
import { FlyingContextEvent } from '@a-vue/events'
|
12
|
+
import { randomCssClass } from '@a-vue/utils/random'
|
13
|
+
|
14
|
+
@Component({
|
15
|
+
props: [{show: false}]
|
16
|
+
})
|
17
|
+
export default class FlyingContext extends Vue {
|
18
|
+
isVisible = false
|
19
|
+
contextId = randomCssClass(10)
|
20
|
+
|
21
|
+
created () {
|
22
|
+
this.$events.on(FlyingContextEvent.HIDE_ALL, this.onHide)
|
23
|
+
}
|
24
|
+
|
25
|
+
mounted () {
|
26
|
+
if (this.show) {
|
27
|
+
this.showChanged()
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
@Watch('show')
|
32
|
+
showChanged () {
|
33
|
+
if (this.isVisible === this.show) {
|
34
|
+
return
|
35
|
+
}
|
36
|
+
|
37
|
+
this.isVisible = this.show
|
38
|
+
|
39
|
+
if (this.isVisible) {
|
40
|
+
const container = this.getSidebarContainer()
|
41
|
+
container.appendChild(this.getContent())
|
42
|
+
} else {
|
43
|
+
this.$el.appendChild(this.getContent())
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
destroyed () {
|
48
|
+
const container = this.getSidebarContainer()
|
49
|
+
const el = this.getContent()
|
50
|
+
if (container.contains(el)) {
|
51
|
+
container.removeChild(el)
|
52
|
+
}
|
53
|
+
|
54
|
+
this.$events.off(FlyingContextEvent.HIDE_ALL, this.onHide)
|
55
|
+
}
|
56
|
+
|
57
|
+
onHide () {
|
58
|
+
if (this.isVisible) {
|
59
|
+
this.$el.appendChild(this.getContent())
|
60
|
+
this.isVisible = false
|
61
|
+
this.$emit('hide')
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
getContent () {
|
66
|
+
return document.querySelector('.' + this.contextId)
|
67
|
+
}
|
68
|
+
|
69
|
+
getSidebarContainer () {
|
70
|
+
return document.getElementById('flyingContextContainer__children')
|
71
|
+
}
|
72
|
+
}
|
73
|
+
</script>
|
74
|
+
|
75
|
+
|
76
|
+
<style lang="scss" scoped>
|
77
|
+
</style>
|
@@ -0,0 +1,85 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
id="flyingContextContainer"
|
4
|
+
:class="{visible}"
|
5
|
+
>
|
6
|
+
<a
|
7
|
+
href=""
|
8
|
+
@click.prevent="hide"
|
9
|
+
>close</a>
|
10
|
+
|
11
|
+
<br>
|
12
|
+
<br>
|
13
|
+
|
14
|
+
<div id="flyingContextContainer__children" />
|
15
|
+
</div>
|
16
|
+
</template>
|
17
|
+
|
18
|
+
<script>
|
19
|
+
import { Component, Vue } from '@a-vue'
|
20
|
+
import { FlyingContextEvent } from '@a-vue/events'
|
21
|
+
|
22
|
+
@Component({
|
23
|
+
props: []
|
24
|
+
})
|
25
|
+
export default class FlyingContextContainer extends Vue {
|
26
|
+
visible = false
|
27
|
+
|
28
|
+
mounted () {
|
29
|
+
this.mutationWatcher = new MutationObserver(this.domChanged)
|
30
|
+
this.mutationWatcher.observe(this.getChildrenContainer(), { childList: true })
|
31
|
+
|
32
|
+
window.addEventListener('mousedown', this.onClickOutside)
|
33
|
+
}
|
34
|
+
|
35
|
+
domChanged () {
|
36
|
+
const container = this.getChildrenContainer()
|
37
|
+
this.visible = !!container.children.length
|
38
|
+
}
|
39
|
+
|
40
|
+
hide () {
|
41
|
+
if (this.visible) {
|
42
|
+
this.$events.dispatch(new FlyingContextEvent(FlyingContextEvent.HIDE_ALL))
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
getChildrenContainer () {
|
47
|
+
return this.$el.querySelector('#flyingContextContainer__children')
|
48
|
+
}
|
49
|
+
|
50
|
+
onClickOutside (e) {
|
51
|
+
// check if trigger is clicked
|
52
|
+
let parent = e.target
|
53
|
+
while (parent) {
|
54
|
+
if (parent.classList.contains('flyingContextTrigger')) {
|
55
|
+
return
|
56
|
+
}
|
57
|
+
parent = parent.parentElement
|
58
|
+
}
|
59
|
+
|
60
|
+
// check if flying context ist clicked
|
61
|
+
if (!this.$el.contains(e.target)) {
|
62
|
+
this.hide()
|
63
|
+
}
|
64
|
+
}
|
65
|
+
}
|
66
|
+
</script>
|
67
|
+
|
68
|
+
|
69
|
+
<style lang="scss" scoped>
|
70
|
+
#flyingContextContainer {
|
71
|
+
position: fixed;
|
72
|
+
z-index: 200;
|
73
|
+
right: 0;
|
74
|
+
width: 60vw;
|
75
|
+
height: 80vh;
|
76
|
+
top: 10vh;
|
77
|
+
background: rgba($color: white, $alpha: .6);
|
78
|
+
border: 1px solid black;
|
79
|
+
transition: right .2s;
|
80
|
+
|
81
|
+
&:not(.visible) {
|
82
|
+
right: -80vw;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
</style>
|
@@ -0,0 +1,66 @@
|
|
1
|
+
<template>
|
2
|
+
<v-navigation-drawer
|
3
|
+
id="sidebar"
|
4
|
+
v-model="visible"
|
5
|
+
app
|
6
|
+
right
|
7
|
+
disable-resize-watcher
|
8
|
+
width="220"
|
9
|
+
>
|
10
|
+
<div id="sidebar__children">
|
11
|
+
<div class="top" />
|
12
|
+
<div class="bottom" />
|
13
|
+
</div>
|
14
|
+
</v-navigation-drawer>
|
15
|
+
</template>
|
16
|
+
|
17
|
+
<script>
|
18
|
+
import { Component, Vue } from '@a-vue'
|
19
|
+
|
20
|
+
@Component({
|
21
|
+
props: []
|
22
|
+
})
|
23
|
+
export default class Sidebar extends Vue {
|
24
|
+
visible = false
|
25
|
+
|
26
|
+
mounted () {
|
27
|
+
this.mutationWatcher = new MutationObserver(this.domChanged)
|
28
|
+
this.mutationWatcher.observe(this.$el.querySelector('#sidebar__children > .top'), { childList: true })
|
29
|
+
this.mutationWatcher.observe(this.$el.querySelector('#sidebar__children > .bottom'), { childList: true })
|
30
|
+
|
31
|
+
this.domChanged()
|
32
|
+
}
|
33
|
+
|
34
|
+
domChanged () {
|
35
|
+
this.visible = this.hasSidebarItems()
|
36
|
+
}
|
37
|
+
|
38
|
+
getChildrenContainer () {
|
39
|
+
return this.$el.querySelector('#sidebar__children')
|
40
|
+
}
|
41
|
+
|
42
|
+
hasSidebarItems () {
|
43
|
+
return !!(this.$el.querySelector('#sidebar__children .top').children.length +
|
44
|
+
this.$el.querySelector('#sidebar__children .bottom').children.length)
|
45
|
+
}
|
46
|
+
}
|
47
|
+
</script>
|
48
|
+
|
49
|
+
|
50
|
+
<style lang="scss" scoped>
|
51
|
+
#sidebar {
|
52
|
+
&__children {
|
53
|
+
width: 100%;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
#sidebar__children {
|
58
|
+
height: 100%;
|
59
|
+
padding: 2rem;
|
60
|
+
// padding-left: 4rem;
|
61
|
+
|
62
|
+
display: flex;
|
63
|
+
flex-direction: column;
|
64
|
+
justify-content: space-between;
|
65
|
+
}
|
66
|
+
</style>
|