@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,362 @@
1
+ <template lang="pug">
2
+ .text-input(:class="textInputClass")
3
+ label(v-if="label || $slots.label" :for="uid")
4
+ slot(name='label') {{ label }}
5
+ span.required(v-if="required") *
6
+ .form-control(
7
+ :class="{ 'is-invalid': isInvalid !== null && isInvalid, 'is-valid': isInvalid !== null && !isInvalid }"
8
+ )
9
+ .input-group(
10
+ :class="{ 'is-focus': isFocus, 'is-fill': modelValue !== '' }"
11
+ )
12
+ .input-group-prepend(v-if="$slots.prepend")
13
+ slot(name="prepend")
14
+ .input(:class="inputClass")
15
+ input(
16
+ :name="name === '' ? uid : name"
17
+ :type="type"
18
+ :id="uid"
19
+ :value="modelValue"
20
+ :disabled="disabled"
21
+ :readonly="beReadonly"
22
+ :placeholder="placeholder"
23
+ :autocomplete="autocomplete"
24
+ @compositionstart="onInputCompositionStart"
25
+ @compositionend="onInputCompositionEnd"
26
+ @input="onInputedModelValue"
27
+ @focus="onFocused"
28
+ @blur="onBlured"
29
+ @paste="onPasted"
30
+ ref='input'
31
+ :data-cy="name === '' ? uid : name"
32
+ )
33
+ label(v-if="label || $slots.label" :for="uid").float-label
34
+ slot(name='label') {{ label }}
35
+ SLIcon(icon="exclamation-triangle")
36
+ .input-group-append(v-if="$slots.append")
37
+ slot(name="append")
38
+ .invalid-feedback
39
+ slot(name="invalid-feedback") {{ invalidFeedback }}
40
+ </template>
41
+
42
+ <script lang="ts">
43
+ import { debounce } from "lodash-es";
44
+ import { getUID } from "~ui/utils";
45
+
46
+ export default defineComponent({
47
+ name: "SLTextInput",
48
+ components: {},
49
+ props: {
50
+ type: {
51
+ type: String,
52
+ default: "text",
53
+ validator: (val: string) => ["", "text", "password"].includes(val),
54
+ },
55
+ name: {
56
+ type: String,
57
+ default: "",
58
+ },
59
+ size: {
60
+ type: String,
61
+ default: "",
62
+ validator: (val: string) => ["", "sm", "xs"].includes(val),
63
+ },
64
+ label: {
65
+ type: String,
66
+ default: undefined,
67
+ },
68
+ inline: {
69
+ type: Boolean,
70
+ default: false,
71
+ },
72
+ modelValue: {
73
+ type: String,
74
+ default: "",
75
+ },
76
+ placeholder: {
77
+ type: String,
78
+ default: "",
79
+ },
80
+ isInvalid: {
81
+ type: Boolean,
82
+ default: false,
83
+ },
84
+ invalidFeedback: {
85
+ type: String,
86
+ default: "",
87
+ },
88
+ variant: {
89
+ type: String,
90
+ default: undefined,
91
+ },
92
+ lazy: {
93
+ type: [Boolean, Number],
94
+ default: true,
95
+ },
96
+ disabled: {
97
+ type: Boolean,
98
+ default: false,
99
+ },
100
+ autocomplete: {
101
+ type: String,
102
+ default: "new-password",
103
+ },
104
+ beReadonly: {
105
+ type: Boolean,
106
+ default: false,
107
+ },
108
+ required: {
109
+ type: Boolean,
110
+ default: false,
111
+ },
112
+ },
113
+ emits: [
114
+ "update:modelValue",
115
+ "lazyUpdate:modelValue",
116
+ "focus",
117
+ "blur",
118
+ "paste",
119
+ ],
120
+ setup(props, { emit }) {
121
+ const { modelValue, size, lazy, inline, variant, disabled, beReadonly } =
122
+ toRefs(props);
123
+
124
+ const input = shallowRef<HTMLInputElement | null>(null);
125
+ const uid = ref<string | undefined>(undefined);
126
+ const isFocus = ref(false);
127
+ const isComposing = ref(false);
128
+
129
+ const textInputClass = computed(() => {
130
+ const textInputClass: string[] = [];
131
+
132
+ if (inline.value) textInputClass.push("inline");
133
+ if (variant.value === "float") textInputClass.push("is-float");
134
+ if (disabled.value) textInputClass.push("disabled");
135
+ if (beReadonly.value) textInputClass.push("readonly");
136
+
137
+ return textInputClass;
138
+ });
139
+ const inputClass = computed(() => {
140
+ if (size.value === "") {
141
+ return "";
142
+ }
143
+
144
+ return `input-${size.value}`;
145
+ });
146
+
147
+ const debounceUpdateModelValue = debounce(
148
+ lazyUpdateModelValue,
149
+ Number.isInteger(lazy.value) ? (lazy.value as number) : 500
150
+ );
151
+
152
+ function onFocused() {
153
+ isFocus.value = true;
154
+ emit("focus");
155
+ }
156
+
157
+ function onBlured() {
158
+ isFocus.value = false;
159
+ emit("blur");
160
+ }
161
+
162
+ function onPasted(e: ClipboardEvent) {
163
+ emit("paste", e);
164
+ }
165
+
166
+ function lazyUpdateModelValue(newValue: string) {
167
+ emit("lazyUpdate:modelValue", newValue);
168
+ }
169
+
170
+ function onInputCompositionStart() {
171
+ isComposing.value = true;
172
+ }
173
+
174
+ function onInputCompositionEnd(e: CompositionEvent) {
175
+ const target = e.target as HTMLInputElement;
176
+ if (target) {
177
+ if (Number.isInteger(lazy.value) || lazy.value) {
178
+ debounceUpdateModelValue(target.value);
179
+ }
180
+
181
+ emit("update:modelValue", target.value);
182
+ }
183
+ }
184
+
185
+ function onInputedModelValue(e: Event) {
186
+ const inputEvent = e as InputEvent;
187
+ if (isComposing.value && !inputEvent.isComposing) {
188
+ isComposing.value = false;
189
+ return;
190
+ }
191
+
192
+ const target = inputEvent.target as HTMLInputElement;
193
+
194
+ if (target) {
195
+ if (Number.isInteger(lazy.value) || lazy.value) {
196
+ debounceUpdateModelValue(target?.value || "");
197
+ }
198
+
199
+ emit("update:modelValue", target?.value || "");
200
+ }
201
+ }
202
+
203
+ function focus() {
204
+ if (!input.value) return;
205
+ input.value.focus();
206
+ }
207
+
208
+ onMounted(() => {
209
+ uid.value = getUID();
210
+ });
211
+
212
+ return {
213
+ input,
214
+ uid,
215
+ isFocus,
216
+ textInputClass,
217
+ inputClass,
218
+ onFocused,
219
+ onBlured,
220
+ onPasted,
221
+ onInputCompositionStart,
222
+ onInputCompositionEnd,
223
+ onInputedModelValue,
224
+ focus,
225
+ };
226
+ },
227
+ });
228
+ </script>
229
+
230
+ <style lang="stylus">
231
+ .text-input
232
+ &.inline
233
+ @apply flex
234
+
235
+ & > label
236
+ @apply flex-grow-0 flex-shrink-0 mb-0 mr-2 py-2 border-t border-b border-transparent
237
+
238
+ .form-control
239
+ @apply flex-grow
240
+
241
+ &.is-float
242
+ & > label
243
+ @apply hidden
244
+
245
+ .input-group
246
+ &.is-fill
247
+ .input
248
+ @apply bg-white border-primary-lighter
249
+
250
+ &.is-focus
251
+ .input
252
+ @apply bg-white border-primary
253
+
254
+ .input
255
+ @apply relative bg-bg-middle border-bg-middle
256
+
257
+ .float-label
258
+ @apply inline-block
259
+
260
+ .is-invalid
261
+ .input-group
262
+ .input, .input.is-focus
263
+ @apply border-danger-hover
264
+
265
+ &.is-fixed-float
266
+ & > label
267
+ @apply hidden
268
+
269
+ .input-group
270
+ .input
271
+ @apply relative bg-white border-primary
272
+
273
+ .float-label
274
+ @apply inline-block s('ml-1.5') s('-mt-2.25') py-0 s('px-0.5') bg-white text-primary text-xs transition-input-focus
275
+
276
+ .is-invalid
277
+ .input-group
278
+ .input, .input.is-focus
279
+ @apply border-danger-hover
280
+
281
+ &.disabled, &.readonly
282
+ .input-group
283
+ &.is-focus
284
+ .input
285
+ @apply border-primary-light
286
+
287
+ .input
288
+ @apply border-primary-light bg-bg
289
+
290
+ & > label
291
+ @apply mb-2 text-base leading-normal text-gray-2
292
+
293
+ .required
294
+ @apply text-danger
295
+
296
+ .is-invalid
297
+ .input-group, .input-group.is-focus
298
+ .input
299
+ @apply border-danger-hover
300
+
301
+ &.input-sm, &.input-xs
302
+ .icon
303
+ @apply hidden
304
+
305
+ .icon
306
+ @apply inline-block
307
+
308
+ .invalid-feedback
309
+ @apply block
310
+
311
+
312
+ .input-group
313
+ @apply flex flex-nowrap text-base leading-normal
314
+
315
+ &.is-focus
316
+ .input
317
+ @apply border-primary
318
+
319
+ &.is-fill, &.is-focus
320
+ .input
321
+ .float-label
322
+ @apply s('ml-1.5') s('-mt-2.25') py-0 s('px-0.5') bg-white text-primary text-xs transition-input-focus
323
+
324
+ &-prepend
325
+ @apply flex-grow-0 flex-shrink-0
326
+
327
+ .input
328
+ @apply flex-grow flex items-center s('p-1.75') bg-white rounded border border-primary-light
329
+
330
+ &.input-sm
331
+ @apply s('py-0.75')
332
+
333
+ input
334
+ @apply text-base
335
+
336
+ &.input-xs
337
+ @apply py-px s('px-0.75')
338
+
339
+ input
340
+ @apply text-base
341
+
342
+ &:not(:first-child)
343
+ @apply rounded-l-none border-l-0
344
+
345
+ &:not(:last-child)
346
+ @apply rounded-r-none border-r-0
347
+
348
+ input
349
+ @apply flex-grow w-full bg-transparent text-gray-2 placeholder-gray-4 s('focus:outline-none')
350
+
351
+ .icon
352
+ @apply flex-grow-0 flex-shrink-0 hidden text-danger-hover
353
+
354
+ .float-label
355
+ @apply hidden absolute top-0 left-0 s('p-1.75') border-t border-b border-transparent text-gray-3 cursor-text
356
+
357
+ &-append
358
+ @apply flex-grow-0 flex-shrink-0
359
+
360
+ .invalid-feedback
361
+ @apply hidden text-danger text-xs
362
+ </style>
@@ -0,0 +1,134 @@
1
+ <template lang="pug">
2
+ .textarea(:class="{ inline, disabled: disabled }")
3
+ label(v-if="label" :for="uid")
4
+ span {{ label }}
5
+ .form-control-notice(v-if='notice || $slots.notice')
6
+ slot(name='notice' v-if='$slots.notice')
7
+ template(v-else) ({{ notice }})
8
+ .form-control(
9
+ :class="{ 'is-invalid': isInvalid !== null && isInvalid, 'is-valid': isInvalid !== null && !isInvalid }"
10
+ )
11
+ textarea(
12
+ :id="uid"
13
+ :rows="rows"
14
+ v-model="modelProxy"
15
+ :placeholder="placeholder"
16
+ :disabled="disabled"
17
+ @input="onInputed"
18
+ )
19
+ .invalid-feedback
20
+ slot(name="invalid-feedback") {{ invalidFeedback }}
21
+ </template>
22
+
23
+ <script lang="ts">
24
+ import { getUID } from "~ui/utils";
25
+
26
+ export default defineComponent({
27
+ name: "SLTextArea",
28
+ props: {
29
+ label: {
30
+ type: String,
31
+ default: null,
32
+ },
33
+ inline: {
34
+ type: Boolean,
35
+ default: false,
36
+ },
37
+ modelValue: {
38
+ type: String,
39
+ default: "",
40
+ },
41
+ placeholder: {
42
+ type: String,
43
+ default: "",
44
+ },
45
+ isInvalid: {
46
+ type: Boolean,
47
+ default: false,
48
+ },
49
+ invalidFeedback: {
50
+ type: String,
51
+ default: "",
52
+ },
53
+ rows: {
54
+ type: Number,
55
+ default: 6,
56
+ },
57
+ disabled: {
58
+ type: Boolean,
59
+ default: false,
60
+ },
61
+ notice: {
62
+ type: String,
63
+ default: null,
64
+ },
65
+ },
66
+ emits: ["update:modelValue"],
67
+ setup(props, { emit }) {
68
+ const { modelValue } = toRefs(props);
69
+
70
+ const uid = ref<string | undefined>(undefined);
71
+ const modelProxy = ref(modelValue.value);
72
+
73
+ function onInputed(e: Event) {
74
+ const { target } = e;
75
+ emit("update:modelValue", (target as HTMLInputElement).value);
76
+ }
77
+
78
+ watch(modelValue, () => {
79
+ modelProxy.value = modelValue.value;
80
+ });
81
+
82
+ onMounted(() => {
83
+ uid.value = getUID();
84
+ });
85
+
86
+ return {
87
+ uid,
88
+ modelProxy,
89
+ onInputed,
90
+ };
91
+ },
92
+ });
93
+ </script>
94
+
95
+ <style lang="stylus">
96
+ .textarea
97
+ &.inline
98
+ @apply flex
99
+
100
+ label
101
+ @apply flex-grow-0 flex-shrink-0 mb-0 mr-2 py-2 border-t border-b border-transparent
102
+
103
+ .form-control
104
+ @apply flex-grow
105
+
106
+ &.disabled
107
+ textarea
108
+ @apply border-primary-light bg-bg
109
+
110
+ label
111
+ @apply mb-2 text-base leading-normal text-gray-2
112
+
113
+ .is-invalid
114
+ textarea
115
+ @apply border-danger-hover
116
+
117
+ .invalid-feedback
118
+ @apply block
119
+
120
+ .form-control
121
+ @apply relative
122
+
123
+ textarea
124
+ @apply block w-full p-2 border border-primary-light rounded bg-white text-base text-gray-2 resize-none s('focus:border-primary') s('focus:outline-none')
125
+
126
+ textarea:focus + .textarea-placeholder
127
+ @apply invisible
128
+
129
+ .form-control-notice
130
+ @apply inline-block ml-1 text-gray-3 text-xs
131
+
132
+ .invalid-feedback
133
+ @apply hidden text-danger text-xs
134
+ </style>
@@ -0,0 +1,71 @@
1
+ <template lang="pug">
2
+ Transition(name='toast-fade')
3
+ .toast(v-if='show')
4
+ .toast-wrapper {{ message }}
5
+ </template>
6
+
7
+ <script lang="ts">
8
+ export default defineComponent({
9
+ name: "SLToast",
10
+ props: {
11
+ show: {
12
+ type: Boolean,
13
+ default: false,
14
+ },
15
+ message: {
16
+ type: String,
17
+ required: true,
18
+ },
19
+ },
20
+ emits: ["update:show"],
21
+ setup(props, { emit }) {
22
+ const { show } = toRefs(props);
23
+
24
+ let showTimeoutId: any = null;
25
+
26
+ function clearShowTimeout() {
27
+ if (showTimeoutId) {
28
+ clearTimeout(showTimeoutId);
29
+ }
30
+ showTimeoutId = null;
31
+ }
32
+
33
+ function setupHideTimeout() {
34
+ clearShowTimeout();
35
+
36
+ showTimeoutId = setTimeout(() => {
37
+ emit("update:show", false);
38
+ }, 1300);
39
+ }
40
+
41
+ watch(show, () => {
42
+ if (show.value) {
43
+ setupHideTimeout();
44
+ }
45
+ });
46
+
47
+ onBeforeUnmount(() => {
48
+ clearShowTimeout();
49
+ });
50
+
51
+ return {};
52
+ },
53
+ });
54
+ </script>
55
+
56
+ <style lang="stylus" scoped>
57
+ .toast
58
+ @apply fixed top-0 left-0 w-full h-full pointer-events-none
59
+
60
+ &-wrapper
61
+ @apply absolute s('top-1/2') s('left-1/2') py-4 px-6 s('bg-backdrop/80') rounded text-base text-white s('-translate-x-1/2') s('-translate-y-1/2')
62
+
63
+ .toast-fade-enter-active
64
+ @apply transition-opacity duration-300 ease-linear
65
+
66
+ .toast-fade-leave-active
67
+ @apply transition-opacity duration-200 ease-linear
68
+
69
+ .toast-fade-enter-from, .toast-fade-leave-to
70
+ @apply opacity-0
71
+ </style>
@@ -0,0 +1,78 @@
1
+ <template lang="pug">
2
+ a.sl-toggle-button(
3
+ href="javascript:;"
4
+ :class="[{ active: isActive, disabled: isDisabled }, sizeClass]"
5
+ data-skip-download
6
+ @click.prevent="onClicked"
7
+ )
8
+ SLIcon(:icon="icon")
9
+ span(v-if="title !== ''") {{ title }}
10
+ </template>
11
+
12
+ <script lang="ts">
13
+ export default defineComponent({
14
+ name: "SLToggleButton",
15
+ components: {},
16
+ props: {
17
+ icon: {
18
+ type: String,
19
+ default: "chart_with_num",
20
+ },
21
+ title: {
22
+ type: String,
23
+ default: "",
24
+ },
25
+ isActive: {
26
+ type: Boolean,
27
+ default: true,
28
+ },
29
+ isDisabled: {
30
+ type: Boolean,
31
+ default: false,
32
+ },
33
+ size: {
34
+ type: String,
35
+ default: "",
36
+ validator: (val: string) => ["", "sm"].includes(val),
37
+ },
38
+ },
39
+ emits: ["click"],
40
+ setup(props, { emit }) {
41
+ const { isDisabled, size } = toRefs(props);
42
+
43
+ const sizeClass = computed(() => {
44
+ if (size.value === "") return "";
45
+
46
+ return `sl-toggle-button-${size.value}`;
47
+ });
48
+
49
+ function onClicked(e: MouseEvent) {
50
+ if (isDisabled.value) return;
51
+
52
+ emit("click", e);
53
+ }
54
+
55
+ return {
56
+ sizeClass,
57
+ onClicked,
58
+ };
59
+ },
60
+ });
61
+ </script>
62
+
63
+ <style lang="stylus">
64
+ .sl-toggle-button
65
+ @apply inline-flex items-center justify-center s('p-1.5') space-x-2 bg-bg rounded text-base text-primary-hover
66
+
67
+ &.sl-toggle-button-sm
68
+ @apply s('h-[29px]') px-1 py-0 text-sm
69
+
70
+ .icon
71
+ @apply text-lg leading-none
72
+
73
+ &.active
74
+ @apply bg-primary-hover text-white
75
+
76
+ &.disabled
77
+ @apply bg-cancel text-white cursor-default
78
+ </style>