@afeefa/vue-app 0.0.75 → 0.0.78

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1 @@
1
- 0.0.75
1
+ 0.0.78
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.75",
3
+ "version": "0.0.78",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
@@ -18,7 +18,7 @@ export class SaveAction extends ApiAction {
18
18
 
19
19
  processError (result) {
20
20
  eventBus.dispatch(new AlertEvent(AlertEvent.ERROR, {
21
- headline: 'Die Daten konntent nicht gespeichert werden.',
21
+ headline: 'Die Daten konnten nicht gespeichert werden.',
22
22
  message: result.message,
23
23
  detail: result.detail
24
24
  }))
@@ -17,9 +17,10 @@
17
17
  <h3>{{ _headline }}</h3>
18
18
 
19
19
  <div v-html="message" />
20
+
20
21
  <div
21
22
  v-if="detail"
22
- class="pt-3"
23
+ class="pt-1 details"
23
24
  v-html="detail"
24
25
  />
25
26
  </div>
@@ -126,7 +127,12 @@ export default class AAlert extends Vue {
126
127
 
127
128
  h3 {
128
129
  margin-bottom: .5rem;
129
- font-size: 1.4rem;
130
+ font-size: 1.2rem;
131
+ line-height: 1.2;
132
+ }
133
+
134
+ .details {
135
+ font-size: .9rem;
130
136
  }
131
137
 
132
138
  .closeButton {
@@ -5,8 +5,9 @@
5
5
  :contentClass="_dialogId"
6
6
  transition="v-fade-transition"
7
7
  v-bind="$attrs"
8
+ persistent
9
+ no-click-animation
8
10
  @click:outside="cancel"
9
- @keydown.esc="cancel"
10
11
  >
11
12
  <template #activator="{ on }">
12
13
  <div v-on="on">
@@ -18,7 +19,7 @@
18
19
  v-if="dialog"
19
20
  class="pb-1"
20
21
  >
21
- <v-card-title>
22
+ <v-card-title class="pa-3">
22
23
  {{ title }}
23
24
  </v-card-title>
24
25
 
@@ -26,7 +27,7 @@
26
27
  <span v-html="message" />
27
28
  </v-card-text>
28
29
 
29
- <v-card-text>
30
+ <v-card-text v-if="$slots.default">
30
31
  <slot :props="props" />
31
32
  </v-card-text>
32
33
 
@@ -59,11 +60,12 @@ import { DialogEvent } from './dialog/DialogEvent'
59
60
  import { PositionConfig } from '../services/PositionService'
60
61
  import { UsesPositionServiceMixin } from '../services/position/UsesPositionServiceMixin'
61
62
  import { randomCssClass } from '../utils/random'
63
+ import { CancelOnEscMixin } from '@a-vue/services/escape/CancelOnEscMixin'
62
64
 
63
65
  @Component({
64
66
  props: ['id', 'anchor', 'active', 'payload']
65
67
  })
66
- export default class ADialog extends Mixins(UsesPositionServiceMixin) {
68
+ export default class ADialog extends Mixins(UsesPositionServiceMixin, CancelOnEscMixin) {
67
69
  dialogId = randomCssClass(10)
68
70
 
69
71
  title = null
@@ -88,6 +90,11 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin) {
88
90
  this.$events.off(DialogEvent.SHOW, this.show)
89
91
  }
90
92
 
93
+ coe_cancelOnEsc () {
94
+ this.cancel()
95
+ return false // stop esc propagation
96
+ }
97
+
91
98
  @Watch('dialog')
92
99
  dialogChanged () {
93
100
  // called without event from activator
@@ -105,6 +112,13 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin) {
105
112
 
106
113
  this.calledViaEvent = false
107
114
  }
115
+
116
+ // register for esc
117
+ if (this.dialog) {
118
+ this.coe_watchCancel()
119
+ } else {
120
+ this.coe_unwatchCancel()
121
+ }
108
122
  }
109
123
 
110
124
  get _dialogId () {
@@ -195,11 +209,11 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin) {
195
209
  <style lang="scss" scoped>
196
210
  .v-card__title {
197
211
  background: #EEEEEE;
198
- padding: .3rem 1rem !important;
212
+ padding: .6rem 1rem .3rem !important;
199
213
  }
200
214
 
201
215
  .v-card__text {
202
- padding: .5rem 1rem !important;
216
+ padding: .8rem 1rem !important;
203
217
  }
204
218
 
205
219
  ::v-deep .v-dialog {
@@ -7,10 +7,9 @@
7
7
  v-bind="$attrs"
8
8
  :contentClass="modalId"
9
9
  transition="v-fade-transition"
10
- :persistent="true"
11
- :no-click-animation="true"
10
+ persistent
11
+ no-click-animation
12
12
  @click:outside="cancel"
13
- @keydown.esc="cancel"
14
13
  >
15
14
  <template #activator="{ on }">
16
15
  <div
@@ -41,11 +40,12 @@ import { UsesPositionServiceMixin } from '@a-vue/services/position/UsesPositionS
41
40
  import { randomCssClass } from '../utils/random'
42
41
  import { getZIndex } from 'vuetify/lib/util/helpers'
43
42
  import { ComponentWidthMixin } from './mixins/ComponentWidthMixin'
43
+ import { CancelOnEscMixin } from '@a-vue/services/escape/CancelOnEscMixin'
44
44
 
45
45
  @Component({
46
46
  props: ['show', 'title', 'beforeClose', 'triggerClass', 'anchorPosition']
47
47
  })
48
- export default class ADialog extends Mixins(UsesPositionServiceMixin, ComponentWidthMixin) {
48
+ export default class ADialog extends Mixins(UsesPositionServiceMixin, ComponentWidthMixin, CancelOnEscMixin) {
49
49
  modalId = randomCssClass(10)
50
50
 
51
51
  modal = false
@@ -79,6 +79,11 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin, ComponentW
79
79
  }
80
80
  }
81
81
 
82
+ coe_cancelOnEsc () {
83
+ this.cancel()
84
+ return false // stop esc propagation
85
+ }
86
+
82
87
  /**
83
88
  * visiblility changes from outside
84
89
  * this will trigger the modal watcher
@@ -107,6 +112,14 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin, ComponentW
107
112
  } else {
108
113
  this.removeTransientAnchor()
109
114
  }
115
+
116
+ // register for esc
117
+ if (this.modal) {
118
+ this.coe_watchCancel()
119
+ } else {
120
+ this.coe_unwatchCancel()
121
+ }
122
+
110
123
  this.$emit('update:show', this.modal)
111
124
  }
112
125
 
@@ -168,11 +181,11 @@ export default class ADialog extends Mixins(UsesPositionServiceMixin, ComponentW
168
181
  <style lang="scss" scoped>
169
182
  .v-card__title {
170
183
  background: #EEEEEE;
171
- padding: .3rem 1rem !important;
184
+ padding: .6rem 1rem .3rem !important;
172
185
  }
173
186
 
174
187
  .v-card__text {
175
- padding: .5rem 1rem !important;
188
+ padding: .8rem 1rem !important;
176
189
  color: inherit !important;
177
190
  }
178
191
 
@@ -9,9 +9,12 @@
9
9
  <template v-for="option in options_">
10
10
  <v-radio
11
11
  :key="option.itemText"
12
- :label="option.itemText"
13
12
  :value="option.itemValue"
14
- />
13
+ >
14
+ <template #label>
15
+ <div v-html="option.itemText" />
16
+ </template>
17
+ </v-radio>
15
18
  </template>
16
19
  </v-radio-group>
17
20
  </template>
@@ -62,6 +65,7 @@ export default class ARadioGroup extends Vue {
62
65
 
63
66
  <style lang="scss" scoped>
64
67
  .v-input {
68
+ margin: 0;
65
69
 
66
70
  &:not(.hasLabel) {
67
71
  ::v-deep legend {
@@ -22,6 +22,8 @@ import { ComponentWidthMixin } from './mixins/ComponentWidthMixin'
22
22
  props: ['focus', 'debounce', 'validator', {password: false, number: false}]
23
23
  })
24
24
  export default class ATextField extends Mixins(ComponentWidthMixin) {
25
+ $hasOptions = ['counter']
26
+
25
27
  showPassword = false
26
28
 
27
29
  created () {
@@ -83,6 +85,10 @@ export default class ATextField extends Mixins(ComponentWidthMixin) {
83
85
  }
84
86
 
85
87
  get counter () {
88
+ if (!this.$has.counter) {
89
+ return false
90
+ }
91
+
86
92
  if (!this.validator) {
87
93
  return false
88
94
  }
@@ -2,7 +2,7 @@ import { Component, Vue } from '@a-vue'
2
2
  import { ListAction } from '@a-vue/api-resources/ApiActions'
3
3
 
4
4
  @Component({
5
- props: ['name', 'label']
5
+ props: ['name', 'label', 'additionalRules']
6
6
  })
7
7
  export class FormFieldMixin extends Vue {
8
8
  get model () {
@@ -69,7 +69,18 @@ export class FormFieldMixin extends Vue {
69
69
  }
70
70
 
71
71
  if (field.hasOptions()) {
72
- const options = field.getOptions()
72
+ let options = field.getOptions()
73
+
74
+ if (!Array.isArray(options)) {
75
+ options = Object.entries(options).map(([key, title]) => {
76
+ return {
77
+ itemText: title,
78
+ itemValue: key
79
+ }
80
+ })
81
+ return options
82
+ }
83
+
73
84
  return options.map((value, index) => {
74
85
  if (typeof value === 'object') { // object option
75
86
  return {
@@ -87,6 +98,12 @@ export class FormFieldMixin extends Vue {
87
98
  }
88
99
 
89
100
  get validator () {
101
+ const validator = this.field.getValidator()
102
+ if (this.additionalRules) {
103
+ this.additionalRules.forEach(validate => {
104
+ validator.addRule(validate)
105
+ })
106
+ }
90
107
  return this.field.getValidator()
91
108
  }
92
109
 
@@ -55,6 +55,7 @@ export default class FormFieldText extends Mixins(FormFieldMixin) {
55
55
  }
56
56
 
57
57
  this.model[this.name] = value
58
+ this.$emit('input', value)
58
59
  }
59
60
 
60
61
  setInternalValue (value, reset = false) {
@@ -11,6 +11,10 @@ export function debounce (callback, delay = 300, condition = () => true) {
11
11
  clearTimeout(timeout)
12
12
  }
13
13
 
14
+ /**
15
+ * fire immediately if condition falsy
16
+ * e.g. textfield content gets canceled using (x)
17
+ */
14
18
  if (!condition(...args)) {
15
19
  callback(...args)
16
20
  return
@@ -97,7 +97,7 @@
97
97
 
98
98
  <v-container
99
99
  fluid
100
- class="pa-8 pt-2"
100
+ class="pa-8 pt-0"
101
101
  >
102
102
  <sticky-header />
103
103
 
@@ -230,6 +230,7 @@ export default class App extends Vue {
230
230
  left: 0;
231
231
  top: 0;
232
232
  padding: .2rem 1.1rem;
233
+ background-color: white;
233
234
  }
234
235
 
235
236
  .a-breadcrumbs {
@@ -7,14 +7,15 @@
7
7
  </template>
8
8
 
9
9
  <script>
10
- import { Component, Watch, Vue } from '@a-vue'
10
+ import { Component, Watch, Mixins } from '@a-vue'
11
11
  import { FlyingContextEvent } from '@a-vue/events'
12
12
  import { randomCssClass } from '@a-vue/utils/random'
13
+ import { CancelOnEscMixin } from '@a-vue/services/escape/CancelOnEscMixin'
13
14
 
14
15
  @Component({
15
16
  props: [{show: false}]
16
17
  })
17
- export default class FlyingContext extends Vue {
18
+ export default class FlyingContext extends Mixins(CancelOnEscMixin) {
18
19
  isVisible = false
19
20
  contextId = randomCssClass(10)
20
21
 
@@ -44,8 +45,10 @@ export default class FlyingContext extends Vue {
44
45
  if (this.isVisible) {
45
46
  const container = this.getSidebarContainer()
46
47
  container.appendChild(el)
48
+ this.coe_watchCancel() // show context -> watch esc
47
49
  } else {
48
50
  this.$el.appendChild(el)
51
+ this.coe_unwatchCancel() // hide context -> do not watch esc any more
49
52
  }
50
53
  }
51
54
 
@@ -62,11 +65,17 @@ export default class FlyingContext extends Vue {
62
65
  onHide () {
63
66
  if (this.isVisible) {
64
67
  this.$el.appendChild(this.getContent())
68
+ this.coe_unwatchCancel() // hide context -> do not watch esc any more
65
69
  this.isVisible = false
66
70
  this.$emit('hide')
67
71
  }
68
72
  }
69
73
 
74
+ coe_cancelOnEsc () {
75
+ this.onHide()
76
+ return false // stop esc propagation
77
+ }
78
+
70
79
  getContent () {
71
80
  return document.querySelector('.' + this.contextId)
72
81
  }
@@ -57,8 +57,9 @@ export default class StickyHeader extends Vue {
57
57
  #stickyHeader {
58
58
  position: sticky;
59
59
  top: -1px;
60
- margin: -1rem -2rem 2rem;
60
+ margin: 0 -2rem 2rem;
61
61
  padding: 1rem 2rem;
62
+ background-color: white;
62
63
 
63
64
  &:not(.visible) {
64
65
  display: none !important;
@@ -3,18 +3,32 @@
3
3
  gap="1"
4
4
  v-bind="$attrs"
5
5
  >
6
- <v-btn
7
- fab
8
- small
9
- :disabled="($has.reset && !changed) || !valid"
10
- color="green white--text"
11
- title="Speichern"
12
- @click="$emit('save')"
13
- >
14
- <v-icon>
15
- $checkIcon
16
- </v-icon>
17
- </v-btn>
6
+ <v-tooltip bottom>
7
+ <template #activator="{ on }">
8
+ <div v-on="disabled ? on : null">
9
+ <v-btn
10
+ fab
11
+ small
12
+ :disabled="disabled"
13
+ color="green white--text"
14
+ title="Speichern"
15
+ @click="$emit('save')"
16
+ >
17
+ <v-icon>
18
+ $checkIcon
19
+ </v-icon>
20
+ </v-btn>
21
+ </div>
22
+ </template>
23
+ <span v-if="disabled">
24
+ <template v-if="!valid">
25
+ Daten berichtigen,<br>um zu speichern
26
+ </template>
27
+ <template v-else>
28
+ Daten ändern,<br>um zu speichern
29
+ </template>
30
+ </span>
31
+ </v-tooltip>
18
32
 
19
33
  <v-hover
20
34
  v-if="$has.reset && changed"
@@ -49,12 +63,9 @@ export default class EditFormButtons extends Vue {
49
63
  $hasOptions = ['reset']
50
64
 
51
65
  undoIcon = mdiRotateLeft
52
- }
53
- </script>
54
-
55
66
 
56
- <style lang="scss" scoped>
57
- .v-icon--disabled {
58
- opacity: .3;
67
+ get disabled () {
68
+ return (this.$has.reset && !this.changed) || !this.valid
69
+ }
59
70
  }
60
- </style>
71
+ </script>
@@ -2,14 +2,14 @@
2
2
  <div>
3
3
  <v-hover v-slot="{ hover }">
4
4
  <v-btn
5
- :class="'removeButton-' + dialogId"
5
+ :class="'a-btn-standard removeButton-' + dialogId"
6
6
  fab
7
7
  x-small
8
8
  :color="(hover ? 'red' : 'grey lighten-3')"
9
- title="Löschen"
9
+ :title="title"
10
10
  @click="remove"
11
11
  >
12
- <v-icon :color="hover ? 'white' : '#999999'">
12
+ <v-icon class="white--hover">
13
13
  $trashCanIcon
14
14
  </v-icon>
15
15
  </v-btn>
@@ -17,7 +17,7 @@
17
17
 
18
18
  <a-dialog
19
19
  :id="dialogId"
20
- :anchor="[document, '.removeButton-' + dialogId]"
20
+ :anchor="'.removeButton-' + dialogId"
21
21
  :active="protect ? removeKey === removeConfirmed : true"
22
22
  >
23
23
  <template v-if="protect">
@@ -41,11 +41,10 @@ import { DialogEvent } from '@a-vue/events'
41
41
  import { randomCssClass } from '@a-vue/utils/random'
42
42
 
43
43
  @Component({
44
- props: ['itemTitle', 'protect']
44
+ props: ['title', 'itemTitle', 'protect']
45
45
  })
46
46
  export default class EditPage extends Vue {
47
47
  dialogId = randomCssClass(10)
48
- document = document
49
48
  removeKey = null
50
49
  removeConfirmed = null
51
50
 
@@ -28,11 +28,39 @@
28
28
  }
29
29
  }
30
30
 
31
+ .theme--light.v-btn.a-btn-standard {
32
+ background-color: #E9E9E9;
33
+
34
+ &:not(:hover) {
35
+ background-color: #EEEEEE !important;
36
+ border-color: #EEEEEE !important;
37
+ }
38
+
39
+ span,
40
+ .v-icon {
41
+ color: grey !important;
42
+ }
43
+
44
+ &:hover {
45
+ span,
46
+ .v-icon {
47
+ &.white--hover {
48
+ color: white !important;
49
+ }
50
+ }
51
+ }
52
+ }
53
+
31
54
  .theme--light.v-btn.v-btn--has-bg {
32
55
  background-color: #E9E9E9;
33
56
  }
34
57
 
58
+ .theme--light.v-btn:focus::before {
59
+ opacity: .08;
60
+ }
61
+
35
62
  .theme--light.v-btn.v-btn--disabled,
63
+ .theme--light.v-btn.v-btn--disabled span,
36
64
  .theme--light.v-btn.v-btn--disabled .v-icon,
37
65
  .theme--light.v-btn.v-btn--disabled .v-btn__loading {
38
66
  color: white !important;