@mptw/skylens-ui 1.0.0

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.
Files changed (143) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintrc.cjs +4 -0
  3. package/.nuxtrc +1 -0
  4. package/.playground/app.config.ts +5 -0
  5. package/.playground/nuxt.config.ts +3 -0
  6. package/README.md +73 -0
  7. package/app.config.ts +5 -0
  8. package/app.vue +3 -0
  9. package/assets/css/fonts/MEShPlus-font-icon.eot +0 -0
  10. package/assets/css/fonts/MEShPlus-font-icon.svg +186 -0
  11. package/assets/css/fonts/MEShPlus-font-icon.ttf +0 -0
  12. package/assets/css/fonts/MEShPlus-font-icon.woff +0 -0
  13. package/assets/css/icons.css +555 -0
  14. package/assets/css/layout.styl +98 -0
  15. package/assets/css/tailwind.css +3 -0
  16. package/assets/images/commons/app-logo-white.png +0 -0
  17. package/assets/images/commons/app-logo.png +0 -0
  18. package/assets/images/commons/empty-box.png +0 -0
  19. package/assets/images/commons/watermark.svg +15 -0
  20. package/components/SLAlertModal.vue +99 -0
  21. package/components/SLBreadcrumbs.vue +42 -0
  22. package/components/SLButton.vue +301 -0
  23. package/components/SLCalendarButton.vue +259 -0
  24. package/components/SLCalendarPopup.vue +832 -0
  25. package/components/SLCard.vue +118 -0
  26. package/components/SLChart.vue +181 -0
  27. package/components/SLCheckbox.vue +179 -0
  28. package/components/SLCircleButton.vue +95 -0
  29. package/components/SLCollapsableBlock.vue +116 -0
  30. package/components/SLCollapsableMulitPillSelect.vue +92 -0
  31. package/components/SLConfirmModal.vue +122 -0
  32. package/components/SLDateInput.vue +460 -0
  33. package/components/SLDatePicker.vue +143 -0
  34. package/components/SLDistributor.vue +30 -0
  35. package/components/SLDownloadButton.vue +410 -0
  36. package/components/SLDraggable.vue +151 -0
  37. package/components/SLDropdown.vue +277 -0
  38. package/components/SLDropdownItem.vue +31 -0
  39. package/components/SLElementWithTitle.vue +181 -0
  40. package/components/SLEyeCheckbox.vue +162 -0
  41. package/components/SLFileInput.vue +101 -0
  42. package/components/SLGenderAgeSelect.vue +279 -0
  43. package/components/SLHeatMap.vue +151 -0
  44. package/components/SLHourRangeInput.vue +211 -0
  45. package/components/SLIOSSwitch.vue +235 -0
  46. package/components/SLIcon.vue +35 -0
  47. package/components/SLIconButton.vue +130 -0
  48. package/components/SLInfoTip.vue +221 -0
  49. package/components/SLInsightSitePage.vue +27 -0
  50. package/components/SLLegend.vue +76 -0
  51. package/components/SLLinearProgressBar.vue +35 -0
  52. package/components/SLLink.vue +162 -0
  53. package/components/SLLoading.vue +127 -0
  54. package/components/SLMapChart.vue +151 -0
  55. package/components/SLModal.vue +377 -0
  56. package/components/SLMonthCalendarButton.vue +378 -0
  57. package/components/SLMonthPicker.vue +151 -0
  58. package/components/SLMultiSelect.vue +121 -0
  59. package/components/SLNoData.vue +43 -0
  60. package/components/SLPageModal.vue +64 -0
  61. package/components/SLPagination.vue +192 -0
  62. package/components/SLPillCheckbox.vue +207 -0
  63. package/components/SLPillLabel.vue +101 -0
  64. package/components/SLPopupMenuButton.vue +158 -0
  65. package/components/SLProfileButton.vue +186 -0
  66. package/components/SLRadioButton.vue +97 -0
  67. package/components/SLRadioButtonGroup.vue +113 -0
  68. package/components/SLRadioGroup.vue +201 -0
  69. package/components/SLRangeInput.vue +209 -0
  70. package/components/SLRegionsMapChart.vue +151 -0
  71. package/components/SLRightSider.vue +242 -0
  72. package/components/SLSearchInput.vue +87 -0
  73. package/components/SLSelect.vue +545 -0
  74. package/components/SLSelectAllToggle.vue +118 -0
  75. package/components/SLSiderbarNav.vue +394 -0
  76. package/components/SLSiderbarNavItem.vue +204 -0
  77. package/components/SLSitePage.vue +96 -0
  78. package/components/SLSkyInsightSitePage.vue +27 -0
  79. package/components/SLSortByDropdown.vue +189 -0
  80. package/components/SLSpinIcon.vue +24 -0
  81. package/components/SLStayRangeInput.vue +306 -0
  82. package/components/SLTab.vue +159 -0
  83. package/components/SLTable.vue +409 -0
  84. package/components/SLTableTooltip.vue +111 -0
  85. package/components/SLTabs.vue +388 -0
  86. package/components/SLTextInput.vue +362 -0
  87. package/components/SLTextarea.vue +134 -0
  88. package/components/SLToast.vue +71 -0
  89. package/components/SLToggleButton.vue +78 -0
  90. package/components/SLTwoLayerMultiSelect.vue +428 -0
  91. package/components/SLTwoLayerSelect.vue +265 -0
  92. package/components/SLWarnModal.vue +75 -0
  93. package/interface/IDateRange.ts +5 -0
  94. package/interface/IHourRange.ts +4 -0
  95. package/interface/IInputOption.ts +6 -0
  96. package/interface/ILegendItem.ts +7 -0
  97. package/interface/IPopupMenuButton.ts +5 -0
  98. package/interface/IStayRange.ts +15 -0
  99. package/interface/ITableField.ts +19 -0
  100. package/interface/IWeb.ts +5 -0
  101. package/interface/NavConfigType.ts +14 -0
  102. package/interface/commons.ts +7 -0
  103. package/models/DateRange.ts +21 -0
  104. package/nuxt.config.ts +22 -0
  105. package/package.json +52 -0
  106. package/plugins/googlemaps.ts +17 -0
  107. package/plugins/v-calendar.ts +5 -0
  108. package/public/assets/files/taiwan-regions.json +7 -0
  109. package/public/assets/files/taiwan.json +24 -0
  110. package/public/assets/images/commons/default-favico.png +0 -0
  111. package/public/assets/images/dashboard/closure-button-icon.png +0 -0
  112. package/public/assets/images/dashboard/dashboard-widget-bar-chart-icon-disabled.png +0 -0
  113. package/public/assets/images/dashboard/dashboard-widget-bar-chart-icon-poi.png +0 -0
  114. package/public/assets/images/dashboard/dashboard-widget-bar-chart-icon-web.png +0 -0
  115. package/public/assets/images/dashboard/dashboard-widget-country-heatmap-chart-icon-disabled.png +0 -0
  116. package/public/assets/images/dashboard/dashboard-widget-country-heatmap-chart-icon.png +0 -0
  117. package/public/assets/images/dashboard/dashboard-widget-geo-list-icon-disabled.png +0 -0
  118. package/public/assets/images/dashboard/dashboard-widget-geo-list-icon-poi.png +0 -0
  119. package/public/assets/images/dashboard/dashboard-widget-geo-list-icon-web.png +0 -0
  120. package/public/assets/images/dashboard/dashboard-widget-heatmap-chart-icon-disabled.png +0 -0
  121. package/public/assets/images/dashboard/dashboard-widget-heatmap-chart-icon-web.png +0 -0
  122. package/public/assets/images/dashboard/dashboard-widget-line-chart-icon-disabled.png +0 -0
  123. package/public/assets/images/dashboard/dashboard-widget-line-chart-icon-poi.png +0 -0
  124. package/public/assets/images/dashboard/dashboard-widget-list-icon-disabled.png +0 -0
  125. package/public/assets/images/dashboard/dashboard-widget-list-icon-poi.png +0 -0
  126. package/public/assets/images/dashboard/dashboard-widget-list-icon-web.png +0 -0
  127. package/public/assets/images/dashboard/dashboard-widget-pie-chart-icon-disabled.png +0 -0
  128. package/public/assets/images/dashboard/dashboard-widget-pie-chart-icon-poi.png +0 -0
  129. package/public/assets/images/dashboard/dashboard-widget-pie-chart-icon-web.png +0 -0
  130. package/public/assets/images/dashboard/drag-hint-icon.svg +3 -0
  131. package/public/assets/images/dashboard/extend-button-icon.png +0 -0
  132. package/public/assets/images/dashboard/map-list-chart-icon.svg +17 -0
  133. package/public/assets/images/dashboard/map-marker-chart-icon.svg +32 -0
  134. package/public/assets/images/dashboard/pie-chart-icon.svg +4 -0
  135. package/public/assets/images/dashboard/poi-gender-age-chart-icon.svg +20 -0
  136. package/public/assets/images/dashboard/poi-nav-icon.png +0 -0
  137. package/public/assets/images/dashboard/web-gender-age-chart-icon.svg +20 -0
  138. package/public/assets/images/dashboard/web-nav-icon.png +0 -0
  139. package/tailwind.config.js +300 -0
  140. package/tsconfig.json +8 -0
  141. package/utils/constants.ts +160 -0
  142. package/utils/generateSheet.ts +36 -0
  143. package/utils/index.ts +539 -0
