@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
@@ -0,0 +1,209 @@
1
+ <template>
2
+ <div class="informationBarItem">
3
+ <div
4
+ :class="['item', infoItemId, {expanded, rail}]"
5
+ :style="{width}"
6
+ >
7
+ <a-row justify-space-between>
8
+ <div
9
+ class="header"
10
+ @click="derail"
11
+ >
12
+ <v-icon
13
+ v-if="_icon"
14
+ :color="_icon.color"
15
+ size="2rem"
16
+ >
17
+ {{ _icon.icon }}
18
+ </v-icon>
19
+
20
+ <div
21
+ v-else
22
+ class="iconPlaceholder"
23
+ />
24
+
25
+ <template v-if="!rail">
26
+ <label class="label">{{ label }}</label>
27
+
28
+ <v-icon class="contextButton mt-n1">
29
+ {{ expanded ? '$caretDownIcon' : '$caretRightIcon' }}
30
+ </v-icon>
31
+ </template>
32
+ </div>
33
+
34
+ <div v-if="expanded">
35
+ <slot name="actionButton" />
36
+ </div>
37
+ </a-row>
38
+
39
+ <collapse-transition>
40
+ <div
41
+ v-if="!rail && expanded"
42
+ class="content"
43
+ >
44
+ <a-row
45
+ vertical
46
+ gap="6"
47
+ >
48
+ <slot />
49
+ </a-row>
50
+ </div>
51
+ </collapse-transition>
52
+ </div>
53
+ </div>
54
+ </template>
55
+
56
+ <script>
57
+ import { Component, Vue } from '@a-vue'
58
+ import { randomCssClass } from '@a-vue/utils/random'
59
+ import { sidebarService } from './SidebarService'
60
+ import { SidebarEvent } from '@a-admin/events'
61
+
62
+ @Component({
63
+ props: [
64
+ 'icon',
65
+ 'iconModelType',
66
+ 'label',
67
+ {
68
+ top: true,
69
+ bottom: false,
70
+ width: 'auto',
71
+ open: false
72
+ }
73
+ ]
74
+ })
75
+ export default class InformationBarItem extends Vue {
76
+ infoItemId = randomCssClass(10)
77
+ rail = sidebarService.informationRailed
78
+ expanded = !this.rail && this.open
79
+ isCreated = false
80
+
81
+ created () {
82
+ this.$events.on(SidebarEvent.STATUS, this.railChanged)
83
+ }
84
+
85
+ mounted () {
86
+ const container = this.getSidebarContainer()
87
+ container.appendChild(this.getContent())
88
+ }
89
+
90
+ destroyed () {
91
+ const container = this.getSidebarContainer()
92
+ const el = this.getContent()
93
+ if (container.contains(el)) {
94
+ container.removeChild(el)
95
+ }
96
+
97
+ this.$events.off(SidebarEvent.STATUS, this.railChanged)
98
+ }
99
+
100
+ get _icon () {
101
+ if (this.icon) {
102
+ return this.icon
103
+ }
104
+
105
+ if (this.iconModelType) {
106
+ const ModelClass = this.$apiResources.getModelClass(this.iconModelType)
107
+ return ModelClass.icon
108
+ }
109
+ }
110
+
111
+ railChanged ({payload: {informationRailed}}) {
112
+ if (this.rail === informationRailed) {
113
+ return
114
+ }
115
+
116
+ this.rail = informationRailed
117
+
118
+ if (!this.rail) { // derailed
119
+ if (!this.isCreated) { // open only the first time not after subsequent derailing
120
+ this.expanded = this.open
121
+ }
122
+ }
123
+
124
+ this.isCreated = true
125
+ }
126
+
127
+ derail () {
128
+ const railed = this.rail
129
+
130
+ sidebarService.setRailInformation(false)
131
+
132
+ if (railed) {
133
+ this.expanded = true
134
+ } else {
135
+ this.expanded = !this.expanded
136
+ }
137
+ }
138
+
139
+ getContent () {
140
+ return document.querySelector('.' + this.infoItemId)
141
+ }
142
+
143
+ getSidebarContainer () {
144
+ return document.querySelector('#information-bar__children > .' + this.position)
145
+ }
146
+
147
+ get position () {
148
+ if (this.bottom) {
149
+ return 'bottom'
150
+ } else {
151
+ return 'top'
152
+ }
153
+ }
154
+ }
155
+ </script>
156
+
157
+
158
+ <style lang="scss" scoped>
159
+ .item {
160
+ min-width: 100%;
161
+ margin-bottom: 1rem;
162
+
163
+ &:last-child {
164
+ margin-bottom: 0;
165
+ }
166
+
167
+ &.rail {
168
+ margin-bottom: .5rem;
169
+ }
170
+ }
171
+
172
+ .header {
173
+ display: flex;
174
+ flex-wrap: nowrap;
175
+ align-items: center;
176
+ font-size: .8rem;
177
+ cursor: pointer;
178
+
179
+ > .v-icon {
180
+ margin-right: .75rem;
181
+ }
182
+
183
+ .label {
184
+ display: block;
185
+ text-transform: uppercase;
186
+ letter-spacing: 3px;
187
+ color: #666666;
188
+ cursor: pointer;
189
+ }
190
+
191
+ &:hover {
192
+ label {
193
+ color: #333333;
194
+ }
195
+
196
+ .v-icon.contextButton {
197
+ color: #333333 !important;
198
+ }
199
+ }
200
+ }
201
+
202
+ .content {
203
+ border-top: 2px solid #EEEEEE;
204
+ font-size: .9rem;
205
+
206
+ margin: .25rem -1.5rem;
207
+ padding: 1rem 1.5rem;
208
+ }
209
+ </style>
@@ -0,0 +1,5 @@
1
+ import { BaseEvent } from '@a-vue/plugins/event-bus/BaseEvent'
2
+
3
+ export class SidebarEvent extends BaseEvent {
4
+ static STATUS = 'SidebarEvent:status'
5
+ }
@@ -0,0 +1,107 @@
1
+ import { eventBus } from '@a-vue/plugins/event-bus/EventBus'
2
+
3
+ import { SidebarEvent } from './SidebarEvent'
4
+
5
+ export class SidebarState {
6
+ navigation = false
7
+ informationDerailed = false
8
+ informationRailed = false
9
+ mobile = false
10
+
11
+ constructor (service) {
12
+ this.navigation = service.navigation
13
+ this.information = service.information
14
+ this.informationRailed = service.informationRailed
15
+ this.mobile = service.mobile
16
+ this.hasFloatingOverlay = service.hasFloatingOverlay
17
+ }
18
+ }
19
+
20
+ class SidebarService {
21
+ navigation = true
22
+ information = false
23
+ informationRailed = false
24
+ mobile = false
25
+
26
+ constructor () {
27
+ window.addEventListener('resize', () => this.checkIsMobile())
28
+
29
+ this.checkIsMobile()
30
+ }
31
+
32
+ checkIsMobile () {
33
+ const old = this.mobile
34
+
35
+ const width = window.innerWidth
36
+ this.mobile = width < 1200
37
+
38
+ if (old !== this.mobile) {
39
+ if (!this.mobile) { // expand if destop
40
+ this.navigation = true
41
+ }
42
+
43
+ if (this.information) { // rail if mobile, derail if desktop
44
+ this.informationRailed = this.mobile
45
+ }
46
+
47
+ eventBus.dispatch(new SidebarEvent(SidebarEvent.STATUS, new SidebarState(this)))
48
+ }
49
+ }
50
+
51
+ setNavigation (navigation) {
52
+ if (this.navigation === navigation) {
53
+ return
54
+ }
55
+
56
+ this.navigation = navigation
57
+
58
+ eventBus.dispatch(new SidebarEvent(SidebarEvent.STATUS, new SidebarState(this)))
59
+ }
60
+
61
+ setInformation (information) {
62
+ if (this.information === information) {
63
+ return
64
+ }
65
+
66
+ this.information = information
67
+
68
+ if (information) { // rail if mobile, derail if desktop
69
+ this.informationRailed = this.mobile
70
+ }
71
+
72
+ eventBus.dispatch(new SidebarEvent(SidebarEvent.STATUS, new SidebarState(this)))
73
+ }
74
+
75
+ setRailInformation (rail) {
76
+ if (this.informationRailed === rail) {
77
+ return
78
+ }
79
+
80
+ this.informationRailed = rail
81
+
82
+ eventBus.dispatch(new SidebarEvent(SidebarEvent.STATUS, new SidebarState(this)))
83
+ }
84
+
85
+ closeAllFloating () {
86
+ this.setNavigation(false)
87
+ this.setRailInformation(true)
88
+ }
89
+
90
+ get hasFloatingOverlay () {
91
+ if (!this.mobile) {
92
+ return false
93
+ }
94
+
95
+ if (this.navigation) {
96
+ return true
97
+ }
98
+
99
+ if (this.information) {
100
+ return !this.informationRailed
101
+ }
102
+
103
+ return false
104
+ }
105
+ }
106
+
107
+ export const sidebarService = new SidebarService()
@@ -0,0 +1,61 @@
1
+ <template>
2
+ <transition
3
+ name="collapse-transition"
4
+ @enter="enter"
5
+ @after-enter="afterEnter"
6
+ @leave="leave"
7
+ @after-leave="afterLeave"
8
+ >
9
+ <slot />
10
+ </transition>
11
+ </template>
12
+
13
+ <script>
14
+ // concepts by https://github.com/ivanvermeyen/vue-collapse-transition
15
+ import { Component, Vue } from '@a-vue'
16
+
17
+ @Component({
18
+ props: [{ duration: 150, min: 0 }]
19
+ })
20
+ export default class CollapseTransition extends Vue {
21
+ enter (el, done) {
22
+ const h = el.offsetHeight
23
+
24
+ el.style.height = this.min + 'px'
25
+ el.style.overflow = 'hidden'
26
+
27
+ getComputedStyle(el).height // force repaint
28
+
29
+ el.style.transition = 'height ' + this.duration + 'ms'
30
+ el.style.height = h + 'px'
31
+
32
+ setTimeout(done, this.duration)
33
+ }
34
+
35
+ afterEnter (el) {
36
+ el.style.transition = ''
37
+ el.style.overflow = ''
38
+ el.style.height = ''
39
+ }
40
+
41
+ leave (el, done) {
42
+ const h = el.offsetHeight
43
+
44
+ el.style.height = h + 'px'
45
+ el.style.overflow = 'hidden'
46
+
47
+ getComputedStyle(el).height // force repaint
48
+
49
+ el.style.transition = 'height ' + this.duration + 'ms'
50
+ el.style.height = this.min + 'px'
51
+
52
+ setTimeout(done, this.duration)
53
+ }
54
+
55
+ afterLeave (el) {
56
+ el.style.transition = ''
57
+ el.style.overflow = ''
58
+ el.style.height = ''
59
+ }
60
+ }
61
+ </script>
@@ -2,6 +2,7 @@ import {
2
2
  mdiAlarmLightOutline,
3
3
  mdiAlert,
4
4
  mdiArrowLeft,
5
+ mdiArrowRight,
5
6
  mdiCalendar,
6
7
  mdiCheck,
7
8
  mdiCheckBold,
@@ -13,11 +14,13 @@ import {
13
14
  mdiDotsHorizontal,
14
15
  mdiDotsVertical,
15
16
  mdiFilter,
17
+ mdiInformationOutline,
16
18
  mdiLock,
17
19
  mdiLockOpenVariant,
18
20
  mdiLogoutVariant,
19
21
  mdiMagnify,
20
22
  mdiMenuDown,
23
+ mdiMenuRight,
21
24
  mdiMenuUp,
22
25
  mdiPalette,
23
26
  mdiPencil,
@@ -56,13 +59,16 @@ export default new Vuetify({
56
59
  checkIcon: mdiCheck,
57
60
  checkBoldIcon: mdiCheckBold,
58
61
  arrowLeftIcon: mdiArrowLeft,
62
+ arrowRightIcon: mdiArrowRight,
59
63
  caretDownIcon: mdiMenuDown,
60
64
  caretUpIcon: mdiMenuUp,
65
+ caretRightIcon: mdiMenuRight,
61
66
  printerIcon: mdiPrinter,
62
67
  euroSymbol: mdiCurrencyEur,
63
68
  paletteIcon: mdiPalette,
64
69
  addIcon: mdiPlusCircle,
65
- filterIcon: mdiFilter
70
+ filterIcon: mdiFilter,
71
+ infoIcon: mdiInformationOutline
66
72
  }
67
73
  },
68
74
  breakpoint: {
@@ -0,0 +1 @@
1
+ export { SidebarEvent } from './components/sidebar/SidebarEvent'
@@ -1,5 +1,13 @@
1
1
  html {
2
- overflow-y: auto; // ress.css • v2.0.4 sets overflow-y: scroll
2
+ // overflow-y: auto; // ress.css • v2.0.4 sets overflow-y: scroll
3
+ overflow: hidden;
4
+ }
5
+
6
+ #v-main {
7
+ overflow-y: auto;
8
+ overflow-x: auto;
9
+ height: 100vh;
10
+ flex: 1 1 auto;
3
11
  }
4
12
 
5
13
  .container {
@@ -17,7 +25,7 @@ html {
17
25
  }
18
26
 
19
27
  .contextButton {
20
- color: #AAAAAA !important;
28
+ color: #999999 !important;
21
29
  cursor: pointer;
22
30
 
23
31
  &:hover {
@@ -1,66 +0,0 @@
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>
@@ -1,59 +0,0 @@
1
- <template>
2
- <div class="sidebarItem">
3
- <div :class="contextId">
4
- <slot />
5
- </div>
6
- </div>
7
- </template>
8
-
9
- <script>
10
- import { Component, Vue } from '@a-vue'
11
- import { randomCssClass } from '@a-vue/utils/random'
12
-
13
- @Component({
14
- props: [
15
- {
16
- top: true,
17
- bottom: false
18
- }
19
- ]
20
- })
21
- export default class SidebarItem extends Vue {
22
- contextId = randomCssClass(10)
23
-
24
- mounted () {
25
- const container = this.getSidebarContainer()
26
- console.log(container)
27
- container.appendChild(this.getContent())
28
- }
29
-
30
- destroyed () {
31
- const container = this.getSidebarContainer()
32
- const el = this.getContent()
33
- if (container.contains(el)) {
34
- container.removeChild(el)
35
- }
36
- }
37
-
38
- getContent () {
39
- return document.querySelector('.' + this.contextId)
40
- }
41
-
42
- getSidebarContainer () {
43
- console.log('toporbottom', this.$props)
44
- return document.querySelector('#sidebar__children > .' + this.position)
45
- }
46
-
47
- get position () {
48
- if (this.bottom) {
49
- return 'bottom'
50
- } else {
51
- return 'top'
52
- }
53
- }
54
- }
55
- </script>
56
-
57
-
58
- <style lang="scss" scoped>
59
- </style>