comand-component-library 4.0.0 → 4.0.2
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/comand-component-library.js +1632 -1565
- package/dist/comand-component-library.umd.cjs +4 -4
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/{App.vue → ComponentLibrary.vue} +875 -413
- package/src/assets/data/main-navigation.json +2 -0
- package/src/assets/styles/global-styles.scss +1 -10
- package/src/components/CmdAddressData.vue +1 -1
- package/src/components/CmdBox.vue +40 -4
- package/src/components/CmdBoxWrapper.vue +15 -5
- package/src/components/CmdFormElement.vue +37 -33
- package/src/components/CmdHeadline.vue +97 -33
- package/src/components/CmdInputGroup.vue +6 -5
- package/src/components/CmdListOfLinks.vue +24 -24
- package/src/components/CmdLoginForm.vue +1 -0
- package/src/components/CmdMainNavigation.vue +20 -9
- package/src/components/CmdMultistepFormProgressBar.vue +43 -1
- package/src/components/CmdNewsletterSubscription.vue +7 -7
- package/src/components/CmdOpeningHours.vue +33 -18
- package/src/components/CmdOpeningHoursItem.vue +21 -13
- package/src/components/CmdPagination.vue +2 -2
- package/src/components/CmdSidebar.vue +6 -1
- package/src/components/CmdSiteHeader.vue +3 -0
- package/src/components/CmdSiteSearch.vue +12 -11
- package/src/components/CmdSystemMessage.vue +1 -0
- package/src/components/CmdTable.vue +9 -1
- package/src/components/CmdTextImageBlock.vue +2 -0
- package/src/components/CmdThumbnailScroller.vue +52 -32
- package/src/components/CmdTooltip.vue +5 -0
- package/src/components/CmdUploadForm.vue +67 -41
- package/src/components/ComponentSettings.vue +171 -0
- package/src/main.js +3 -3
@@ -24,22 +24,24 @@
|
|
24
24
|
</CmdSystemMessage>
|
25
25
|
<!-- end CmdSystemMessage -->
|
26
26
|
|
27
|
-
<div :class="['box
|
27
|
+
<div :class="['box flex-container vertical', { 'drop-area': enableDragAndDrop, 'allow-drop': allowDrop }]" v-on="dragAndDropHandler">
|
28
28
|
<template v-if="!listOfFiles.length">
|
29
|
+
<!-- begin CmdHeadline -->
|
29
30
|
<CmdHeadline v-if="allowMultipleFileUploads" v-bind="cmdHeadlineNoFilesToUpload" headlineLevel="4">
|
30
|
-
{{
|
31
|
-
</CmdHeadline>
|
32
|
-
<CmdHeadline v-else v-bind="cmdHeadlineNoFilesToUpload" headlineLevel="4">
|
33
|
-
{{ getMessage("cmduploadform.no_file_to_upload") }}
|
31
|
+
{{ headlineTextNoFilesToUpload }}
|
34
32
|
</CmdHeadline>
|
33
|
+
<!-- end CmdHeadline -->
|
35
34
|
</template>
|
36
35
|
|
37
36
|
<!-- begin total-upload information -->
|
38
37
|
<div v-else class="flex-container vertical">
|
39
38
|
<div v-if="showTotalUpload && listOfFiles.length !== 1" class="flex-container vertical list-files-wrapper">
|
39
|
+
<!-- begin CmdHeadline -->
|
40
40
|
<CmdHeadline v-bind="cmdHeadlineSummaryOfAllFiles" headlineLevel="4">
|
41
41
|
{{ getMessage("cmduploadform.headline.summary_of_all_files") }}
|
42
42
|
</CmdHeadline>
|
43
|
+
<!-- end CmdHeadline -->
|
44
|
+
|
43
45
|
<ul v-if="showTotalUpload && listOfFiles.length !== 1" class="list-of-files total-files">
|
44
46
|
<li class="flex-container no-flex">
|
45
47
|
<a
|
@@ -83,9 +85,12 @@
|
|
83
85
|
|
84
86
|
<div class="flex-container vertical list-files-wrapper">
|
85
87
|
<!-- begin list of selected files -->
|
88
|
+
<!-- begin CmdHeadline -->
|
86
89
|
<CmdHeadline v-bind="cmdHeadlineListOfSelectedFiles" headlineLevel="4">
|
87
90
|
{{ getMessage("cmduploadform.headline.list_of_selected_files") }}
|
88
91
|
</CmdHeadline>
|
92
|
+
<!-- end CmdHeadline -->
|
93
|
+
|
89
94
|
<ul class="list-of-files">
|
90
95
|
<li
|
91
96
|
v-for="(uploadFile, index) in listOfFiles"
|
@@ -108,20 +113,21 @@
|
|
108
113
|
{ error: uploadFile.error }
|
109
114
|
]">
|
110
115
|
{{ uploadFile.file.name }} <small>({{ formatSize(uploadFile.file.size) }})</small>
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
<span
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
</
|
116
|
+
</span>
|
117
|
+
|
118
|
+
<!-- begin progressbar -->
|
119
|
+
<span class="progressbar" v-if="uploadInitiated && !uploadFile.error">
|
120
|
+
<span>{{ getPercentage(uploadFile.progress) }}</span>
|
121
|
+
<!-- do not place inside progress-tag (will not be displayed then) -->
|
122
|
+
<progress
|
123
|
+
max="100"
|
124
|
+
:value="uploadFile.progress"
|
125
|
+
:title="
|
126
|
+
formatSize(uploadFile.uploadedBytes) + '/' + formatSize(uploadFile.file.size)
|
127
|
+
"
|
128
|
+
></progress>
|
129
|
+
</span>
|
130
|
+
<!-- end progressbar -->
|
125
131
|
</li>
|
126
132
|
</ul>
|
127
133
|
<a
|
@@ -137,12 +143,18 @@
|
|
137
143
|
<!-- end list of selected files -->
|
138
144
|
|
139
145
|
<!-- begin upload conditions -->
|
146
|
+
<!-- begin CmdHeadline -->
|
140
147
|
<CmdHeadline v-if="allowMultipleFileUploads && listOfFiles.length" v-bind="cmdHeadlineSelectAdditionalFiles" headlineLevel="4">
|
141
148
|
{{ getMessage("cmduploadform.headline.select_additional_files") }}
|
142
149
|
</CmdHeadline>
|
150
|
+
<!-- end CmdHeadline -->
|
151
|
+
|
152
|
+
<!-- begin CmdHeadline -->
|
143
153
|
<CmdHeadline v-if="!allowMultipleFileUploads && listOfFiles.length" v-bind="cmdHeadlineSelectNewFile" headlineLevel="4">
|
144
154
|
{{ getMessage("cmduploadform.headline.select_new_file") }}
|
145
155
|
</CmdHeadline>
|
156
|
+
<!-- end CmdHeadline -->
|
157
|
+
|
146
158
|
<dl class="small">
|
147
159
|
<template v-if="maxTotalUploadSize > 0">
|
148
160
|
<dt :class="{ error: totalSize > maxTotalUploadSize }">
|
@@ -188,7 +200,8 @@
|
|
188
200
|
</dl>
|
189
201
|
<!-- end upload conditions -->
|
190
202
|
|
191
|
-
|
203
|
+
<!-- begin upload-button and drag-and-drop-text -->
|
204
|
+
<div class="flex-container vertical no-gap">
|
192
205
|
<button
|
193
206
|
type="button"
|
194
207
|
:class="['button upload primary', { disabled: uploadInitiated }]"
|
@@ -217,7 +230,9 @@
|
|
217
230
|
</strong>
|
218
231
|
</p>
|
219
232
|
</div>
|
233
|
+
<!-- end upload-button and drag-and-drop-text -->
|
220
234
|
</div>
|
235
|
+
|
221
236
|
<!-- begin CmdFormElement -->
|
222
237
|
<CmdFormElement
|
223
238
|
v-if="enableComment"
|
@@ -268,7 +283,8 @@
|
|
268
283
|
<!-- end advanced mode -->
|
269
284
|
|
270
285
|
<!-- begin simple mode -->
|
271
|
-
<a v-else href="#" @click.prevent="selectFiles" :class="['cmd-upload-form
|
286
|
+
<a v-else href="#" @click.prevent="selectFiles" :class="['cmd-upload-form box', { 'drop-area': enableDragAndDrop, 'allow-drop': allowDrop }]" v-on="dragAndDropHandler">
|
287
|
+
<!-- begin progressbar -->
|
272
288
|
<span class="progressbar" v-if="uploadInitiated">
|
273
289
|
<span>{{ getPercentage(totalUploadProgress) }}</span>
|
274
290
|
<progress
|
@@ -277,10 +293,11 @@
|
|
277
293
|
:title="totalBytesUploaded">
|
278
294
|
</progress>
|
279
295
|
</span>
|
296
|
+
<!-- end progressbar -->
|
280
297
|
|
281
298
|
<!-- begin slot-content -->
|
282
299
|
<slot>
|
283
|
-
<template v-if="enableDragAndDrop">
|
300
|
+
<template v-if="!enableDragAndDrop">
|
284
301
|
<template v-if="fileTypeImage">
|
285
302
|
<span>{{ getMessage("cmduploadform.select_image") }}</span>
|
286
303
|
<!-- begin CmdIcon -->
|
@@ -455,6 +472,22 @@ export default {
|
|
455
472
|
type: Boolean,
|
456
473
|
default: true
|
457
474
|
},
|
475
|
+
/**
|
476
|
+
* toggle visibility for legend-text
|
477
|
+
*/
|
478
|
+
showLegend: {
|
479
|
+
type: Boolean,
|
480
|
+
default: true
|
481
|
+
},
|
482
|
+
/**
|
483
|
+
* text for legend
|
484
|
+
*
|
485
|
+
* @requiredForAccessibility: true
|
486
|
+
*/
|
487
|
+
textLegend: {
|
488
|
+
type: String,
|
489
|
+
required: false
|
490
|
+
},
|
458
491
|
/**
|
459
492
|
* set icon for delete-icons
|
460
493
|
*/
|
@@ -611,25 +644,12 @@ export default {
|
|
611
644
|
cmdHeadlineSelectNewFile: {
|
612
645
|
type: Object,
|
613
646
|
required: false
|
614
|
-
},
|
615
|
-
/**
|
616
|
-
* toggle visibility for legend-text
|
617
|
-
*/
|
618
|
-
showLegend: {
|
619
|
-
type: Boolean,
|
620
|
-
default: true
|
621
|
-
},
|
622
|
-
/**
|
623
|
-
* text for legend
|
624
|
-
*
|
625
|
-
* @requiredForAccessibility: true
|
626
|
-
*/
|
627
|
-
textLegend: {
|
628
|
-
type: String,
|
629
|
-
required: false
|
630
647
|
}
|
631
648
|
},
|
632
649
|
computed: {
|
650
|
+
headlineTextNoFilesToUpload() {
|
651
|
+
return this.allowMultipleFileUploads ? this.getMessage("cmduploadform.no_files_to_upload") : this.this.getMessage("cmduploadform.no_file_to_upload")
|
652
|
+
},
|
633
653
|
fileTypeImage() {
|
634
654
|
return this.allowedFileExtensions.some(extension => extension.includes('jpg'));
|
635
655
|
},
|
@@ -1076,7 +1096,7 @@ export default {
|
|
1076
1096
|
overflow-x: hidden;
|
1077
1097
|
overflow-y: auto;
|
1078
1098
|
border: var(--default-border);
|
1079
|
-
padding:
|
1099
|
+
padding: var(--default-padding);
|
1080
1100
|
margin: 0;
|
1081
1101
|
|
1082
1102
|
> li {
|
@@ -1187,14 +1207,20 @@ export default {
|
|
1187
1207
|
}
|
1188
1208
|
}
|
1189
1209
|
|
1190
|
-
&.
|
1210
|
+
&.box {
|
1191
1211
|
display: inline-flex;
|
1192
1212
|
flex-direction: column;
|
1193
|
-
text-decoration: none;
|
1194
1213
|
background: var(--default-background-color);
|
1214
|
+
text-decoration: none;
|
1215
|
+
text-align: center;
|
1216
|
+
padding: var(--default-padding);
|
1195
1217
|
|
1196
1218
|
span {
|
1197
1219
|
margin: 0;
|
1220
|
+
|
1221
|
+
&[class*="icon-"] {
|
1222
|
+
font-size: 5rem;
|
1223
|
+
}
|
1198
1224
|
}
|
1199
1225
|
}
|
1200
1226
|
}
|
@@ -0,0 +1,171 @@
|
|
1
|
+
<template>
|
2
|
+
<CmdBox
|
3
|
+
:use-slots="['body']"
|
4
|
+
:collapsible="true"
|
5
|
+
:cmdHeadline="{headlineText: readableName(componentName), headlineLevel: 4, headlineIcon: {iconClass: 'icon-settings-template'}}"
|
6
|
+
:openCollapsedBox="true"
|
7
|
+
boxBodyClass="settings-body"
|
8
|
+
>
|
9
|
+
<template v-slot:body>
|
10
|
+
<CmdFormElement
|
11
|
+
v-for="(prop) in filteredProps" :key="prop.name"
|
12
|
+
:element="formElement(prop)"
|
13
|
+
:type="formType(prop)"
|
14
|
+
:labelText="readableName(prop.name)"
|
15
|
+
:placeholder="readableName(prop.name)"
|
16
|
+
:toggleSwitch="prop.toggleSwitch"
|
17
|
+
:colored="true"
|
18
|
+
:selectOptions="selectOptions(prop)"
|
19
|
+
:modelValue="prop.value"
|
20
|
+
@update:modelValue="onUpdateProperty(prop.name, $event)"
|
21
|
+
/>
|
22
|
+
</template>
|
23
|
+
</CmdBox>
|
24
|
+
</template>
|
25
|
+
|
26
|
+
<script>
|
27
|
+
|
28
|
+
export default {
|
29
|
+
name: "ComponentSettings",
|
30
|
+
data() {
|
31
|
+
return {
|
32
|
+
currentComponentName: ""
|
33
|
+
}
|
34
|
+
},
|
35
|
+
props: {
|
36
|
+
componentName: {
|
37
|
+
type: String,
|
38
|
+
default: ""
|
39
|
+
},
|
40
|
+
componentProps: {
|
41
|
+
type: Object,
|
42
|
+
required: true
|
43
|
+
},
|
44
|
+
componentSettings: {
|
45
|
+
type: Object,
|
46
|
+
required: true
|
47
|
+
},
|
48
|
+
componentControls: {
|
49
|
+
type: Object
|
50
|
+
}
|
51
|
+
},
|
52
|
+
computed: {
|
53
|
+
filteredProps() {
|
54
|
+
return this.filterProperties(this.componentProps, [])
|
55
|
+
}
|
56
|
+
},
|
57
|
+
methods: {
|
58
|
+
filterProperties(properties, nameParts) {
|
59
|
+
const allProps = []
|
60
|
+
|
61
|
+
for (let key in properties) {
|
62
|
+
const propType = typeof properties[key]
|
63
|
+
if (propType === "boolean" || propType === "string" || propType === "number" || (propType === "object" && key.slice(0, 3) === "cmd")) {
|
64
|
+
|
65
|
+
if(propType === "object") {
|
66
|
+
this.filterProperties(properties[key], [...nameParts, key]).forEach((item) => allProps.push(item))
|
67
|
+
} else {
|
68
|
+
const prop = {}
|
69
|
+
|
70
|
+
if (propType === "boolean") {
|
71
|
+
prop.toggleSwitch = true
|
72
|
+
}
|
73
|
+
|
74
|
+
prop.name = [...nameParts, key].join(".")
|
75
|
+
prop.type = propType
|
76
|
+
prop.value = properties[key]
|
77
|
+
|
78
|
+
allProps.push(prop)
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
return allProps
|
84
|
+
},
|
85
|
+
onUpdateProperty(propName, value) {
|
86
|
+
const nameParts = propName.split(".")
|
87
|
+
let settings = this.componentSettings
|
88
|
+
for (let i = 0; i < nameParts.length - 1; i++) {
|
89
|
+
settings = settings[nameParts.shift()]
|
90
|
+
}
|
91
|
+
|
92
|
+
if (typeof settings[nameParts[0]] === "number") {
|
93
|
+
settings[nameParts[0]] = Number(value)
|
94
|
+
} else {
|
95
|
+
settings[nameParts[0]] = value
|
96
|
+
}
|
97
|
+
},
|
98
|
+
readableName(name) {
|
99
|
+
// remove prefix from current component-name
|
100
|
+
let nameWithoutPrefix = name.replace("Cmd", "")
|
101
|
+
|
102
|
+
// remove entire prefix (componentName) for inner-component-properties
|
103
|
+
nameWithoutPrefix = nameWithoutPrefix.replace(/^[^.]*\./, '');
|
104
|
+
|
105
|
+
// use a regular expression to find the positions of capital letters
|
106
|
+
let capitalPositions = []
|
107
|
+
nameWithoutPrefix.replace(/[A-Z]/g, function (match, index) {
|
108
|
+
capitalPositions.push(index)
|
109
|
+
return match
|
110
|
+
})
|
111
|
+
|
112
|
+
// add a space before each capital letter based on the found positions
|
113
|
+
for (let i = capitalPositions.length - 1; i >= 0; i--) {
|
114
|
+
nameWithoutPrefix = nameWithoutPrefix.slice(0, capitalPositions[i]) + ' ' + nameWithoutPrefix.slice(capitalPositions[i])
|
115
|
+
}
|
116
|
+
|
117
|
+
// capitalize first letter
|
118
|
+
nameWithoutPrefix = nameWithoutPrefix.charAt(0).toUpperCase() + nameWithoutPrefix.slice(1)
|
119
|
+
|
120
|
+
return nameWithoutPrefix
|
121
|
+
},
|
122
|
+
formType(prop) {
|
123
|
+
if (Array.isArray(this.componentControls?.[prop.name])) {
|
124
|
+
return null
|
125
|
+
}
|
126
|
+
|
127
|
+
switch (prop.type) {
|
128
|
+
case "boolean":
|
129
|
+
return "checkbox"
|
130
|
+
|
131
|
+
case "number":
|
132
|
+
return "number"
|
133
|
+
|
134
|
+
default:
|
135
|
+
return "text"
|
136
|
+
|
137
|
+
}
|
138
|
+
},
|
139
|
+
formElement(prop) {
|
140
|
+
if (Array.isArray(this.componentControls?.[prop.name])) {
|
141
|
+
return "select"
|
142
|
+
} else {
|
143
|
+
return "input"
|
144
|
+
}
|
145
|
+
},
|
146
|
+
selectOptions(prop) {
|
147
|
+
if (Array.isArray(this.componentControls?.[prop.name])) {
|
148
|
+
return this.componentControls[prop.name]
|
149
|
+
} else {
|
150
|
+
return null
|
151
|
+
}
|
152
|
+
}
|
153
|
+
},
|
154
|
+
watch: {
|
155
|
+
componentName: {
|
156
|
+
handler() {
|
157
|
+
this.currentComponentName = this.componentName
|
158
|
+
},
|
159
|
+
immediate: true
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
</script>
|
164
|
+
|
165
|
+
<style>
|
166
|
+
.cmd-box .settings-body > div {
|
167
|
+
display: flex;
|
168
|
+
flex-direction: column;
|
169
|
+
gap: calc(var(--default-gap) / 2);
|
170
|
+
}
|
171
|
+
</style>
|
package/src/main.js
CHANGED
@@ -4,8 +4,8 @@ import "comand-frontend-framework/styles"
|
|
4
4
|
|
5
5
|
import { createApp } from "vue"
|
6
6
|
|
7
|
-
// import
|
8
|
-
import
|
7
|
+
// import ComponentLibrary from "./ComponentLibrary.vue"
|
8
|
+
import ComponentLibrary from "./ComponentLibrary.vue"
|
9
9
|
//import { createRouter, createWebHistory } from "vue-router"
|
10
10
|
import "clickout-event"
|
11
11
|
|
@@ -53,4 +53,4 @@ import router from "./router"
|
|
53
53
|
// })
|
54
54
|
|
55
55
|
// createApp(App).use(router).directive('telephone', directiveTelephone).directive('focus', directiveFocus).mount('#app')
|
56
|
-
createApp(
|
56
|
+
createApp(ComponentLibrary).use(router).directive('telephone', directiveTelephone).directive('focus', directiveFocus).mount('#app')
|