@mixd-id/web-scaffold 0.2.240705 → 0.2.250801009
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.
- package/docs/components/Dashboard.md +56 -0
- package/log.txt +7 -0
- package/package.json +27 -19
- package/src/components/404.vue +61 -0
- package/src/components/AccountIcon.vue +19 -0
- package/src/components/Ahref.vue +1 -1
- package/src/components/Alert.vue +4 -13
- package/src/components/ArrayList.vue +49 -0
- package/src/components/Article.vue +24 -30
- package/src/components/Button.vue +79 -167
- package/src/components/Card.vue +235 -0
- package/src/components/Carousel.vue +61 -60
- package/src/components/Cart.vue +192 -0
- package/src/components/CartIcon.vue +89 -0
- package/src/components/ChartBar.vue +2 -3
- package/src/components/Checkbox.vue +20 -11
- package/src/components/Checkout.vue +373 -0
- package/src/components/CheckoutDelivery.vue +267 -0
- package/src/components/CodeEditor.vue +5 -16
- package/src/components/CollapsiblePanel.vue +70 -0
- package/src/components/ColorPicker.vue +8 -3
- package/src/components/ColorPicker2.vue +41 -19
- package/src/components/ColorPicker3.vue +100 -0
- package/src/components/Confirm.vue +9 -7
- package/src/components/ContextMenu.vue +122 -206
- package/src/components/ContextMenuItem.vue +53 -0
- package/src/components/Dashboard.vue +243 -0
- package/src/components/Dashboard2.vue +118 -0
- package/src/components/DashboardComponentSelector.vue +96 -0
- package/src/components/DashboardConfigs.vue +202 -0
- package/src/components/Datepicker.vue +102 -41
- package/src/components/DayTimeRange.vue +3 -2
- package/src/components/Dropdown.vue +7 -4
- package/src/components/Flex.vue +14 -40
- package/src/components/GHeatMaps.vue +2 -2
- package/src/components/Grid.vue +6 -6
- package/src/components/HTMLEditor.vue +27 -14
- package/src/components/Image.vue +62 -108
- package/src/components/ImagePreview.vue +14 -4
- package/src/components/ImageUploader.vue +114 -0
- package/src/components/ImportModal.vue +3 -3
- package/src/components/Link.vue +62 -6
- package/src/components/List.vue +524 -402
- package/src/components/ListContextMenu.vue +88 -0
- package/src/components/ListItem.vue +5 -3
- package/src/components/ListPage1.vue +14 -15
- package/src/components/ListView.vue +5 -6
- package/src/components/ListViewSettings.vue +2 -2
- package/src/components/LogViewerItem.vue +1 -1
- package/src/components/MarkdownEdit.vue +128 -0
- package/src/components/MarkdownPreview.vue +102 -0
- package/src/components/MenuItem1.vue +36 -0
- package/src/components/Modal.vue +95 -43
- package/src/components/MultiDropdown.vue +124 -0
- package/src/components/MultilineText.vue +1 -4
- package/src/components/OTPField.vue +11 -17
- package/src/components/ObjectTree.vue +1 -1
- package/src/components/PageBuilder.vue +3 -3
- package/src/components/Paragraph.vue +1 -2
- package/src/components/PresetSelectorFilterItem.vue +107 -95
- package/src/components/Radio.vue +1 -1
- package/src/components/SearchModal.vue +153 -0
- package/src/components/Slider.vue +1 -1
- package/src/components/Svg.vue +1 -1
- package/src/components/SvgEditor.vue +173 -0
- package/src/components/Switch.vue +4 -5
- package/src/components/Table.vue +2 -2
- package/src/components/TableView.vue +2 -3
- package/src/components/TableViewHead.vue +2 -2
- package/src/components/Tabs.vue +1 -1
- package/src/components/Testimonial.vue +2 -2
- package/src/components/Text.vue +7 -22
- package/src/components/TextEditor.vue +3 -3
- package/src/components/TextWithTag.vue +61 -30
- package/src/components/Textarea.vue +11 -16
- package/src/components/Textbox.vue +9 -19
- package/src/components/Timepicker.vue +25 -15
- package/src/components/Toast.vue +5 -3
- package/src/components/TreeMenu.vue +122 -0
- package/src/components/TreeView.vue +15 -10
- package/src/components/TreeView2.vue +38 -0
- package/src/components/TreeViewItem.vue +58 -29
- package/src/components/TreeViewItem2.vue +55 -0
- package/src/components/Uploader.vue +45 -0
- package/src/components/Video.vue +119 -0
- package/src/components/VirtualGrid.vue +24 -7
- package/src/components/VirtualTable.vue +363 -128
- package/src/configs/dashboard/data-table.js +9 -0
- package/src/configs/web-page-builder.js +118 -0
- package/src/directives/intersect.js +26 -0
- package/src/hooks/device.js +14 -0
- package/src/index.js +62 -107
- package/src/mixin/component.js +147 -67
- package/src/themes/default/index.js +83 -155
- package/src/utils/dashboard.js +22 -962
- package/src/utils/helpers.cjs +635 -0
- package/src/utils/helpers.js +91 -60
- package/src/utils/helpers.mjs +245 -12
- package/src/utils/importer.js +22 -3
- package/src/utils/list.mjs +1509 -0
- package/src/utils/preset-selector.cjs +1455 -0
- package/src/utils/preset-selector.js +489 -95
- package/src/utils/preset-selector.mjs +59 -20
- package/src/utils/queue.js +63 -0
- package/src/utils/web.mjs +120 -0
- package/src/utils/wss.js +37 -29
- package/src/utils/wss.mjs +24 -19
- package/src/widgets/AhrefSetting.vue +16 -13
- package/src/widgets/ArticleSetting.vue +15 -27
- package/src/widgets/BackgroundColorSetting.vue +153 -0
- package/src/widgets/BorderColorSetting.vue +57 -0
- package/src/widgets/BotEditor/BotEditorActions.vue +3 -2
- package/src/widgets/BotEditor/BotEditorSettings.vue +21 -0
- package/src/widgets/BotEditor.vue +35 -15
- package/src/widgets/ButtonSetting.vue +12 -13
- package/src/widgets/CarouselSetting.vue +33 -45
- package/src/widgets/CartSetting.vue +46 -0
- package/src/widgets/CheckoutSetting.vue +46 -0
- package/src/widgets/CollapsiblePanelSetting.vue +46 -0
- package/src/widgets/ColumnSelector.vue +29 -5
- package/src/widgets/ComponentSetting.vue +1 -1
- package/src/widgets/ComponentSetting2.vue +112 -234
- package/src/widgets/ComponentSetting3.vue +1 -1
- package/src/widgets/ContactForm.vue +3 -3
- package/src/widgets/ContactFormSetting.vue +41 -30
- package/src/widgets/Dashboard/BarChart.vue +47 -11
- package/src/widgets/Dashboard/BarChartSetting.vue +1 -1
- package/src/widgets/Dashboard/DataTable.vue +125 -0
- package/src/widgets/Dashboard/DataTableSetting.vue +243 -0
- package/src/widgets/Dashboard/DatasourceSelector.vue +1 -1
- package/src/widgets/Dashboard/Doughnut.vue +49 -7
- package/src/widgets/Dashboard/DoughnutSetting.vue +2 -2
- package/src/widgets/Dashboard/Metric.vue +78 -19
- package/src/widgets/Dashboard/MetricSetting.vue +81 -28
- package/src/widgets/Dashboard/Pie.vue +55 -6
- package/src/widgets/Dashboard/PieSetting.vue +1 -1
- package/src/widgets/Dashboard/PolarArea.vue +49 -7
- package/src/widgets/Dashboard/PolarAreaSetting.vue +1 -1
- package/src/widgets/Dashboard/SharingModal.vue +4 -5
- package/src/widgets/Dashboard/ViewSelector.vue +2 -2
- package/src/widgets/Dashboard/VirtualTableSetting.vue +121 -184
- package/src/widgets/{Dashboard.vue → Dashboard0.vue} +426 -343
- package/src/widgets/EmbeddedVideoSetting.vue +7 -5
- package/src/widgets/FAQ.vue +16 -3
- package/src/widgets/FAQSetting.vue +53 -47
- package/src/widgets/FeatureList.vue +3 -0
- package/src/widgets/FeatureListSetting.vue +112 -102
- package/src/widgets/FlexSetting.vue +83 -106
- package/src/widgets/GridSetting.vue +71 -196
- package/src/widgets/Header2.vue +34 -71
- package/src/widgets/Header2Setting.vue +95 -179
- package/src/widgets/HeaderSetting.vue +16 -18
- package/src/widgets/IconListSetting.vue +69 -65
- package/src/widgets/ImageSetting.vue +33 -60
- package/src/widgets/LinkSetting.vue +60 -37
- package/src/widgets/LinkSettingModal.vue +173 -0
- package/src/widgets/LogViewer.vue +1 -1
- package/src/widgets/MarginSetting.vue +2 -2
- package/src/widgets/MenuEditor.vue +1 -1
- package/src/widgets/MenuItem1Setting.vue +78 -0
- package/src/widgets/ModalSetting.vue +42 -44
- package/src/widgets/MultiValueSetting.vue +2 -2
- package/src/widgets/MultiValueSetting2.vue +78 -45
- package/src/widgets/OGSettingModal.vue +103 -0
- package/src/widgets/PaddingSetting.vue +2 -2
- package/src/widgets/ParagraphSetting.vue +16 -13
- package/src/widgets/PositionSetting.vue +209 -0
- package/src/widgets/PresetBar.vue +359 -210
- package/src/widgets/PresetBarPivot.vue +31 -19
- package/src/widgets/PresetSelector.vue +29 -17
- package/src/widgets/SearchModalSetting.vue +70 -0
- package/src/widgets/Share.vue +1 -2
- package/src/widgets/ShareSetting.vue +67 -60
- package/src/widgets/StyleSetting.vue +227 -116
- package/src/widgets/TestimonialSetting.vue +97 -88
- package/src/widgets/TextBlockSetting.vue +16 -13
- package/src/widgets/UserActionBuilder/UserActionConsole.vue +30 -10
- package/src/widgets/UserActionBuilder/UserActionOutput.vue +2 -2
- package/src/widgets/UserActionBuilder/UserActionOutputReply.vue +64 -87
- package/src/widgets/UserActionBuilder/UserActionProps.vue +3 -3
- package/src/widgets/UserActionBuilder.vue +4 -16
- package/src/widgets/WebComponentSelector.vue +15 -11
- package/src/widgets/WebLayoutSelector.vue +41 -270
- package/src/widgets/WebPageBuilder.vue +693 -704
- package/src/widgets/WebPageBuilder2.vue +7 -7
- package/src/widgets/WebPageBuilder4/ButtonSetting.vue +0 -8
- package/src/widgets/WebPageBuilder4/CarouselSetting.vue +63 -7
- package/src/widgets/WebPageBuilder4/FlexAlignSetting.vue +3 -3
- package/src/widgets/WebPageBuilder4/FlexSetting.vue +1 -10
- package/src/widgets/WebPageBuilder4/MultiValueSetting.vue +2 -2
- package/src/widgets/WebPageBuilder4/PropertySetting.vue +0 -7
- package/src/widgets/WebPageBuilder4/WebPageComponentSelector.vue +1 -7
- package/src/widgets/WebPageBuilder4.vue +289 -575
- package/src/widgets/WebPageSelector.vue +1 -1
- package/src/widgets/YoutubeVideoSetting.vue +16 -13
- package/tailwind.config.js +3 -35
- package/docs/schema/user-action.json +0 -266
- package/src/App.vue +0 -25
- package/src/components/SearchButton.vue +0 -57
- package/src/entry-client.js +0 -27
- package/src/entry-server.js +0 -73
- package/src/events/event.js +0 -2
- package/src/main.js +0 -29
- package/src/mixin/website.js +0 -121
- package/src/router.js +0 -57
- package/src/widgets/MobileMenu.vue +0 -182
- package/src/widgets/WebPageBuilder4/ActionSetting.vue +0 -158
- package/src/widgets/WebPageBuilder4/ColorSetting.vue +0 -63
- package/src/widgets/WebPageBuilder4/DataSetting.vue +0 -92
- package/src/widgets/WebPageBuilder4/FontSizeSetting.vue +0 -76
- package/src/widgets/WebPageBuilder4/LinkSetting.vue +0 -68
- package/src/widgets/WebPageBuilder4/MobileMenuSetting.vue +0 -106
- package/src/widgets/WebPageBuilder4/Setting.vue +0 -73
- package/src/widgets/WebPageBuilder4/StyleSetting.vue +0 -77
- package/src/widgets/WebPageBuilder4/SvgSetting.vue +0 -207
- package/src/widgets/WebPageBuilder4/TextTransformSetting.vue +0 -70
- package/src/widgets/WebPageBuilder4/WebPageDataEdit.vue +0 -121
- package/test.json +0 -22
- /package/src/widgets/{Header1.vue → Header0.vue} +0 -0
- /package/src/widgets/{Header1Setting.vue → Header0Setting.vue} +0 -0
|
@@ -5,30 +5,42 @@
|
|
|
5
5
|
:style="computedStyle">
|
|
6
6
|
|
|
7
7
|
<div ref="inner" :class="computedContainerClass">
|
|
8
|
-
<div v-for="item in
|
|
8
|
+
<div v-for="item in items" :class="computedItemClass">
|
|
9
9
|
<slot v-if="$slots['default']" :item="item"></slot>
|
|
10
10
|
<component v-else :is="item.type" :="item" />
|
|
11
11
|
</div>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
|
-
<div v-if="
|
|
15
|
-
<slot name="next"
|
|
14
|
+
<div v-if="useNextPrev && (items ?? []).length > 1 && index < items.length - 1" :class="$style.carouselNext" @click="next(true)">
|
|
15
|
+
<slot name="next">
|
|
16
|
+
<div class="p-3">
|
|
17
|
+
<button :class="$style.btn">
|
|
18
|
+
<svg :class="$style.btnSvg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M438.6 278.6l-160 160C272.4 444.9 264.2 448 256 448s-16.38-3.125-22.62-9.375c-12.5-12.5-12.5-32.75 0-45.25L338.8 288H32C14.33 288 .0016 273.7 .0016 256S14.33 224 32 224h306.8l-105.4-105.4c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0l160 160C451.1 245.9 451.1 266.1 438.6 278.6z"/></svg>
|
|
19
|
+
</button>
|
|
20
|
+
</div>
|
|
21
|
+
</slot>
|
|
16
22
|
</div>
|
|
17
23
|
|
|
18
|
-
<div v-if="
|
|
24
|
+
<div v-if="useNextPrev && (items ?? []).length > 1 && index > 0" :class="$style.carouselPrev" @click="prev">
|
|
19
25
|
<slot name="prev">
|
|
26
|
+
<div class="p-3">
|
|
27
|
+
<button :class="$style.btn">
|
|
28
|
+
<svg :class="$style.btnSvg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M447.1 256C447.1 273.7 433.7 288 416 288H109.3l105.4 105.4c12.5 12.5 12.5 32.75 0 45.25C208.4 444.9 200.2 448 192 448s-16.38-3.125-22.62-9.375l-160-160c-12.5-12.5-12.5-32.75 0-45.25l160-160c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25L109.3 224H416C433.7 224 447.1 238.3 447.1 256z"/></svg>
|
|
29
|
+
</button>
|
|
30
|
+
</div>
|
|
20
31
|
</slot>
|
|
21
32
|
</div>
|
|
22
33
|
|
|
23
|
-
|
|
24
|
-
<div v-for="_index in
|
|
25
|
-
|
|
26
|
-
@click="
|
|
34
|
+
<div :class="$style.legend">
|
|
35
|
+
<div v-for="_index in items.length"
|
|
36
|
+
:class="$style.legendItem + (index === _index - 1 ? ` ${$style.legendItemActive}` : '')"
|
|
37
|
+
@click="setIndex(_index - 1)">
|
|
27
38
|
<slot name="legend">
|
|
28
|
-
|
|
39
|
+
<div></div>
|
|
29
40
|
</slot>
|
|
30
41
|
</div>
|
|
31
42
|
</div>
|
|
43
|
+
|
|
32
44
|
</div>
|
|
33
45
|
</template>
|
|
34
46
|
|
|
@@ -38,51 +50,10 @@ import {componentMixin} from "../mixin/component";
|
|
|
38
50
|
|
|
39
51
|
export default{
|
|
40
52
|
|
|
41
|
-
computed: {
|
|
42
|
-
|
|
43
|
-
cItems(){
|
|
44
|
-
|
|
45
|
-
if(!this.dataKey)
|
|
46
|
-
return this.items
|
|
47
|
-
|
|
48
|
-
const page = this.getPage()
|
|
49
|
-
const obj = page.data?.find(_ => _.key === this.dataKey)
|
|
50
|
-
return obj ?
|
|
51
|
-
obj.value.map(_ => ({
|
|
52
|
-
...this.items[0],
|
|
53
|
-
data: _
|
|
54
|
-
})) :
|
|
55
|
-
[]
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
computedContainerClass(){
|
|
59
|
-
return [
|
|
60
|
-
this.$style.inner,
|
|
61
|
-
this.containerClass
|
|
62
|
-
]
|
|
63
|
-
.filter(_ => _)
|
|
64
|
-
.join(' ')
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
computedItemClass(){
|
|
68
|
-
return [
|
|
69
|
-
this.$style.item,
|
|
70
|
-
this.itemClass
|
|
71
|
-
]
|
|
72
|
-
.filter(_ => _)
|
|
73
|
-
.join(' ')
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
},
|
|
77
|
-
|
|
78
53
|
mixins: [ componentMixin ],
|
|
79
54
|
|
|
80
55
|
props:{
|
|
81
56
|
|
|
82
|
-
data: Object,
|
|
83
|
-
|
|
84
|
-
dataKey: String,
|
|
85
|
-
|
|
86
57
|
items: Array,
|
|
87
58
|
|
|
88
59
|
infinite: {
|
|
@@ -96,10 +67,34 @@ export default{
|
|
|
96
67
|
|
|
97
68
|
useLegend: [ Boolean, Number ],
|
|
98
69
|
|
|
70
|
+
useNextPrev: [ Boolean, Number ],
|
|
71
|
+
|
|
99
72
|
},
|
|
100
73
|
|
|
101
74
|
emits: [ 'change' ],
|
|
102
75
|
|
|
76
|
+
computed: {
|
|
77
|
+
|
|
78
|
+
computedContainerClass(){
|
|
79
|
+
return [
|
|
80
|
+
this.$style.inner,
|
|
81
|
+
this.containerClass
|
|
82
|
+
]
|
|
83
|
+
.filter(_ => _)
|
|
84
|
+
.join(' ')
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
computedItemClass(){
|
|
88
|
+
return [
|
|
89
|
+
this.$style.item,
|
|
90
|
+
this.itemClass
|
|
91
|
+
]
|
|
92
|
+
.filter(_ => _)
|
|
93
|
+
.join(' ')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
},
|
|
97
|
+
|
|
103
98
|
data(){
|
|
104
99
|
return {
|
|
105
100
|
index: 0,
|
|
@@ -147,7 +142,7 @@ export default{
|
|
|
147
142
|
const index = this.index
|
|
148
143
|
let left = 0
|
|
149
144
|
const gapPx = parseInt(window.getComputedStyle(this.$refs.inner).getPropertyValue('column-gap'))
|
|
150
|
-
for(let curIndex = 0 ; curIndex < this.
|
|
145
|
+
for(let curIndex = 0 ; curIndex < this.items.length ; curIndex++){
|
|
151
146
|
const item = this.$refs.inner.children[curIndex]
|
|
152
147
|
if(curIndex < index)
|
|
153
148
|
left += (item.clientWidth + (!isNaN(gapPx) ? gapPx : 0))
|
|
@@ -168,7 +163,7 @@ export default{
|
|
|
168
163
|
},
|
|
169
164
|
|
|
170
165
|
setIndex(index){
|
|
171
|
-
if(index >= 0 && index < this.
|
|
166
|
+
if(index >= 0 && index < this.items.length){
|
|
172
167
|
this.index = index
|
|
173
168
|
this.setPosition()
|
|
174
169
|
}
|
|
@@ -177,8 +172,8 @@ export default{
|
|
|
177
172
|
next(useBack){
|
|
178
173
|
let index = this.index + 1
|
|
179
174
|
|
|
180
|
-
if(index >= this.
|
|
181
|
-
index = useBack === true ? 0 : this.
|
|
175
|
+
if(index >= this.items.length)
|
|
176
|
+
index = useBack === true ? 0 : this.items.length - 1
|
|
182
177
|
|
|
183
178
|
this.index = index
|
|
184
179
|
|
|
@@ -223,7 +218,7 @@ export default{
|
|
|
223
218
|
}
|
|
224
219
|
else if(this._props['direction'] === 'horizontal'){
|
|
225
220
|
let ix
|
|
226
|
-
if((this.index === this.
|
|
221
|
+
if((this.index === this.items.length - 1 && dx < 0) ||
|
|
227
222
|
(this.index === 0 && dx > 0)){
|
|
228
223
|
ix = parseInt(this._props['ix'] + (dx * .19812))
|
|
229
224
|
}
|
|
@@ -268,7 +263,7 @@ export default{
|
|
|
268
263
|
},
|
|
269
264
|
|
|
270
265
|
mouseDown(e){
|
|
271
|
-
if(!this.
|
|
266
|
+
if(!this.items || this.items.length <= 1)
|
|
272
267
|
return
|
|
273
268
|
|
|
274
269
|
this.stop()
|
|
@@ -318,9 +313,9 @@ export default{
|
|
|
318
313
|
<style module>
|
|
319
314
|
|
|
320
315
|
.comp{
|
|
321
|
-
white-space: nowrap;
|
|
322
316
|
overflow: hidden;
|
|
323
317
|
position: relative;
|
|
318
|
+
@apply flex flex-col;
|
|
324
319
|
}
|
|
325
320
|
|
|
326
321
|
.comp img{
|
|
@@ -328,15 +323,14 @@ export default{
|
|
|
328
323
|
}
|
|
329
324
|
|
|
330
325
|
.carouselNext{
|
|
331
|
-
@apply absolute top-0 bottom-0 right-0
|
|
326
|
+
@apply absolute top-0 bottom-0 right-0 flex items-center justify-center;
|
|
332
327
|
}
|
|
333
328
|
|
|
334
329
|
.carouselPrev{
|
|
335
|
-
@apply absolute top-0 bottom-0 left-0
|
|
330
|
+
@apply absolute top-0 bottom-0 left-0 flex items-center justify-center;
|
|
336
331
|
}
|
|
337
332
|
|
|
338
333
|
.inner{
|
|
339
|
-
white-space: nowrap;
|
|
340
334
|
will-change: transform;
|
|
341
335
|
@apply flex flex-row items-stretch;
|
|
342
336
|
}
|
|
@@ -359,5 +353,12 @@ export default{
|
|
|
359
353
|
@apply bg-primary-500;
|
|
360
354
|
}
|
|
361
355
|
|
|
356
|
+
.btn{
|
|
357
|
+
@apply w-[32px] h-[32px] md:w-[48px] md:h-[48px] rounded-full bg-black/50 flex items-center justify-center opacity-50 hover:opacity-70;
|
|
358
|
+
}
|
|
359
|
+
.btnSvg{
|
|
360
|
+
@apply w-[19px] h-[19px] md:w-[32px] md:h-[32px] fill-white/70 hover:fill-white/90;
|
|
361
|
+
}
|
|
362
|
+
|
|
362
363
|
|
|
363
364
|
</style>
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="$style.el">
|
|
3
|
+
|
|
4
|
+
<div v-if="readyState === 2" class="flex justify-center items-center min-h-[80vh]">
|
|
5
|
+
Loading...
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div v-else-if="!cart" class="flex flex-col gap-4 justify-center items-center min-h-[80vh]">
|
|
9
|
+
<div class="text-center">
|
|
10
|
+
<h1>Cart is Empty</h1>
|
|
11
|
+
<p class="max-w-[480px]">Your cart is empty, if you're interested in our products, browse products from our catalog by clicking button below.</p>
|
|
12
|
+
</div>
|
|
13
|
+
<router-link to="/" class="text-primary">Browse Catalog</router-link>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div v-else class="flex flex-col">
|
|
17
|
+
|
|
18
|
+
<div class="p-5">
|
|
19
|
+
<h3>Cart</h3>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="divide-y divide-border-50 px-3 bg-base-300 min-h-[80vh]">
|
|
23
|
+
<div v-for="item in cart.items" class="flex flex-row gap-2 p-2">
|
|
24
|
+
<Checkbox v-model="item.checked" />
|
|
25
|
+
<Image :src="item.imageUrl" class="w-[56px] aspect-square rounded-lg" />
|
|
26
|
+
<div class="flex-1 flex flex-col">
|
|
27
|
+
<small>{{ item.code }}</small>
|
|
28
|
+
<label>{{ item.name }}</label>
|
|
29
|
+
<div class="flex flex-row gap-2">
|
|
30
|
+
<strong>Rp. {{ item.price.toLocaleString() }}</strong>
|
|
31
|
+
<button type="button" class="text-primary text-xs" @click="remove(item)">
|
|
32
|
+
<svg width="11" height="11" class="fill-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 80h-82.38l-34-56.75C306.1 8.827 291.4 0 274.6 0H173.4C156.6 0 141 8.827 132.4 23.25L98.38 80H16C7.125 80 0 87.13 0 96v16C0 120.9 7.125 128 16 128H32v320c0 35.35 28.65 64 64 64h256c35.35 0 64-28.65 64-64V128h16C440.9 128 448 120.9 448 112V96C448 87.13 440.9 80 432 80zM171.9 50.88C172.9 49.13 174.9 48 177 48h94c2.125 0 4.125 1.125 5.125 2.875L293.6 80H154.4L171.9 50.88zM352 464H96c-8.837 0-16-7.163-16-16V128h288v320C368 456.8 360.8 464 352 464zM224 416c8.844 0 16-7.156 16-16V192c0-8.844-7.156-16-16-16S208 183.2 208 192v208C208 408.8 215.2 416 224 416zM144 416C152.8 416 160 408.8 160 400V192c0-8.844-7.156-16-16-16S128 183.2 128 192v208C128 408.8 135.2 416 144 416zM304 416c8.844 0 16-7.156 16-16V192c0-8.844-7.156-16-16-16S288 183.2 288 192v208C288 408.8 295.2 416 304 416z"/></svg>
|
|
33
|
+
</button>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="flex flex-col items-end gap-1">
|
|
37
|
+
<Textbox class="w-[100px]"
|
|
38
|
+
v-model="item.qty"
|
|
39
|
+
item-class="text-center p-1">
|
|
40
|
+
<template #start>
|
|
41
|
+
<button type="button"
|
|
42
|
+
class="p-2"
|
|
43
|
+
@click="item.qty = (res => res < 1 ? 1 : res)(item.qty - 1)">
|
|
44
|
+
<svg width="14" height="14" class="fill-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280H40c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h368C421.3 232 432 242.8 432 256z"/></svg>
|
|
45
|
+
</button>
|
|
46
|
+
</template>
|
|
47
|
+
<template #end>
|
|
48
|
+
<button type="button"
|
|
49
|
+
class="p-2"
|
|
50
|
+
@click="item.qty = (res => res > 5 ? 5 : res)(item.qty + 1)">
|
|
51
|
+
<svg width="14" height="14" class="fill-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256C432 269.3 421.3 280 408 280h-160v160c0 13.25-10.75 24.01-24 24.01S200 453.3 200 440v-160h-160c-13.25 0-24-10.74-24-23.99C16 242.8 26.75 232 40 232h160v-160c0-13.25 10.75-23.99 24-23.99S248 58.75 248 72v160h160C421.3 232 432 242.8 432 256z"/></svg>
|
|
52
|
+
</button>
|
|
53
|
+
</template>
|
|
54
|
+
</Textbox>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="p-5 py-3 bg-base-300 flex flex-row sticky bottom-0 border-t-[1px] border-border-50">
|
|
60
|
+
<div v-if="cart?.total > 0" class="flex flex-col flex-1 leading-3">
|
|
61
|
+
<small>Total</small>
|
|
62
|
+
<h5>Rp. {{ cart.total.toLocaleString() }}</h5>
|
|
63
|
+
</div>
|
|
64
|
+
<div v-else class="flex-1"></div>
|
|
65
|
+
<Button ref="checkoutBtn"
|
|
66
|
+
class="px-3"
|
|
67
|
+
:state="canCheckout ? 1 : -1"
|
|
68
|
+
@click="checkout">
|
|
69
|
+
Checkout
|
|
70
|
+
</Button>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<script>
|
|
79
|
+
|
|
80
|
+
import axios from "axios";
|
|
81
|
+
import {invokeAfterIdle} from "../utils/helpers.mjs";
|
|
82
|
+
|
|
83
|
+
export default {
|
|
84
|
+
|
|
85
|
+
inject: [ 'alert' ],
|
|
86
|
+
|
|
87
|
+
computed: {
|
|
88
|
+
|
|
89
|
+
canCheckout(){
|
|
90
|
+
return this.apiUrl &&
|
|
91
|
+
this.cart && (this.cart.items ?? []).some(item => item.checked)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
props: {
|
|
97
|
+
|
|
98
|
+
apiUrl: String
|
|
99
|
+
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
methods: {
|
|
103
|
+
|
|
104
|
+
calculate(){
|
|
105
|
+
if(!this.cart) return
|
|
106
|
+
|
|
107
|
+
let subtotal = 0;
|
|
108
|
+
for(let item of this.cart.items){
|
|
109
|
+
if(!item.checked) continue
|
|
110
|
+
|
|
111
|
+
subtotal += item.qty * item.price
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this.cart.total = subtotal
|
|
115
|
+
|
|
116
|
+
this.update()
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
checkout(){
|
|
120
|
+
this.$refs.checkoutBtn.setState(2)
|
|
121
|
+
axios.post(import.meta.env.VITE_API_HOST + this.apiUrl, {
|
|
122
|
+
action: 'checkout',
|
|
123
|
+
cart: this.cart
|
|
124
|
+
})
|
|
125
|
+
.then(res => {
|
|
126
|
+
if(res.data.target)
|
|
127
|
+
this.$router.push(res.data.target)
|
|
128
|
+
})
|
|
129
|
+
.catch(err => this.alert(err))
|
|
130
|
+
.finally(_ => this.$refs.checkoutBtn.resetState())
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
load(){
|
|
134
|
+
this.readyState = 2
|
|
135
|
+
axios.get(import.meta.env.VITE_API_HOST + this.apiUrl)
|
|
136
|
+
.then(res => {
|
|
137
|
+
this.cart = res.data
|
|
138
|
+
this.readyState = 1
|
|
139
|
+
})
|
|
140
|
+
.catch(err => {
|
|
141
|
+
this.readyState = -1
|
|
142
|
+
this.error = err
|
|
143
|
+
})
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
remove(item){
|
|
147
|
+
this.cart.items.splice(this.cart.items.indexOf(item), 1)
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
update: invokeAfterIdle(function(){
|
|
151
|
+
axios.post(import.meta.env.VITE_API_HOST + this.apiUrl, {
|
|
152
|
+
action: 'update',
|
|
153
|
+
cart: this.cart
|
|
154
|
+
})
|
|
155
|
+
}, 1000),
|
|
156
|
+
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
data(){
|
|
160
|
+
return {
|
|
161
|
+
cart: null,
|
|
162
|
+
readyState: 1,
|
|
163
|
+
error: null,
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
mounted() {
|
|
168
|
+
this.load()
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
watch: {
|
|
172
|
+
|
|
173
|
+
cart: {
|
|
174
|
+
deep: true,
|
|
175
|
+
handler(){
|
|
176
|
+
this.calculate()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
</script>
|
|
185
|
+
|
|
186
|
+
<style module>
|
|
187
|
+
|
|
188
|
+
.el{
|
|
189
|
+
@apply flex flex-col;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
</style>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button type="button"
|
|
3
|
+
:class="$style.comp"
|
|
4
|
+
@click="$refs.contextMenu.open($el)">
|
|
5
|
+
|
|
6
|
+
<div :class="$style.badge">3</div>
|
|
7
|
+
|
|
8
|
+
<slot name="icon">
|
|
9
|
+
<component v-if="items?.length > 0"
|
|
10
|
+
v-for="item in items"
|
|
11
|
+
:is="item.type"
|
|
12
|
+
:key="item.key"
|
|
13
|
+
:="item" />
|
|
14
|
+
|
|
15
|
+
<svg v-else
|
|
16
|
+
width="16"
|
|
17
|
+
height="16px"
|
|
18
|
+
class="fill-text"
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M416 160h-72V120C344 53.83 290.2 0 224 0S104 53.83 104 120V160H32C14.33 160 0 174.3 0 192v240C0 476.2 35.82 512 80 512h288c44.18 0 80-35.82 80-80V192C448 174.3 433.7 160 416 160zM152 120C152 80.3 184.3 48 224 48s72 32.3 72 72V160h-144V120zM400 432c0 17.64-14.36 32-32 32h-288c-17.64 0-32-14.36-32-32v-224h56v56C104 277.3 114.8 288 128 288s24-10.75 24-24V208h144v56C296 277.3 306.8 288 320 288s24-10.75 24-24V208h56V432z"/></svg>
|
|
21
|
+
</slot>
|
|
22
|
+
|
|
23
|
+
<ContextMenu ref="contextMenu"
|
|
24
|
+
position="bottom-right"
|
|
25
|
+
class="border-transparent">
|
|
26
|
+
<div class="flex flex-col min-w-[300px] divide-y divide-border-50">
|
|
27
|
+
|
|
28
|
+
<div class="" @click.stop>
|
|
29
|
+
<div class="p-5 py-3 flex flex-row items-center">
|
|
30
|
+
<div class="flex-1">
|
|
31
|
+
<h5>Shopping Cart</h5>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div>
|
|
36
|
+
<div class="min-h-[160px] flex items-center justify-center">
|
|
37
|
+
<label class="text-text-400">
|
|
38
|
+
No item in cart
|
|
39
|
+
</label>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="text-center p-3">
|
|
45
|
+
<router-link to="/cart" type="button" class="text-primary">Open Cart</router-link>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
</div>
|
|
49
|
+
</ContextMenu>
|
|
50
|
+
|
|
51
|
+
</button>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<script>
|
|
55
|
+
|
|
56
|
+
import {componentMixin} from "../mixin/component";
|
|
57
|
+
|
|
58
|
+
export default {
|
|
59
|
+
|
|
60
|
+
mixins: [ componentMixin ],
|
|
61
|
+
|
|
62
|
+
props: {
|
|
63
|
+
|
|
64
|
+
items: Array
|
|
65
|
+
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
methods: {
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<style module>
|
|
78
|
+
|
|
79
|
+
.comp{
|
|
80
|
+
@apply relative;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.badge{
|
|
84
|
+
@apply rounded-full w-[16px] h-[16px] bg-text text-white pointer-events-none;
|
|
85
|
+
@apply absolute bottom-[-6px] right-[-12px];
|
|
86
|
+
@apply flex items-center justify-center text-xs;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
</style>
|
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
<script>
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import Chart from 'chart.js/auto'
|
|
10
|
+
import {Bar} from 'vue-chartjs';
|
|
12
11
|
import dayjs from "dayjs";
|
|
13
|
-
import groupBy from "
|
|
12
|
+
import {groupBy} from "../utils/helpers.mjs";
|
|
14
13
|
|
|
15
14
|
export default{
|
|
16
15
|
|
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="$style.comp">
|
|
3
3
|
<input :id="id" type="checkbox" :checked="checked" @change="onChange" :disabled="isDisabled"/>
|
|
4
|
-
<label :for="id" :class="labelClass" class="whitespace-nowrap text-ellipsis overflow-hidden">
|
|
5
|
-
<
|
|
4
|
+
<label :for="id" :class="labelClass" class="whitespace-nowrap text-ellipsis overflow-hidden flex flex-row">
|
|
5
|
+
<span :class="$style.indicator" v-if="Boolean(showIcon)">
|
|
6
6
|
<Transition name="checkbox">
|
|
7
7
|
<div v-if="checked">
|
|
8
8
|
<svg width="14" height="14" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M470.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 338.7 425.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>
|
|
9
9
|
</div>
|
|
10
10
|
</Transition>
|
|
11
|
-
</
|
|
12
|
-
<
|
|
11
|
+
</span>
|
|
12
|
+
<div v-if="$slots.default" class="ml-2">
|
|
13
13
|
<slot name="default"></slot>
|
|
14
|
-
</
|
|
15
|
-
<slot v-else name="item"></slot>
|
|
14
|
+
</div>
|
|
16
15
|
</label>
|
|
17
16
|
</div>
|
|
18
17
|
</template>
|
|
19
18
|
|
|
20
19
|
<script>
|
|
21
20
|
|
|
22
|
-
import {
|
|
21
|
+
import {parseBoolean} from "../utils/helpers.mjs";
|
|
23
22
|
|
|
24
23
|
export default {
|
|
25
24
|
|
|
@@ -40,7 +39,7 @@ export default {
|
|
|
40
39
|
computed: {
|
|
41
40
|
|
|
42
41
|
id(){
|
|
43
|
-
return this.$style.comp + this.uniqid()
|
|
42
|
+
return this.mounted ? this.$style.comp + this.uniqid() : ''
|
|
44
43
|
},
|
|
45
44
|
|
|
46
45
|
isDisabled(){
|
|
@@ -78,6 +77,12 @@ export default {
|
|
|
78
77
|
|
|
79
78
|
},
|
|
80
79
|
|
|
80
|
+
data(){
|
|
81
|
+
return {
|
|
82
|
+
mounted: false
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
|
|
81
86
|
methods: {
|
|
82
87
|
|
|
83
88
|
onChange(e){
|
|
@@ -118,7 +123,11 @@ export default {
|
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
|
|
121
|
-
}
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
mounted() {
|
|
129
|
+
this.mounted = true
|
|
130
|
+
}
|
|
122
131
|
|
|
123
132
|
}
|
|
124
133
|
|
|
@@ -131,7 +140,7 @@ export default {
|
|
|
131
140
|
}
|
|
132
141
|
|
|
133
142
|
.comp label{
|
|
134
|
-
@apply flex flex-row items-start
|
|
143
|
+
@apply flex flex-row items-start;
|
|
135
144
|
}
|
|
136
145
|
|
|
137
146
|
.comp label *{
|
|
@@ -151,7 +160,7 @@ export default {
|
|
|
151
160
|
}
|
|
152
161
|
|
|
153
162
|
.indicator{
|
|
154
|
-
@apply w-[21px] h-[21px] rounded-lg border-[1px] border-text-
|
|
163
|
+
@apply min-w-[21px] w-[21px] h-[21px] rounded-lg border-[1px] border-text-300 bg-base-300;
|
|
155
164
|
@apply flex items-center justify-center overflow-hidden;
|
|
156
165
|
transition: border 300ms cubic-bezier(0.25, 1, 0.5, 1);
|
|
157
166
|
}
|