@afeefa/vue-app 0.0.173 → 0.0.175

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 (29) hide show
  1. package/.afeefa/package/release/version.txt +1 -1
  2. package/package.json +1 -1
  3. package/src/components/AInfo.vue +15 -1
  4. package/src/components/ALoadingIndicator.vue +4 -0
  5. package/src/components/ATable.vue +6 -0
  6. package/src/components/ATableRow.vue +5 -0
  7. package/src/plugins/route-config/RouteConfigPlugin.js +17 -0
  8. package/src/utils/format-time.js +17 -0
  9. package/src-admin/components/App.vue +48 -186
  10. package/src-admin/components/CollapsibleSection.vue +64 -0
  11. package/src-admin/components/DetailOrInfo.vue +33 -0
  12. package/src-admin/components/FlyingContextContainer.vue +21 -1
  13. package/src-admin/components/HSeparator.vue +90 -0
  14. package/src-admin/components/InformationBar.vue +176 -0
  15. package/src-admin/components/NavigationBar.vue +187 -0
  16. package/src-admin/components/StickyHeader.vue +40 -8
  17. package/src-admin/components/app/AppBarTitle.vue +6 -11
  18. package/src-admin/components/detail/DetailProperty.vue +12 -17
  19. package/src-admin/components/index.js +14 -5
  20. package/src-admin/components/list/ListView.vue +1 -1
  21. package/src-admin/components/sidebar/InformationBarItem.vue +209 -0
  22. package/src-admin/components/sidebar/SidebarEvent.js +5 -0
  23. package/src-admin/components/sidebar/SidebarService.js +107 -0
  24. package/src-admin/components/transitions/CollapseTransition.vue +61 -0
  25. package/src-admin/config/vuetify.js +7 -1
  26. package/src-admin/events.js +1 -0
  27. package/src-admin/styles.scss +10 -2
  28. package/src-admin/components/Sidebar.vue +0 -66
  29. package/src-admin/components/SidebarItem.vue +0 -59
@@ -1 +1 @@
1
- 0.0.173
1
+ 0.0.175
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.173",
3
+ "version": "0.0.175",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
@@ -2,6 +2,7 @@
2
2
  <v-alert
3
3
  v-bind="$attrs"
4
4
  :style="{display: inline ? 'inline-block' : 'block'}"
5
+ :class="['a-info', {xSmall}]"
5
6
  dense
6
7
  border="left"
7
8
  colored-border
@@ -16,11 +17,24 @@
16
17
  import { Component, Vue } from '@a-vue'
17
18
 
18
19
  @Component({
19
- props: [{inline: true}]
20
+ props: [{inline: true, xSmall: false}]
20
21
  })
21
22
  export default class AInfo extends Vue {
22
23
  }
23
24
  </script>
24
25
 
25
26
  <style lang="scss" scoped>
27
+ :deep(.v-icon) {
28
+ margin-right: .4rem;
29
+ }
30
+
31
+ .xSmall {
32
+ padding: .3rem .6rem;
33
+ font-size: .9rem;
34
+
35
+ :deep(.v-icon) {
36
+ margin-left: .2rem;
37
+ margin-right: .4rem;
38
+ }
39
+ }
26
40
  </style>
@@ -6,6 +6,10 @@
6
6
  :color="color"
7
7
  v-bind="$attrs"
8
8
  />
9
+ <div
10
+ v-else
11
+ style="height: 4px;"
12
+ />
9
13
  </template>
10
14
 
11
15
  <script>