@@ -0,0 +1,99 @@
1
+ <template lang="pug">
2
+ SLModal(
3
+ :show="show"
4
+ :title="title"
5
+ size="xs"
6
+ :backdrop="true"
7
+ :closeOnBackdrop="false"
8
+ modalClass='alert-modal'
9
+ @update:show="onUpdatedShow"
10
+ )
11
+ slot
12
+ SLIcon(
13
+ v-if="color === 'primary'"
14
+ icon="check-circle"
15
+ ).text-secondary
16
+ SLIcon(
17
+ v-else
18
+ icon="exclamation-triangle"
19
+ :class="color === '' ? '' : `text-${color}-hover`"
20
+ )
21
+ p(v-html='message')
22
+ template(#footer)
23
+ SLButton(
24
+ color="primary"
25
+ size="lg"
26
+ :title="buttonTitle"
27
+ @click="onClickedConfirm"
28
+ )
29
+ </template>
30
+
31
+ <script lang="ts">
32
+ export default defineComponent({
33
+ name: "SLAlertModal",
34
+ components: {},
35
+ props: {
36
+ show: {
37
+ type: Boolean,
38
+ default: false,
39
+ },
40
+ title: {
41
+ type: String,
42
+ default: "",
43
+ },
44
+ buttonTitle: {
45
+ type: String,
46
+ default: "確定",
47
+ },
48
+ color: {
49
+ type: String,
50
+ default: "secondary",
51
+ validator: (value: string) =>
52
+ ["", "primary", "secondary", "danger"].includes(value),
53
+ },
54
+ message: {
55
+ type: String,
56
+ default: "",
57
+ },
58
+ },
59
+ emits: ["update:show"],
60
+ setup(_, { emit }) {
61
+ function onClickedConfirm() {
62
+ emit("update:show", false);
63
+ }
64
+
65
+ function onUpdatedShow(value: boolean) {
66
+ emit("update:show", value);
67
+ }
68
+
69
+ return {
70
+ onClickedConfirm,
71
+ onUpdatedShow,
72
+ };
73
+ },
74
+ });
75
+ </script>
76
+
77
+ <style lang="stylus">
78
+ .alert-modal
79
+ @apply z-60
80
+
81
+ .modal-backdrop
82
+ @apply s('bg-white/40') backdrop-blur-5
83
+
84
+ &.show
85
+ @apply s('bg-white/40')
86
+
87
+ .modal-body
88
+ &-content
89
+ @apply text-base leading-6 text-gray-2 text-center space-y-4
90
+
91
+ .icon
92
+ @apply s('text-7.17xl')
93
+
94
+ p
95
+ @apply whitespace-pre-wrap
96
+
97
+ .modal-footer
98
+ @apply flex justify-center
99
+ </style>
@@ -0,0 +1,42 @@
1
+ <template lang="pug">
2
+ .breadcrumbs
3
+ .breadcrumbs-container
4
+ template(v-for="item, i in items")
5
+ span.breadcrumb-divider(v-if="i > 0") |
6
+ span.breadcrumb-item {{ item }}
7
+ SLInfoTip(v-if="info !== ''" :info="info")
8
+ .breadcrumbs-notice(v-if="$slots.notice")
9
+ slot(name="notice")
10
+ </template>
11
+
12
+ <script lang="ts">
13
+ import type { PropType } from "vue";
14
+
15
+ export default defineComponent({
16
+ name: "SLBreadcrumbs",
17
+ components: {},
18
+ props: {
19
+ items: {
20
+ type: Array as PropType<Array<string>>,
21
+ default: () => [],
22
+ },
23
+ info: {
24
+ type: String,
25
+ default: "",
26
+ },
27
+ },
28
+ setup() {},
29
+ });
30
+ </script>
31
+
32
+ <style lang="stylus">
33
+ .breadcrumbs
34
+ @apply flex flex-wrap items-center justify-start text-lg text-primary font-bold
35
+
36
+ &-container
37
+ .breadcrumb-item:not(:last-child)
38
+ @apply text-base font-normal
39
+
40
+ &-notice
41
+ @apply inline-flex items-center
42
+ </style>
@@ -0,0 +1,301 @@
1
+ <template lang="pug">
2
+ button(:type='type', :class='btnClass' :disabled="disabled")
3
+ .btn-content
4
+ slot
5
+ SLIcon(v-if='icon !== ""', :icon='icon')
6
+ span(v-if='title !== ""') {{ title }}
7
+ SLIcon(v-if='postIcon !== ""', :icon='postIcon')
8
+ .btn-loading
9
+ .loading
10
+ div
11
+ div
12
+ div
13
+ div
14
+ </template>
15
+
16
+ <script lang="ts">
17
+ import type { PropType } from "vue";
18
+
19
+ export default defineComponent({
20
+ name: "SLButton",
21
+ components: {},
22
+ props: {
23
+ size: {
24
+ type: String,
25
+ default: "",
26
+ validator: (val: string) => ["", "lg", "md", "sm", "xs"].includes(val),
27
+ },
28
+ color: {
29
+ type: String,
30
+ default: "",
31
+ validator: (val: string) =>
32
+ [
33
+ "",
34
+ "white",
35
+ "primary",
36
+ "primary-hover",
37
+ "secondary",
38
+ "third",
39
+ "danger",
40
+ "cancel",
41
+ "gray-2",
42
+ "secondary-new",
43
+ "blue-1",
44
+ "insight-title-line",
45
+ ].includes(val),
46
+ },
47
+ variant: {
48
+ type: String,
49
+ default: "",
50
+ validator: (val: string) => ["", "outline", "icon"].includes(val),
51
+ },
52
+ disabled: {
53
+ type: Boolean,
54
+ default: false,
55
+ },
56
+ icon: {
57
+ type: String,
58
+ default: "",
59
+ },
60
+ postIcon: {
61
+ type: String,
62
+ default: "",
63
+ },
64
+ title: {
65
+ type: String,
66
+ default: "",
67
+ },
68
+ type: {
69
+ type: String as PropType<"submit" | "reset" | "button">,
70
+ default: "button",
71
+ validator: (val: string) => ["submit", "reset", "button"].includes(val),
72
+ },
73
+ loading: {
74
+ type: Boolean,
75
+ default: false,
76
+ },
77
+ },
78
+ setup(props, { emit }) {
79
+ const { size, color, variant, disabled, loading } = toRefs(props);
80
+
81
+ const btnClass = computed(() => {
82
+ const btnClass = ["btn"];
83
+ if (size.value !== "") {
84
+ btnClass.push(`btn-${size.value}`);
85
+ }
86
+ if (color.value !== "") {
87
+ btnClass.push(`btn-${color.value}`);
88
+ }
89
+ if (variant.value !== "") {
90
+ btnClass.push(`btn-${variant.value}`);
91
+ }
92
+ if (disabled.value) {
93
+ btnClass.push("btn-disabled");
94
+ }
95
+ if (loading.value) {
96
+ btnClass.push("loading");
97
+ }
98
+
99
+ return btnClass.join(" ");
100
+ });
101
+
102
+ return {
103
+ btnClass,
104
+ };
105
+ },
106
+ });
107
+ </script>
108
+
109
+ <style lang="stylus">
110
+ .btn
111
+ @apply relative inline-flex items-center justify-center s("p-1.75") border border-transparent rounded bg-transparent text-base leading-normal s("focus:outline-none")
112
+
113
+ &-lg
114
+ @apply s("px-7.75")
115
+
116
+ &-md
117
+ @apply s("px-3.75")
118
+
119
+ &-sm
120
+ @apply s("py-0.75") s("px-1.75")
121
+
122
+ .btn-content
123
+ @apply space-x-1
124
+
125
+ &-xs
126
+ @apply s("py-0.75") s("px-1.75") text-xs
127
+
128
+ .btn-content
129
+ @apply space-x-1
130
+
131
+ &-white
132
+ @apply bg-white border-white text-gray-2 s("hover:bg-white") s("hover:border-white")
133
+
134
+ &.btn-outline
135
+ @apply text-gray-2 s("hover:text-gray-2")
136
+
137
+ .btn-loading
138
+ .loading
139
+ div
140
+ border-color white transparent transparent transparent
141
+
142
+ &-primary
143
+ @apply bg-primary border-primary text-gray s("hover:bg-primary-hover") s("hover:border-primary-hover")
144
+
145
+ &.btn-outline
146
+ @apply text-primary s("hover:text-primary-hover")
147
+
148
+ .btn-loading
149
+ .loading
150
+ div
151
+ border-color theme('colors.primary.DEFAULT') transparent transparent transparent
152
+
153
+ &-primary-hover
154
+ @apply bg-primary-hover border-primary-hover text-gray s("hover:bg-primary-lighter") s("hover:border-primary-lighter")
155
+
156
+ &.btn-outline
157
+ @apply text-primary-hover s("hover:text-primary-lighter")
158
+
159
+ .btn-loading
160
+ .loading
161
+ div
162
+ border-color theme('colors.primary.hover') transparent transparent transparent
163
+
164
+ &-secondary
165
+ @apply bg-secondary border-secondary text-gray s("hover:bg-secondary-hover") s("hover:text-white") s("hover:border-secondary-hover")
166
+
167
+ &.btn-outline
168
+ @apply text-secondary s("hover:text-secondary-hover")
169
+
170
+ .btn-loading
171
+ .loading
172
+ div
173
+ border-color theme('colors.secondary.hover') transparent transparent transparent
174
+
175
+ &-third
176
+ @apply bg-third-7 border-third-7 text-white s("hover:bg-third-hover") s("hover:text-white") s("hover:border-third-hover")
177
+
178
+ &.btn-outline
179
+ @apply text-secondary s("hover:text-secondary-hover")
180
+
181
+ .btn-loading
182
+ .loading
183
+ div
184
+ border-color theme('colors.third.hover') transparent transparent transparent
185
+
186
+ &-danger
187
+ @apply bg-danger border-danger text-white s("hover:bg-danger-hover") s("hover:border-danger-hover")
188
+
189
+ &.btn-outline
190
+ @apply text-danger s("hover:text-danger-hover")
191
+
192
+ .btn-loading
193
+ .loading
194
+ div
195
+ border-color theme('colors.danger.hover') transparent transparent transparent
196
+
197
+ &-cancel
198
+ @apply bg-cancel border-cancel text-gray-2 s("hover:bg-cancel-hover") s("hover:border-cancel-hover")
199
+
200
+ &.btn-outline
201
+ @apply text-cancel s("hover:text-cancel-hover")
202
+
203
+ .btn-loading
204
+ .loading
205
+ div
206
+ border-color theme('colors.cancel.hover') transparent transparent transparent
207
+
208
+ &-gray-2
209
+ @apply bg-gray-2 border-gray-2 text-white s("hover:bg-gray-3") s("hover:border-gray-3")
210
+
211
+ &.btn-outline
212
+ @apply text-gray-2 s("hover:text-gray-3")
213
+
214
+ .btn-loading
215
+ .loading
216
+ div
217
+ border-color theme('colors.gray.3') transparent transparent transparent
218
+
219
+ &-secondary-new
220
+ @apply bg-secondary-new border-secondary-new text-white s("hover:bg-secondary-new") s("hover:border-secondary-new")
221
+
222
+ &.btn-outline
223
+ @apply text-secondary-new s("hover:text-secondary-new")
224
+
225
+ .btn-loading
226
+ .loading
227
+ div
228
+ border-color theme('colors.secondary.new') transparent transparent transparent
229
+
230
+ &-blue-1
231
+ @apply bg-secondary-new border-secondary-new text-white s("hover:bg-blue-1") s("hover:border-blue-1")
232
+
233
+ &.btn-outline
234
+ @apply text-blue-1 s("hover:text-blue-1")
235
+
236
+ .btn-loading
237
+ .loading
238
+ div
239
+ border-color theme('colors.blue.1') transparent transparent transparent
240
+
241
+ &-insight-title-line
242
+ @apply bg-insight-title-line border-insight-title-line text-white s("hover:bg-insight-title-line") s("hover:border-insight-title-line")
243
+
244
+ &.btn-outline
245
+ @apply text-insight-title s("hover:text-insight-title")
246
+
247
+ .btn-loading
248
+ .loading
249
+ div
250
+ border-color theme('colors.blue.1') transparent transparent transparent
251
+
252
+ &-outline
253
+ @apply bg-transparent border s("hover:bg-white")
254
+
255
+ &-disabled
256
+ @apply bg-cancel border-cancel text-white cursor-default s("hover:bg-cancel") s("hover:border-cancel") s("hover:text-white")
257
+
258
+ &.btn-outline
259
+ @apply bg-cancel border-cancel text-white s("hover:bg-cancel") s("hover:border-cancel") s("hover:text-white")
260
+
261
+ &.btn-icon
262
+ @apply bg-transparent border-transparent text-cancel s("hover:bg-transparent") s("hover:border-transparent") s("hover:text-cancel")
263
+
264
+ &.loading
265
+ @apply bg-line border-line cursor-default
266
+
267
+ .btn-content
268
+ @apply opacity-0
269
+
270
+ .btn-loading
271
+ @apply block
272
+
273
+ .btn-content
274
+ @apply inline-flex items-center space-x-2
275
+
276
+ .btn-loading
277
+ @apply absolute s('top-1/2') s('left-1/2') w-4 h-4 s('-translate-x-1/2') s('-translate-y-1/2') pointer-events-none hidden
278
+
279
+ .loading
280
+ @apply relative inline-block w-4 h-4
281
+
282
+ div
283
+ @apply absolute block w-4 h-4 border-2 rounded-full
284
+ animation loading 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite
285
+
286
+ &:nth-child(1)
287
+ animation-delay -0.45s
288
+
289
+ &:nth-child(2)
290
+ animation-delay -0.3s
291
+
292
+ &:nth-child(3)
293
+ animation-delay -0.15s
294
+
295
+ @keyframes loading
296
+ 0%
297
+ transform rotate(0deg)
298
+
299
+ 100%
300
+ transform rotate(360deg)
301
+ </style>
@@ -0,0 +1,259 @@
1
+ <template lang="pug">
2
+ .calendar-button(ref="button")
3
+ a(
4
+ href="javascript:;"
5
+ @click="onClickedToggle"
6
+ ref="toggle"
7
+ ).toggle-button
8
+ .date-range
9
+ SLIcon(icon="calendar")
10
+ span.divider
11
+ span.date-range {{ dateRange1 }}
12
+ span.range-days(v-if='dateRange1Days') {{ dateRange1Days }} 天
13
+ .compare-date-range(v-if="dateRange2 && showCompareSwitch")
14
+ span v.s.
15
+ span {{ dateRange2 }}
16
+ ClientOnly
17
+ Teleport(to="body")
18
+ SLCalendarPopup(
19
+ :data-source-type='dataSourceType'
20
+ :show-quicks="showQuicks"
21
+ :showCompareSwitch="showCompareSwitch"
22
+ :min-date="minDate"
23
+ :maxDate="maxDate"
24
+ :maxDays="maxDays"
25
+ :modelValue="modelValue"
26
+ @compare:change="onCompareChanged"
27
+ @update:modelValue="onInputed"
28
+ ref="popup"
29
+ )
30
+ </template>
31
+
32
+ <script lang="ts">
33
+ import { SLCalendarPopup } from "#components";
34
+ import type { PropType } from "vue";
35
+ import { fromEvent } from "rxjs";
36
+ import { differenceInCalendarDays, subDays } from "date-fns";
37
+ import { createPopper } from "@popperjs/core";
38
+ import type { Placement } from "@popperjs/core";
39
+ import DateRange from "~ui/models/DateRange";
40
+ import type IDateRange from "~ui/interface/IDateRange";
41
+ import { OnlineSourceType } from "~ui/interface/IWeb";
42
+
43
+ type SLCalendarPopupType = InstanceType<typeof SLCalendarPopup>;
44
+
45
+ export default defineComponent({
46
+ name: "SLCalendarButton",
47
+ components: {},
48
+ props: {
49
+ dataSourceType: {
50
+ type: Number as PropType<OnlineSourceType>,
51
+ default: OnlineSourceType.Mobile,
52
+ },
53
+ showQuicks: {
54
+ type: Boolean,
55
+ default: true,
56
+ },
57
+ showCompareSwitch: {
58
+ type: Boolean,
59
+ default: true,
60
+ },
61
+ minDate: {
62
+ type: Date,
63
+ default: () => null,
64
+ },
65
+ maxDate: {
66
+ type: Date,
67
+ default: () => subDays(Date.now(), 1),
68
+ },
69
+ maxDays: {
70
+ type: Number,
71
+ default: 365,
72
+ },
73
+ modelValue: {
74
+ type: Array as PropType<Array<IDateRange | null>>,
75
+ default: () => [
76
+ { start: new Date(2020, 8, 11), end: new Date(2020, 8, 17) },
77
+ ],
78
+ },
79
+ placement: {
80
+ type: String,
81
+ default: "bottom-start",
82
+ },
83
+ },
84
+ emits: ["update:modelValue"],
85
+ setup(props, { emit }) {
86
+ const { modelValue, placement } = toRefs(props);
87
+
88
+ const button = shallowRef<HTMLElement | null>(null);
89
+ const toggle = shallowRef<HTMLElement | null>(null);
90
+ const popup = shallowRef<SLCalendarPopupType | null>(null);
91
+
92
+ let popperInstance: any = null;
93
+ let clickSubscriber: any = null;
94
+
95
+ const dateRange1 = computed(() => {
96
+ const [dateRange1] = modelValue.value;
97
+ if (!dateRange1) {
98
+ return null;
99
+ }
100
+ return new DateRange(dateRange1.start, dateRange1.end);
101
+ });
102
+ const dateRange2 = computed(() => {
103
+ const [, dateRange2] = modelValue.value;
104
+ if (!dateRange2) {
105
+ return null;
106
+ }
107
+ return new DateRange(dateRange2.start, dateRange2.end);
108
+ });
109
+ const dateRange1Days = computed(() => {
110
+ if (!dateRange1.value || !dateRange1.value.start || !dateRange1.value.end)
111
+ return 0;
112
+
113
+ return (
114
+ differenceInCalendarDays(dateRange1.value.end, dateRange1.value.start) +
115
+ 1
116
+ );
117
+ });
118
+
119
+ function subscribeClick() {
120
+ clickSubscriber = fromEvent(window, "click").subscribe((e) => {
121
+ const { target } = e;
122
+ if (
123
+ button.value &&
124
+ !button.value.contains(target as Node) &&
125
+ popup.value &&
126
+ !popup.value.$el.contains(target as Node)
127
+ ) {
128
+ hide();
129
+ }
130
+ });
131
+ }
132
+
133
+ function unsubscribeClick() {
134
+ if (clickSubscriber) {
135
+ clickSubscriber.unsubscribe();
136
+ }
137
+ clickSubscriber = null;
138
+ }
139
+
140
+ function show() {
141
+ if (!popup.value) return;
142
+
143
+ subscribeClick();
144
+ popup.value.$el.setAttribute("data-show", "");
145
+
146
+ popperInstance.setOptions({
147
+ modifiers: [
148
+ {
149
+ name: "offset",
150
+ options: {
151
+ offset: [0, 8],
152
+ },
153
+ },
154
+ { name: "eventListeners", enabled: true },
155
+ ],
156
+ });
157
+
158
+ popperInstance.update();
159
+ }
160
+
161
+ function hide() {
162
+ if (!popup.value || popup.value.$el.getAttribute("data-show") === null)
163
+ return;
164
+ unsubscribeClick();
165
+ popup.value.$el.removeAttribute("data-show");
166
+ popperInstance.setOptions({
167
+ modifiers: [{ name: "eventListeners", enabled: false }],
168
+ });
169
+ nextTick(() => {
170
+ if (popup.value) {
171
+ popup.value.reset();
172
+ }
173
+ });
174
+ }
175
+
176
+ function onClickedToggle() {
177
+ if (!popup.value || popup.value.$el.getAttribute("data-show") !== null) {
178
+ hide();
179
+ return;
180
+ }
181
+ show();
182
+ }
183
+
184
+ function onInputed(value: Array<IDateRange>) {
185
+ emit("update:modelValue", value);
186
+ hide();
187
+ }
188
+
189
+ function onCompareChanged() {
190
+ popperInstance.update();
191
+ }
192
+
193
+ onMounted(() => {
194
+ nextTick(() => {
195
+ if (button.value && popup.value && popup.value.$el) {
196
+ popperInstance = createPopper(
197
+ button.value,
198
+ popup.value.$el as HTMLElement,
199
+ {
200
+ placement: placement.value as Placement,
201
+ modifiers: [{ name: "eventListeners", enabled: false }],
202
+ }
203
+ );
204
+ }
205
+ });
206
+ });
207
+
208
+ onBeforeUnmount(() => {
209
+ if (popperInstance) {
210
+ popperInstance.destroy();
211
+ }
212
+ popperInstance = null;
213
+ });
214
+
215
+ return {
216
+ button,
217
+ toggle,
218
+ popup,
219
+ dateRange1,
220
+ dateRange2,
221
+ dateRange1Days,
222
+ onClickedToggle,
223
+ onInputed,
224
+ onCompareChanged,
225
+ hide,
226
+ };
227
+ },
228
+ });
229
+ </script>
230
+
231
+ <style lang="stylus" scoped>
232
+ .calendar-button
233
+ @apply inline-block
234
+
235
+ .toggle-button
236
+ @apply inline-flex flex-col justify-center s('px-2.75') space-y-1 border s('border-white/20') rounded bg-white text-sm leading-normal text-gray-2
237
+ height 58px
238
+
239
+ .date-range
240
+ @apply flex items-center
241
+
242
+ .icon
243
+ @apply flex-grow-0 flex-shrink-0 text-base text-primary leading-none
244
+
245
+ .divider
246
+ @apply flex-grow-0 flex-shrink-0 block w-px s('h-4.75') ml-2 s('mr-1.75') bg-primary
247
+
248
+ .range-days
249
+ @apply block s('ml-0.5') px-1 s('py-0.5') bg-bg-middle rounded text-xs text-primary
250
+
251
+ .compare-date-range
252
+ @apply pl-1 space-x-2 text-sm text-gray-3
253
+
254
+ .calendar-popup
255
+ @apply z-60 absolute invisible pointer-events-none
256
+
257
+ &[data-show]
258
+ @apply visible pointer-events-auto
259
+ </style>