@afeefa/vue-app 0.0.317 → 0.0.319

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.
@@ -1 +1 @@
1
- 0.0.317
1
+ 0.0.319
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afeefa/vue-app",
3
- "version": "0.0.317",
3
+ "version": "0.0.319",
4
4
  "description": "",
5
5
  "author": "Afeefa Kollektiv <kollektiv@afeefa.de>",
6
6
  "license": "MIT",
@@ -54,5 +54,9 @@ export default class ARow extends Mixins(ComponentWidthMixin) {
54
54
  flex-direction: column;
55
55
  align-items: start;
56
56
  }
57
+
58
+ &.even > * {
59
+ flex: 1;
60
+ }
57
61
  }
58
62
  </style>
@@ -1,5 +1,8 @@
1
1
  <template>
2
- <div :class="['a-search-select', widthClass]">
2
+ <div
3
+ :class="['a-search-select', widthClass]"
4
+ :style="cwm_widthStyle"
5
+ >
3
6
  <div
4
7
  class="activator"
5
8
  @click="open"
@@ -26,7 +29,7 @@
26
29
  <div
27
30
  v-if="isOpen"
28
31
  class="controls"
29
- :style="cwm_widthStyle"
32
+ :style="cwm_popupWidthStyle"
30
33
  >
31
34
  <div class="background elevation-6" />
32
35
 
@@ -71,7 +74,7 @@
71
74
  :filters.sync="filters"
72
75
  :count.sync="count"
73
76
  :isLoading.sync="isLoading"
74
- :style="cwm_widthStyle"
77
+ :style="cwm_popupWidthStyle"
75
78
  @onLoad="onLoad"
76
79
  @enter="selectItem"
77
80
  @backtab="setFocusToSearchInput"
@@ -358,8 +361,8 @@ export default class ASearchSelect extends Mixins(ComponentWidthMixin, UsesPosit
358
361
  }
359
362
  }
360
363
 