@@ -53,6 +53,12 @@ export default class ATable extends Vue {
53
53
 
54
54
  white-space: nowrap;
55
55
  vertical-align: middle;
56
+ max-width: 300px;
57
+
58
+ .a-table-cell-truncate {
59
+ overflow: hidden;
60
+ text-overflow: ellipsis;
61
+ }
56
62
 
57
63
  &.text--info {
58
64
  color: #888888 !important;
@@ -117,6 +117,11 @@ export default class ATableRow extends Vue {
117
117
  line-height: .9;
118
118
  }
119
119
 
120
+ .textblock--tiny {
121
+ font-size: .8rem;
122
+ line-height: .8;
123
+ }
124
+
120
125
  [class*=text-] {
121
126
  color: inherit;
122
127
  }
@@ -37,6 +37,7 @@ class RouteConfigPlugin {
37
37
 
38
38
  _routeDefinitions = []
39
39
  _config = {}
40
+ _scrollContainer = null
40
41
 
41
42
  _breadcrumbDefinitions = []
42
43
  _breadcrumbDefinitionMap = {}
@@ -117,6 +118,11 @@ class RouteConfigPlugin {
117
118
  return this
118
119
  }
119
120
 
121
+ scrollContainer (scrollContainer) {
122
+ this._scrollContainer = scrollContainer
123
+ return this
124
+ }
125
+
120
126
  routes (callback) {
121
127
  this._promise = this._promise.then(() => {
122
128
  callback = callback({
@@ -161,6 +167,17 @@ class RouteConfigPlugin {
161
167
  for (const route of this._routes) {
162
168
  this._router.addRoute(route)
163
169
  }
170
+
171
+ if (this._scrollContainer) { // scroll to 0 if not window object is used as scoll parent
172
+ this._router.afterEach((to, from) => {
173
+ if (to.path !== from.path) {
174
+ const el = document.querySelector(this._scrollContainer)
175
+ if (el) {
176
+ el.scrollTop = 0
177
+ }
178
+ }
179
+ })
180
+ }
164
181
  })
165
182
  })
166
183
 
@@ -0,0 +1,17 @@
1
+ export function formatTime (date) {
2
+ if (!date) {
3
+ return ''
4
+ }
5
+
6
+ const hour = addZero(date.getHours())
7
+ const minutes = addZero(date.getMinutes())
8
+
9
+ return `${hour}:${minutes}`
10
+ }
11
+
12
+ function addZero (i) {
13
+ if (i < 10) {
14
+ i = '0' + i
15
+ }
16
+ return i
17
+ }
@@ -1,136 +1,41 @@
1
1
  <template>
2
- <div>
3
- <v-navigation-drawer
4
- v-model="drawer"
5
- app
6
- left
7
- width="280"
8
- class="menubar"
9
- >
10
- <v-container
11
- flex-column
12
- align-center
13
- fill-height
14
- >
15
- <a-row
16
- justify-end
17
- width="100%"
18
- >
19
- <v-app-bar-nav-icon
20
- class="sidebarToggleButton mt-1 mr-2 ml-3"
21
- title="Menu schließen"
22
- @click="toggleDrawer"
23
- >
24
- <v-icon>{{ closeMenuIcon }}</v-icon>
25
- </v-app-bar-nav-icon>
26
- </a-row>
27
-
28
- <router-link
29
- :to="{name: rootRouteName}"
30
- class="logoContainer d-flex flex-column align-center pa-6"
31
- >
32
- <img
33
- v-if="logoUrl"
34
- class="logo"
35
- :src="logoUrl"
36
- >
37
- <div class="text-button">
38
- {{ title }}
39
- </div>
40
- </router-link>
41
-
42
- <component
43
- :is="SidebarMenu"
44
- class="px-0 mt-0 flex-grow-1"
45
- />
46
-
47
- <v-container
48
- v-if="hasAuthService"
49
- d-flex
50
- align-center
51
- gap-4
52
- pa-6
53
- pb-8
54
- >
55
- <div class="d-flex align-center gap-3">
56
- <v-avatar
57
- color="primary white--text"
58
- size="40"
59
- >
60
- {{ account.first_name.charAt(0).toUpperCase() }}{{ account.last_name.charAt(0).toUpperCase() }}
61
- </v-avatar>
62
-
63
- <div>
64
- <div class="accountName">
65
- {{ account.first_name }}
66
- <template v-if="$auth.roles[0]">
67
- ({{ $auth.roles[0].title }})
68
- </template>
69
- </div>
70
-
71
- <div class="body-2 d-flex align-center">
72
- <v-icon class="ml-n1 mr-1">
73
- $logoutIcon
74
- </v-icon>
75
- <a @click="logout()">Logout</a>
76
- </div>
77
- </div>
78
-
79
- <a-context-menu v-if="$has.settings">
80
- <a-context-menu-item
81
- :to="{name: 'settings', params: {accountId: account.id}}"
82
- >
83
- <v-icon>$pencilIcon</v-icon>
84
- Einstellungen
85
- </a-context-menu-item>
86
- </a-context-menu>
87
- </div>
88
- </v-container>
89
- </v-container>
90
- </v-navigation-drawer>
91
-
92
- <a-loading-indicator
2
+ <div class="admin">
3
+ <v-overlay
93
4
  fixed
94
- top
95
- left
96
- class="loadingIndicator"
97
- :isLoading="!!numLoadingRequests"
98
- :color="loaderColor"
5
+ :value="sidebarsFloating"
6
+ @click="closeFloatingSidebars"
99
7
  />
100
8
 
101
- <v-main id="v-main">
102
- <a-row
103
- class="topbar"
104
- align-start
9
+ <div class="main-layout">
10
+ <navigation-bar :has="$has" />
11
+
12
+ <div
13
+ id="v-main"
14
+ :class="{marginRight: hasFloatingInformationBar}"
105
15
  >
106
- <v-app-bar-nav-icon
107
- v-if="!drawer"
108
- class="sidebarToggleButton mr-2 ml-3"
109
- title="Menu öffnen"
110
- @click="toggleDrawer"
16
+ <a-loading-indicator
17
+ top
18
+ class="loadingIndicator"
19
+ :isLoading="!!numLoadingRequests"
20
+ :color="loaderColor"
111
21
  />
112
22
 
113
- <a-breadcrumbs />
114
- </a-row>
115
-
116
- <v-container
117
- fluid
118
- class="pa-8 pt-0"
119
- >
120
23
  <sticky-header />
121
24
 
122
- <router-view :class="{isLoading: !!numLoadingRequests}" />
123
- </v-container>
25
+ <div class="pa-8 pt-4">
26
+ <router-view :class="{isLoading: !!numLoadingRequests}" />
27
+ </div>
28
+
29
+ <sticky-footer-container />
30
+ </div>
124
31
 
125
- <sticky-footer-container />
126
- </v-main>
32
+ <information-bar />
33
+ </div>
127
34
 
128
35
  <a-dialog id="app" />
129
36
 
130
37
  <a-save-indicator />
131
38
 
132
- <sidebar />
133
-
134
39
  <flying-context-container />
135
40
  </div>
136
41
  </template>
@@ -144,18 +49,22 @@ import AppBarButtons from './app/AppBarButtons'
144
49
  import AppBarTitleContainer from './app/AppBarTitleContainer'
145
50
  import FlyingContextContainer from './FlyingContextContainer'
146
51
  import StickyFooterContainer from './StickyFooterContainer'
147
- import Sidebar from './Sidebar'
52
+ import NavigationBar from './NavigationBar'
53
+ import InformationBar from './InformationBar'
148
54
  import StickyHeader from './StickyHeader'
149
55
  import '../styles.scss'
150
56
  import { mdiBackburger } from '@mdi/js'
57
+ import { SidebarEvent } from '@a-admin/events'
58
+ import { sidebarService } from './sidebar/SidebarService'
151
59
 
152
60
  @Component({
153
61
  components: {
154
62
  AppBarButtons,
155
63
  AppBarTitleContainer,
64
+ NavigationBar,
65
+ InformationBar,
156
66
  FlyingContextContainer,
157
67
  StickyFooterContainer,
158
- Sidebar,
159
68
  StickyHeader
160
69
  }
161
70
  })
@@ -166,39 +75,32 @@ export default class App extends Vue {
166
75
  closeMenuIcon = mdiBackburger
167
76
  numLoadingRequests = 0
168
77
 
78
+ sidebarsFloating = false
79
+ hasFloatingInformationBar = false
80
+
169
81
  created () {
170
82
  this.$events.on(LoadingEvent.START_LOADING, this.startLoading)
171
83
  this.$events.on(LoadingEvent.STOP_LOADING, this.stopLoading)
172
- this.$emit('appLoaded')
173
- }
174
84
 
175
- get SidebarMenu () {
176
- return adminConfig.app.components.SidebarMenu
177
- }
85
+ this.$events.on(SidebarEvent.STATUS, ({payload: {hasFloatingOverlay, mobile, information}}) => {
86
+ this.sidebarsFloating = hasFloatingOverlay
87
+ this.hasFloatingInformationBar = mobile && information
88
+ })
178
89
 
179
- get logoUrl () {
180
- return adminConfig.app.logo
181
- }
90
+ this.sidebarsFloating = sidebarService.hasFloatingOverlay
91
+ this.hasFloatingInformationBar = sidebarService.mobile && sidebarService.information
182
92
 
183
- get account () {
184
- if (this.hasAuthService) {
185
- return this.$auth.account
186
- }
187
- return null
93
+ this.$emit('appLoaded')
188
94
  }
189
95
 
190
- get title () {
191
- return adminConfig.app.title
96
+ closeFloatingSidebars () {
97
+ sidebarService.closeAllFloating()
192
98
  }
193
99
 
194
100
  get loaderColor () {
195
101
  return adminConfig.app.loaderColor
196
102
  }
197
103
 
198
- get rootRouteName () {
199
- return adminConfig.app.rootRouteName || 'root'
200
- }
201
-
202
104
  startLoading () {
203
105
  this.numLoadingRequests++
204
106
  }
@@ -206,66 +108,26 @@ export default class App extends Vue {
206
108
  stopLoading () {
207
109
  this.numLoadingRequests--
208
110
  }
209
-
210
- toggleDrawer () {
211
- this.drawer = !this.drawer
212
- }
213
-
214
- get hasAuthService () {
215
- return !!this.$auth
216
- }
217
-
218
- logout () {
219
- this.$auth.logout()
220
- }
221
111
  }
222
112
  </script>
223
113
 
224
114
 
225
115
  <style lang="scss" scoped>
226
- .accountName {
227
- line-height: 1.2;
228
- word-break: break-all;
229
- }
230
-
231
- .logoContainer {
232
- text-decoration: none;
233
- }
234
-
235
- .logo {
236
- max-height: 80px;
237
- max-width: 90%;
238
- }
239
-
240
116
  .isLoading {
241
117
  opacity: .6;
242
118
  }
243
119
 
244
- .sidebarToggleButton {
245
- width: 36px !important;
246
- height: 36px !important;
247
- margin-top: 1px;
120
+ .main-layout {
121
+ display: flex;
248
122
  }
249
123
 
250
- .topbar {
251
- position: relative;
252
- width: 100%;
253
- left: 0;
124
+ .loadingIndicator {
125
+ z-index: 3;
126
+ position: sticky;
254
127
  top: 0;
255
- height:40px;
256
- padding: .2rem 1.1rem;
257
- background-color: white;
258
- }
259
-
260
- .a-breadcrumbs {
261
- margin-top: 7px;
262
- }
263
-
264
- .menubar {
265
- // background: #666666 !important;
266
128
  }
267
129
 
268
- #sidebar {
269
- // background: #F4F4F4 !important;
130
+ #v-main.marginRight {
131
+ margin-right: 60px;
270
132
  }
271
133
  </style>
@@ -0,0 +1,64 @@
1
+ <template>
2
+ <div :class="['collapsible-section', {collapsed}]">
3
+ <h-separator
4
+ v-bind="{...$attrs, collapsible: true}"
5
+ :collapsed.sync="collapsed"
6
+ />
7
+
8
+ <a-info
9
+ v-if="showHint && hint"
10
+ type="info"
11
+ x-small
12
+ >
13
+ Inhalt eingeklappt. <a @click="collapsed = !collapsed">ausklappen</a>
14
+ </a-info>
15
+
16
+ <div style="height: 1px;" />
17
+
18
+ <collapse-transition>
19
+ <div
20
+ v-show="!collapsed"
21
+ class="content"
22
+ >
23
+ <slot />
24
+ </div>
25
+ </collapse-transition>
26
+ </div>
27
+ </template>
28
+
29
+
30
+ <script>
31
+ import { Component, Vue, Watch } from '@a-vue'
32
+
33
+ @Component({
34
+ props: [{showHint: true}]
35
+ })
36
+ export default class CollapsibleSection extends Vue {
37
+ collapsed = false
38
+ hint = false
39
+
40
+ @Watch('collapsed')
41
+ collapsedChanged () {
42
+ if (this.collapsed) {
43
+ setTimeout(() => {
44
+ this.hint = this.collapsed
45
+ }, 150)
46
+ } else {
47
+ this.hint = false
48
+ }
49
+ }
50
+ }
51
+ </script>
52
+
53
+
54
+ <style lang="scss" scoped>
55
+ .collapsible-section {
56
+ position: relative;
57
+ }
58
+
59
+ .a-info {
60
+ position: absolute;
61
+ margin-top: -1rem;
62
+ color: #666666;
63
+ }
64
+ </style>
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <information-bar-item
3
+ v-if="sidebar"
4
+ v-bind="$attrs"
5
+ >
6
+ <template #actionButton>
7
+ <slot name="actionButton" />
8
+ </template>
9
+
10
+ <slot />
11
+ </information-bar-item>
12
+
13
+ <detail-property
14
+ v-else
15
+ v-bind="$attrs"
16
+ >
17
+ <template #actionButton>
18
+ <slot name="actionButton" />
19
+ </template>
20
+
21
+ <slot />
22
+ </detail-property>
23
+ </template>
24
+
25
+ <script>
26
+ import { Component, Vue } from '@a-vue'
27
+
28
+ @Component({
29
+ props: [{sidebar: false}]
30
+ })
31
+ export default class DetailOrInfo extends Vue {
32
+ }
33
+ </script>
@@ -46,6 +46,25 @@ export default class FlyingContextContainer extends Vue {
46
46
  sizeWatcher.observe(this.getChildrenContainer())
47
47
  }
48
48
 
49
+ /**
50
+ * park sidebar children and attach - only for use with HMR which would remove all children on destroy 234567890
51
+ */
52
+ destroyed () {
53
+ function moveChildren (from, to) {
54
+ for (const child of from.children) {
55
+ to.appendChild(child)
56
+ }
57
+ }
58
+
59
+ const elTmp = document.createElement('div')
60
+ document.body.appendChild(elTmp)
61
+ moveChildren(this.getChildrenContainer(), elTmp)
62
+
63
+ this.$nextTick(() => {
64
+ moveChildren(elTmp, document.querySelector('#flyingContextContainer__children'))
65
+ })
66
+ }
67
+
49
68
  getScrollbarWidth () {
50
69
  const el = document.documentElement
51
70
  const overflowY = getComputedStyle(el)['overflow-y']
@@ -157,7 +176,8 @@ export default class FlyingContextContainer extends Vue {
157
176
  transition: left .2s;
158
177
  padding: 2rem;
159
178
  overflow-y: auto;
160
- border-left: 1px solid rgba(0, 0, 0, .12);
179
+ box-shadow: 0 0 17px #00000033;
180
+ border-left: 1px solid #DDDDDD;
161
181
 
162
182
  &:not(.visible) {
163
183
  left: 101vw;
@@ -0,0 +1,90 @@
1
+ <template>
2
+ <div :class="['h-separator', {first}]">
3
+ <hr>
4
+
5
+ <div
6
+ :class="['label', {collapsible}]"
7
+ @click="collapseClick"
8
+ >
9
+ {{ label }}
10
+
11
+ <template v-if="collapsible">
12
+ <v-icon class="contextButton mt-n1 ml-n2">
13
+ {{ collapsed_ ? '$caretRightIcon' : '$caretDownIcon' }}
14
+ </v-icon>
15
+ </template>
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+
21
+ <script>
22
+ import { Component, Vue, Watch } from '@a-vue'
23
+
24
+ @Component({
25
+ props: ['label', {first: false, collapsible: false, collapsed: false}]
26
+ })
27
+ export default class HSeparator extends Vue {
28
+ collapsed_ = false
29
+
30
+ created () {
31
+ this.collapsed_ = this.collapsed
32
+ }
33
+
34
+ @Watch('collapsed')
35
+ collapsedChangedFromOutside () {
36
+ this.collapsed_ = this.collapsed
37
+ }
38
+
39
+ collapseClick () {
40
+ this.collapsed_ = !this.collapsed_
41
+ this.$emit('update:collapsed', this.collapsed_)
42
+ }
43
+ }
44
+ </script>
45
+
46
+
47
+ <style lang="scss" scoped>
48
+ .h-separator {
49
+ position: relative;
50
+ display: flex;
51
+ flex-direction: column;
52
+ justify-content: center;
53
+ margin: 5rem 0 3rem;
54
+
55
+ &.first{
56
+ margin-top: 0;
57
+ }
58
+ }
59
+
60
+ hr {
61
+ border: none;
62
+ border-top: 2px solid #EEEEEE;
63
+ }
64
+
65
+ .label {
66
+ position: absolute;
67
+ background: white;
68
+ padding: 0 1rem;
69
+ text-transform: uppercase;
70
+ letter-spacing: 5px;
71
+ color: #CCCCCC;
72
+ font-size: .8rem;
73
+ white-space: nowrap;
74
+
75
+ left: 45%;
76
+ transform: translateX(-50%);
77
+
78
+ &.collapsible {
79
+ cursor: pointer;
80
+
81
+ &:hover {
82
+ color: #333333;
83
+
84
+ .v-icon {
85
+ color: #333333 !important;
86
+ }
87
+ }
88
+ }
89
+ }
90
+ </style>