@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
@@ -0,0 +1,178 @@
1
+ <template>
2
+ <div class="informationBarItem">
3
+ <div
4
+ :class="['item', infoItemId, {expanded, rail}]"
5
+ :style="{width}"
6
+ >
7
+ <div
8
+ class="header"
9
+ @click="derail"
10
+ >
11
+ <v-icon
12
+ :color="icon.color"
13
+ size="2rem"
14
+ >
15
+ {{ icon.icon }}
16
+ </v-icon>
17
+
18
+ <template v-if="!rail">
19
+ <label class="label">{{ label }}</label>
20
+
21
+ <v-icon class="contextButton mt-n1">
22
+ {{ expanded ? '$caretDownIcon' : '$caretRightIcon' }}
23
+ </v-icon>
24
+ </template>
25
+ </div>
26
+
27
+ <collapse-transition>
28
+ <div
29
+ v-if="!rail && expanded"
30
+ class="content"
31
+ >
32
+ <a-row
33
+ vertical
34
+ gap="6"
35
+ >
36
+ <slot />
37
+ </a-row>
38
+ </div>
39
+ </collapse-transition>
40
+ </div>
41
+ </div>
42
+ </template>
43
+
44
+ <script>
45
+ import { Component, Vue } from '@a-vue'
46
+ import { randomCssClass } from '@a-vue/utils/random'
47
+ import { sidebarService } from './SidebarService'
48
+ import { SidebarEvent } from '@a-admin/events'
49
+
50
+ @Component({
51
+ props: [
52
+ 'icon',
53
+ 'label',
54
+ {
55
+ top: true,
56
+ bottom: false,
57
+ width: 'auto',
58
+ open: false
59
+ }
60
+ ]
61
+ })
62
+ export default class InformationBarItem extends Vue {
63
+ infoItemId = randomCssClass(10)
64
+ rail = sidebarService.informationRailed
65
+ expanded = !this.rail && this.open
66
+
67
+ created () {
68
+ this.$events.on(SidebarEvent.STATUS, ({payload: {informationRailed}}) => this.railChanged(informationRailed))
69
+ }
70
+
71
+ mounted () {
72
+ const container = this.getSidebarContainer()
73
+ container.appendChild(this.getContent())
74
+ }
75
+
76
+ destroyed () {
77
+ const container = this.getSidebarContainer()
78
+ const el = this.getContent()
79
+ if (container.contains(el)) {
80
+ container.removeChild(el)
81
+ }
82
+ }
83
+
84
+ railChanged (rail) {
85
+ if (this.rail === rail) {
86
+ return
87
+ }
88
+
89
+ this.rail = rail
90
+
91
+ if (!this.rail) {
92
+ this.expanded = false
93
+ }
94
+ }
95
+
96
+ derail () {
97
+ const railed = this.rail
98
+
99
+ sidebarService.setRailInformation(false)
100
+
101
+ if (railed) {
102
+ this.expanded = true
103
+ } else {
104
+ this.expanded = !this.expanded
105
+ }
106
+ }
107
+
108
+ getContent () {
109
+ return document.querySelector('.' + this.infoItemId)
110
+ }
111
+
112
+ getSidebarContainer () {
113
+ return document.querySelector('#information-bar__children > .' + this.position)
114
+ }
115
+
116
+ get position () {
117
+ if (this.bottom) {
118
+ return 'bottom'
119
+ } else {
120
+ return 'top'
121
+ }
122
+ }
123
+ }
124
+ </script>
125
+
126
+
127
+ <style lang="scss" scoped>
128
+ .item {
129
+ min-width: 100%;
130
+ margin-bottom: 1rem;
131
+
132
+ &:last-child {
133
+ margin-bottom: 0;
134
+ }
135
+
136
+ &.rail {
137
+ margin-bottom: .5rem;
138
+ }
139
+ }
140
+
141
+ .header {
142
+ display: flex;
143
+ flex-wrap: nowrap;
144
+ align-items: center;
145
+ font-size: .8rem;
146
+ cursor: pointer;
147
+
148
+ > .v-icon {
149
+ margin-right: .75rem;
150
+ }
151
+
152
+ .label {
153
+ display: block;
154
+ text-transform: uppercase;
155
+ letter-spacing: 3px;
156
+ color: #666666;
157
+ cursor: pointer;
158
+ }
159
+
160
+ &:hover {
161
+ label {
162
+ color: #333333;
163
+ }
164
+
165
+ .v-icon.contextButton {
166
+ color: #333333 !important;
167
+ }
168
+ }
169
+ }
170
+
171
+ .content {
172
+ border-top: 2px solid #EEEEEE;
173
+ font-size: .9rem;
174
+
175
+ margin: .5rem -1.5rem;
176
+ padding: .5rem 1.5rem;
177
+ }
178
+ </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 && this.mobile) {
69
+ this.informationRailed = true
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,10 +14,13 @@ import {
13
14
  mdiDotsHorizontal,
14
15
  mdiDotsVertical,
15
16
  mdiFilter,
17
+ mdiInformationOutline,
16
18
  mdiLock,
19
+ mdiLockOpenVariant,
17
20
  mdiLogoutVariant,
18
21
  mdiMagnify,
19
22
  mdiMenuDown,
23
+ mdiMenuRight,
20
24
  mdiMenuUp,
21
25
  mdiPalette,
22
26
  mdiPencil,
@@ -51,16 +55,20 @@ export default new Vuetify({
51
55
  calendarIcon: mdiCalendar,
52
56
  searchIcon: mdiMagnify,
53
57
  lockIcon: mdiLock,
58
+ lockOpenIcon: mdiLockOpenVariant,
54
59
  checkIcon: mdiCheck,
55
60
  checkBoldIcon: mdiCheckBold,
56
61
  arrowLeftIcon: mdiArrowLeft,
62
+ arrowRightIcon: mdiArrowRight,
57
63
  caretDownIcon: mdiMenuDown,
58
64
  caretUpIcon: mdiMenuUp,
65
+ caretRightIcon: mdiMenuRight,
59
66
  printerIcon: mdiPrinter,
60
67
  euroSymbol: mdiCurrencyEur,
61
68
  paletteIcon: mdiPalette,
62
69
  addIcon: mdiPlusCircle,
63
- filterIcon: mdiFilter
70
+ filterIcon: mdiFilter,
71
+ infoIcon: mdiInformationOutline
64
72
  }
65
73
  },
66
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>