361
- setWidth (width) {
362
- this.cwm_width_ = width
364
+ setPopupWidth (width) {
365
+ this.cwm_popupWidth_ = width
363
366
  }
364
367
 
365
368
  searchFilterKeyDown (event) {
@@ -121,10 +121,13 @@ export default class ASelect extends Mixins(ComponentWidthMixin) {
121
121
  margin: 0;
122
122
  margin-right: .5rem;
123
123
  }
124
-
125
124
  </style>
126
125
 
127
126
  <style lang="scss" scoped>
127
+ .v-select {
128
+ flex: unset;
129
+ }
130
+
128
131
  .v-text-field :deep(.v-input__icon--clear) { // always show clear icon, https://github.com/vuetifyjs/vuetify/pull/15876
129
132
  opacity: 1;
130
133
  }
@@ -248,4 +248,9 @@ export default class ATextField extends Mixins(ComponentWidthMixin) {
248
248
  .v-text-field :deep(.v-input__icon--clear) { // always show clear icon, https://github.com/vuetifyjs/vuetify/pull/15876
249
249
  opacity: 1;
250
250
  }
251
+
252
+ .v-text-field {
253
+ flex: unset;
254
+ max-width: unset;
255
+ }
251
256
  </style>
@@ -4,8 +4,8 @@
4
4
  :listAction="listAction"
5
5
  :selectedItems="selectedItems"
6
6
  :getSearchInput="() => $refs.searchInput"
7
- diffXControls="-.5rem"
8
- diffYControls="-.5rem"
7
+ diffXControls="1rem"
8
+ diffYControls="1rem"
9
9
  v-bind="$attrs"
10
10
  @select="itemSelected"
11
11
  @close="focusInput"
@@ -38,7 +38,6 @@
38
38
  ref="searchInput"
39
39
  :focus="true"
40
40
  tabindex="1"
41
- maxWidth="100%"
42
41
  :label="'Suche ' + label"
43
42
  v-on="onSearchInputKey"
44
43
  />
@@ -116,7 +115,7 @@ export default class FormFieldSearchSelect extends Mixins(FormFieldMixin) {
116
115
  const input = this.$refs.input?.$el
117
116
  if (input) {
118
117
  const inputWidth = input.offsetWidth
119
- this.$refs.select.setWidth(`calc(${inputWidth}px + 1rem)`)
118
+ this.$refs.select.setPopupWidth(`calc(${inputWidth}px - 2rem)`)
120
119
  }
121
120
  }
122
121
 
@@ -23,8 +23,8 @@
23
23
 
24
24
  <list-filter-search2
25
25
  label="Suche"
26
- maxWidth="220"
27
26
  focus
27
+ width="200"
28
28
  :translateOption="title => {
29
29
  return title
30
30
  .replace('Sprint', $t('SPRINT'))
@@ -7,7 +7,6 @@ import { ListFilterEvent } from '@a-vue/events'
7
7
  export class ListFilterMixin extends Vue {
8
8
  displayValue = null
9
9
  name_ = null
10
- maxWidth_ = null
11
10
 
12
11
  @Watch('displayValue')
13
12
  displayValueChanged () {
@@ -3,7 +3,6 @@
3
3
  <a-text-field
4
4
  ref="input"
5
5
  v-model="filter.value"
6
- :maxWidth="$attrs.maxWidth || maxWidth_"
7
6
  :label="label_"
8
7
  :debounce="500"
9
8
  v-bind="$attrs"
@@ -52,7 +51,6 @@ import { ListFilterMixin } from '../ListFilterMixin'
52
51
  @Component
53
52
  export default class ListFilterSearch extends Mixins(ListFilterMixin) {
54
53
  name_ = 'q'
55
- maxWidth_ = 200
56
54
 
57
55
  clearValue (e) {
58
56
  if (this.filter.value) {
@@ -3,7 +3,6 @@
3
3
  <a-text-field
4
4
  ref="input"
5
5
  v-model="filter.value"
6
- :maxWidth="$attrs.maxWidth || maxWidth_"
7
6
  :label="label_"
8
7
  :debounce="500"
9
8
  v-bind="$attrs"
@@ -36,7 +35,6 @@ import { ListFilterMixin } from '../ListFilterMixin'
36
35
  })
37
36
  export default class ListFilterSearch2 extends Mixins(ListFilterMixin) {
38
37
  name_ = 'q'
39
- maxWidth_ = 200
40
38
 
41
39
  clearValue (e) {
42
40
  if (this.filter.value) {
@@ -5,8 +5,8 @@
5
5
  :specialItems="specialItems"
6
6
  :selectedItems="selectedItems"
7
7
  :getSearchInput="() => $refs.searchInput"
8
- diffXControls="-.5rem"
9
- diffYControls="-.5rem"
8
+ diffXControls="1rem"
9
+ diffYControls="1rem"
10
10
  v-bind="$attrs"
11
11
  @select="itemSelected"
12
12
  @close="focusInput"
@@ -23,7 +23,6 @@
23
23
  :clearable="!!selectedItems.length"
24
24
  appendIcon="$dropdown"
25
25
  hide-details
26
- :maxWidth="$attrs.maxWidth"
27
26
  @keydown.space.prevent="open"
28
27
  @keydown.down.prevent="open"
29
28
  @keydown.enter.prevent="open"
@@ -37,7 +36,6 @@
37
36
  ref="searchInput"
38
37
  :focus="true"
39
38
  tabindex="1"
40
- maxWidth="100%"
41
39
  :label="'Suche ' + label"
42
40
  v-on="onSearchInputKey"
43
41
  />
@@ -149,7 +147,7 @@ export default class ListFilterSearchSelect extends Mixins(ListFilterMixin) {
149
147
  calculateSelectorSize () {
150
148
  const input = this.$refs.input.$el
151
149
  const inputWidth = input.offsetWidth
152
- this.$refs.select.setWidth(`calc(${inputWidth}px + 1rem)`)
150
+ this.$refs.select.setPopupWidth(`calc(${inputWidth}px - 2rem)`)
153
151
  }
154
152
 
155
153
  get selectedItems () {
@@ -1,53 +1,48 @@
1
1
  import { Component, Vue } from '@a-vue'
2
2
 
3
3
  @Component({
4
- props: ['maxWidth', 'width']
4
+ props: ['maxWidth', 'width', 'popupWidth']
5
5
  })
6
6
  export class ComponentWidthMixin extends Vue {
7
7
  cwm_maxWidth_ = null
8
8
  cwm_width_ = null
9
+ cwm_popupWidth_ = null
9
10
 
10
11
  get cwm_width () {
11
- let width = this.width || this.cwm_width_
12
-
13
- if (width) {
14
- if (!isNaN(width)) {
15
- width = width + 'px'
16
- }
17
- return width
18
- }
12
+ return this.cwm_toPixel_(this.width || this.cwm_width_)
19
13
  }
20
14
 
21
15
  get cwm_maxWidth () {
22
- let maxWidth = this.maxWidth || this.cwm_maxWidth_
16
+ return this.cwm_toPixel_(this.maxWidth || this.cwm_maxWidth_)
17
+ }
23
18
 
24
- if (maxWidth) {
25
- if (!isNaN(maxWidth)) {
26
- maxWidth = maxWidth + 'px'
27
- }
28
- return maxWidth
19
+ get cwm_widthStyle () {
20
+ return this.cwm_getWidthStyle_(
21
+ this.width || this.cwm_width_,
22
+ this.maxWidth || this.cwm_maxWidth_
23
+ )
24
+ }
25
+
26
+ get cwm_popupWidthStyle () {
27
+ return this.cwm_getWidthStyle_(this.popupWidth || this.cwm_popupWidth_ || this.width || this.cwm_width_)
28
+ }
29
+
30
+ cwm_toPixel_ (value) {
31
+ if (value && !isNaN(value)) {
32
+ return value + 'px'
29
33
  }
34
+ return value
30
35
  }
31
36
 
32
- get cwm_widthStyle () {
37
+ cwm_getWidthStyle_ (width, maxWidth) {
33
38
  const styles = []
34
39
 
35
- let width = this.width || this.cwm_width_
36
-
37
40
  if (width) {
38
- if (!isNaN(width)) {
39
- width = width + 'px'
40
- }
41
- styles.push(`width: ${width};`)
41
+ styles.push(`width: ${this.cwm_toPixel_(width)};`)
42
42
  }
43
43
 
44
- let maxWidth = this.maxWidth || this.cwm_maxWidth_
45
-
46
44
  if (maxWidth) {
47
- if (!isNaN(maxWidth)) {
48
- maxWidth = maxWidth + 'px'
49
- }
50
- styles.push(`max-width: ${maxWidth};`)
45
+ styles.push(`max-width: ${this.cwm_toPixel_(maxWidth)}; background: yellow`)
51
46
  }
52
47
 
53
48
  return styles.join(' ')
@@ -57,22 +57,33 @@ export default class AppBarNavigation extends Vue {
57
57
 
58
58
  initLinks () {
59
59
  const sections = document.querySelectorAll('.collapsible-section')
60
- this.links = Array.from(sections).map(s => {
61
- const label = s.getAttribute('label')
62
- const slug = label
63
- .toLowerCase()
64
- .replace(/[^\w]+/g, '-') // Sonderzeichen -> Bindestriche
65
- .replace(/^-+|-+$/g, '') // führende/trailing -
66
- .substring(0, 50) // Sicherheitslimit
67
-
68
- s.id = slug
69
-
70
- return {
71
- id: s.id,
72
- label,
73
- slug
74
- }
75
- })
60
+ const seenLabels = new Set()
61
+
62
+ this.links = Array.from(sections)
63
+ .filter(s => { // wenn aus versehen mehrere sections mit gleichem label bestehen, z.b. in popups
64
+ const label = s.getAttribute('label')
65
+ if (seenLabels.has(label)) {
66
+ return false
67
+ }
68
+ seenLabels.add(label)
69
+ return true
70
+ })
71
+ .map(s => {
72
+ const label = s.getAttribute('label')
73
+ const slug = label
74
+ .toLowerCase()
75
+ .replace(/[^\w]+/g, '-') // Sonderzeichen -> Bindestriche
76
+ .replace(/^-+|-+$/g, '') // führende/trailing -
77
+ .substring(0, 50) // Sicherheitslimit
78
+
79
+ s.id = slug
80
+
81
+ return {
82
+ id: s.id,
83
+ label,
84
+ slug
85
+ }
86
+ })
76
87
  }
77
88
 
78
89
  scrollToSection (id) {
@@ -3,8 +3,8 @@
3
3
  ref="select"
4
4
  :listAction="listAction"
5
5
  :getSearchInput="() => $refs.searchInput"
6
- diffXControls="-.5rem"
7
- diffYControls="-.5rem"
6
+ diffXControls="1rem"
7
+ diffYControls="1rem"
8
8
  v-bind="$attrs"
9
9
  @select="itemSelected"
10
10
  @close="focusInput"
@@ -31,7 +31,6 @@
31
31
  ref="searchInput"
32
32
  :focus="true"
33
33
  tabindex="1"
34
- maxWidth="100%"
35
34
  :label="'Suche ' + label"
36
35
  v-on="onSearchInputKey"
37
36
  />
@@ -93,7 +92,7 @@ export default class SearchSelectNavigator extends Vue {
93
92
  calculateSelectorSize () {
94
93
  const input = this.$refs.input.$el
95
94
  const inputWidth = input.offsetWidth
96
- this.$refs.select.setWidth(`calc(${inputWidth}px + 1rem)`)
95
+ this.$refs.select.setPopupWidth(`calc(${inputWidth}px - 2rem)`)
97
96
  }
98
97
 
99
98
  get listAction () {
@@ -1,223 +0,0 @@
1
- <template>
2
- <div>
3
- <a-table
4
- v-if="selectedItems.length"
5
- :style="selectedWidthStyle"
6
- >
7
- <a-table-header
8
- v-if="hasHeader"
9
- small
10
- >
11
- <div
12
- v-for="(column, index) in selectedColumns"
13
- :key="index"
14
- >
15
- {{ column.header }}
16
- </div>
17
- </a-table-header>
18
-
19
- <a-table-row
20
- v-for="(item, index) in selectedItems"
21
- :key="item.id"
22
- :selected="isClicked(item)"
23
- >
24
- <template v-for="(column, index2) in selectedColumns">
25
- <v-icon
26
- v-if="column.icon"
27
- :key="'icon' + index2"
28
- :color="column.icon.color"
29
- class="selectedIcon"
30
- size="1.5rem"
31
- v-text="column.icon.icon"
32
- />
33
-
34
- <div
35
- v-else
36
- :key="'text' + index2"
37
- class="selectedContent"
38
- >
39
- {{ column.text(item) }}
40
- </div>
41
- </template>
42
-
43
- <div>
44
- <a-context-menu
45
- :ref="'editItem' + index"
46
- @open="clickedItem = item"
47
- @close="clickedItem = null"
48
- >
49
- <a-context-menu-item @click="removeItem(item, index)">
50
- <v-icon>$trashCanIcon</v-icon>
51
- Löschen
52
- </a-context-menu-item>
53
- </a-context-menu>
54
- </div>
55
- </a-table-row>
56
- </a-table>
57
-
58
- <div v-else>
59
- {{ isEmptyText }}
60
- </div>
61
-
62
- <a-search-select
63
- :listAction="selectableConfig.listAction"
64
- :selectedItems="selectableSelectedItems"
65
- :width="selectableWidth"
66
- @select="addItem"
67
- >
68
- <template #activator>
69
- <a-icon-button
70
- small
71
- icon="$plusIcon"
72
- :text="selectableConfig.addButtonTitle || 'Hinzufügen'"
73
- class="mt-4"
74
- />
75
- </template>
76
-
77
- <template #filters>
78
- <a-row gap="4">
79
- <list-filter-search
80
- :focus="true"
81
- maxWidth="100%"
82
- label="Suche Berater:in"
83
- />
84
-
85
- <list-filter-page
86
- :has="{page_size: false, page_number: true}"
87
- :totalVisible="0"
88
- />
89
- </a-row>
90
- </template>
91
-
92
- <template #row="{ model, on }">
93
- <template
94
- v-for="(column, index) in selectableColumns"
95
- v-on="on"
96
- >
97
- <v-icon
98
- v-if="column.icon"
99
- :key="'icon' + index"
100
- :color="column.icon.color"
101
- class="selectableIcon"
102
- size="1.5rem"
103
- v-on="on"
104
- v-text="column.icon.icon"
105
- />
106
-
107
- <div
108
- v-else
109
- :key="'text' + index"
110
- class="selectableContent"
111
- v-on="on"
112
- >
113
- {{ column.text(model) }}
114
- </div>
115
- </template>
116
- </template>
117
- </a-search-select>
118
- </div>
119
- </template>
120
-
121
-
122
- <script>
123
- import { Component, Vue } from '@a-vue'
124
-
125
- @Component({
126
- props: [
127
- 'value',
128
- 'selectedConfig',
129
- 'selectedWidth',
130
- 'selectableConfig',
131
- 'selectableWidth'
132
- ]
133
- })
134
- export default class SearchSelectFormField extends Vue {
135
- clickedItem = null
136
-
137
- get hasHeader () {
138
- return this.selectedColumns.some(c => !!c.header)
139
- }
140
-
141
- get selectedItems () {
142
- return this.value
143
- }
144
-
145
- get selectableSelectedItems () {
146
- return this.value.map(this.selectedConfig.selectedToSelectableItem)
147
- }
148
-
149
- get isEmptyText () {
150
- return this.selectedConfig.isEmptyText
151
- }
152
-
153
- isClicked (selectedItem) {
154
- return selectedItem === this.clickedItem
155
- }
156
-
157
- get selectedColumns () {
158
- return this.selectedConfig.columns
159
- }
160
-
161
- get selectableColumns () {
162
- return this.selectableConfig.columns
163
- }
164
-
165
- addItem (selectableItem) {
166
- const selectedItem = this.selectedConfig.newSelectedItem(selectableItem)
167
- const selectedItems = [...this.value, selectedItem]
168
- if (this.$listeners.add) {
169
- this.$emit('add', selectedItems)
170
- } else {
171
- this.$emit('input', selectedItems)
172
- }
173
- }
174
-
175
- async removeItem (selectedItem, rowIndex) {
176
- const removeDialog = this.selectedConfig.removeDialog(selectedItem)
177
- const dialog = {
178
- anchor: this.$refs['editItem' + rowIndex], // is array [component]
179
- ...removeDialog,
180
- yesButton: 'Löschen',
181
- yesColor: 'red white--text'
182
- }
183
-
184
- const selectedItems = this.value.filter(i => i !== selectedItem)
185
- if (this.$listeners.remove) {
186
- this.$emit('remove', selectedItems, dialog)
187
- } else {
188
- this.$emit('input', selectedItems)
189
- }
190
- }
191
-
192
- get selectedWidthStyle () {
193
- if (!this.selectedWidth) {
194
- return ''
195
- }
196
-
197
- let width = this.selectedWidth
198
- if (!isNaN(width)) {
199
- width = width + 'px'
200
- }
201
- return `width: ${width};`
202
- }
203
- }
204
- </script>
205
-
206
-
207
- <style scoped lang="scss">
208
- .selectedIcon:deep() {
209
- padding-right: .3rem !important;
210
- }
211
-
212
- .selectableIcon:deep() {
213
- padding-right: 2rem !important;
214
- }
215
-
216
- .selectedContent:deep() {
217
- width: 100%;
218
- }
219
-
220
- .selectableContent:deep() {
221
- width: 100%;
222
- }
223
- </style>