@afeefa/vue-app 0.0.172 → 0.0.174

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. package/.afeefa/package/release/version.txt +1 -1
  2. package/package.json +1 -1
  3. package/src/components/AInfo.vue +11 -1
  4. package/src/components/ALoadingIndicator.vue +4 -0
  5. package/src/components/ATable.vue +9 -4
  6. package/src/components/ATableHeader.vue +3 -1
  7. package/src/components/ATableRow.vue +11 -5
  8. package/src/plugins/route-config/RouteConfigPlugin.js +17 -0
  9. package/src/utils/format-time.js +17 -0
  10. package/src-admin/components/App.vue +48 -186
  11. package/src-admin/components/CollapsibleSection.vue +64 -0
  12. package/src-admin/components/FlyingContextContainer.vue +1 -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 +39 -8
  17. package/src-admin/components/app/AppBarTitle.vue +6 -11
  18. package/src-admin/components/detail/DetailProperty.vue +11 -16
  19. package/src-admin/components/form/RemoveDialog.vue +1 -1
  20. package/src-admin/components/index.js +9 -2
  21. package/src-admin/components/list/ListView.vue +31 -29
  22. package/src-admin/components/sidebar/InformationBarItem.vue +178 -0
  23. package/src-admin/components/sidebar/SidebarEvent.js +5 -0
  24. package/src-admin/components/sidebar/SidebarService.js +107 -0
  25. package/src-admin/components/transitions/CollapseTransition.vue +61 -0
  26. package/src-admin/config/vuetify.js +9 -1
  27. package/src-admin/events.js +1 -0
  28. package/src-admin/styles.scss +10 -2
  29. package/src-admin/components/Sidebar.vue +0 -66
  30. package/src-admin/components/SidebarItem.vue +0 -59
@@ -1 +1 @@
1
- 0.0.172
1
+ 0.0.174
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.172",
3
+ "version": "0.0.174",
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,20 @@
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
+ .xSmall {
28
+ padding: .3rem .6rem;
29
+ font-size: .9rem;
30
+
31
+ :deep(.v-icon) {
32
+ margin-left: .2rem;
33
+ margin-right: .4rem;
34
+ }
35
+ }
26
36
  </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>
@@ -34,7 +34,7 @@ export default class ATable extends Vue {
34
34
  <style scoped lang="scss">
35
35
  .a-table {
36
36
  display: table;
37
- border-collapse: collapse;
37
+ border-collapse: separate;
38
38
  width: 100%;
39
39
 
40
40
  &.width-auto {
@@ -53,10 +53,15 @@ export default class ATable extends Vue {
53
53
 
54
54
  white-space: nowrap;
55
55
  vertical-align: middle;
56
+ max-width: 300px;
56
57
 
57
- &.info {
58
- background: none !important;
59
- color: #888888;
58
+ .a-table-cell-truncate {
59
+ overflow: hidden;
60
+ text-overflow: ellipsis;
61
+ }
62
+
63
+ &.text--info {
64
+ color: #888888 !important;
60
65
  }
61
66
  }
62
67
  }
@@ -46,17 +46,19 @@ export default class ATableHeader extends Vue {
46
46
  > * {
47
47
  padding: .4rem 0;
48
48
  padding-right: 1rem;
49
+
49
50
  &:last-child {
50
51
  padding-right: 0;
51
52
  }
52
53
  }
53
54
 
54
55
  &.border {
55
- border-bottom: 1px solid #EEEEEE;
56
56
  > * {
57
+ border-bottom: 1px solid #EEEEEE;
57
58
  padding-left: .5rem;
58
59
  padding-right: 1rem;
59
60
  padding-bottom: .6rem;
61
+
60
62
  &:last-child {
61
63
  padding-right: .2rem;
62
64
  }
@@ -49,9 +49,8 @@ export default class ATableRow extends Vue {
49
49
  }
50
50
 
51
51
  &.border {
52
- border-bottom: 1px solid #E5E5E5;
53
-
54
52
  > * {
53
+ border-bottom: 1px solid #E5E5E5;
55
54
  padding: .4rem 1.5rem .4rem .4rem;
56
55
 
57
56
  &:last-child {
@@ -65,7 +64,9 @@ export default class ATableRow extends Vue {
65
64
  }
66
65
 
67
66
  &:hover, &.selected {
68
- background: #F4F4F4;
67
+ & > * {
68
+ background: #F4F4F4;
69
+ }
69
70
  }
70
71
 
71
72
  &.disabled {
@@ -73,11 +74,11 @@ export default class ATableRow extends Vue {
73
74
  opacity: .5;
74
75
  }
75
76
 
76
- &.active {
77
+ &.active > * {
77
78
  background: #EEEEFF;
78
79
  }
79
80
 
80
- &:last-child {
81
+ &:last-child > * {
81
82
  border: none;
82
83
  }
83
84
 
@@ -116,6 +117,11 @@ export default class ATableRow extends Vue {
116
117
  line-height: .9;
117
118
  }
118
119
 
120
+ .textblock--tiny {
121
+ font-size: .8rem;
122
+ line-height: .8;
123
+ }
124
+
119
125
  [class*=text-] {
120
126
  color: inherit;
121
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>
@@ -157,7 +157,7 @@ export default class FlyingContextContainer extends Vue {
157
157
  transition: left .2s;
158
158
  padding: 2rem;
159
159
  overflow-y: auto;
160
- border-left: 1px solid rgba(0, 0, 0, .12);
160
+ box-shadow: 0 0 7px #00000033;
161
161
 
162
162
  &:not(.visible) {
163
163
  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>