@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,189 @@
1
+ <template lang="pug">
2
+ .sort-by-dropdown(
3
+ :class='{ single: options.length === 1 }',
4
+ ref='el',
5
+ )
6
+ a(href='javascript:;', ref='toggleEl', @click='onToggle').sort-by-dropdown-toggle
7
+ span {{ selectedOption ? selectedOption.label : '' }}
8
+ SLIcon(icon='caret-down')
9
+ .sort-by-dropdown-menu(ref='menuEl')
10
+ a.sort-by-dropdown-item(
11
+ v-for='option in options',
12
+ href='javascript:;',
13
+ :class='{ active: option.value === modelValue }'
14
+ :key='option.value',
15
+ @click='onClickedItem(option.value)'
16
+ ) {{ option.label }}
17
+ </template>
18
+
19
+ <script lang="ts">
20
+ import type { PropType } from "vue";
21
+ import { createPopper } from "@popperjs/core";
22
+ import type { Instance as PopperInstance } from "@popperjs/core";
23
+ import { fromEvent, Subscription } from "rxjs";
24
+ import type IInputOption from "~ui/interface/IInputOption";
25
+
26
+ export default defineComponent({
27
+ name: "SLSortByDropdown",
28
+ components: {},
29
+ props: {
30
+ modelValue: {
31
+ type: [String, Number] as PropType<string | number>,
32
+ required: true,
33
+ },
34
+ options: {
35
+ type: Array as PropType<IInputOption[]>,
36
+ required: true,
37
+ },
38
+ },
39
+ emits: ["update:modelValue"],
40
+ setup(props, { emit }) {
41
+ const { modelValue, options } = toRefs(props);
42
+
43
+ const el = shallowRef<HTMLDivElement | null>(null);
44
+ const toggleEl = shallowRef<HTMLLinkElement | null>(null);
45
+ const menuEl = shallowRef<HTMLDivElement | null>(null);
46
+ const isShowMenu = ref(false);
47
+
48
+ let popperInstance: PopperInstance | null = null;
49
+ let clickSubscriber: Subscription | null = null;
50
+
51
+ const selectedOption = computed(() =>
52
+ (options.value || []).find((o) => o.value === modelValue.value)
53
+ );
54
+
55
+ function onToggle() {
56
+ isShowMenu.value = !isShowMenu.value;
57
+ }
58
+
59
+ function createPopperInstance() {
60
+ destroyPopper();
61
+
62
+ nextTick(() => {
63
+ if (toggleEl.value && menuEl.value && options.value.length > 1) {
64
+ popperInstance = createPopper(toggleEl.value, menuEl.value, {
65
+ modifiers: [
66
+ {
67
+ name: "offset",
68
+ options: {
69
+ offset: [0, 4],
70
+ },
71
+ },
72
+ { name: "eventListeners", enabled: false },
73
+ ],
74
+ });
75
+ }
76
+ });
77
+ }
78
+
79
+ function destroyPopper() {
80
+ if (popperInstance) {
81
+ popperInstance.destroy();
82
+ }
83
+ popperInstance = null;
84
+ }
85
+
86
+ function destorySubscriber() {
87
+ if (clickSubscriber) {
88
+ clickSubscriber.unsubscribe();
89
+ }
90
+ clickSubscriber = null;
91
+ }
92
+
93
+ function show() {
94
+ if (!menuEl.value || !popperInstance || options.value.length < 2) return;
95
+
96
+ menuEl.value.setAttribute("data-show", "");
97
+ popperInstance.setOptions((options) => ({
98
+ ...options,
99
+ modifiers: [
100
+ ...(options.modifiers || []),
101
+ { name: "eventListeners", enabled: true },
102
+ ],
103
+ }));
104
+ popperInstance.update();
105
+
106
+ destorySubscriber();
107
+ clickSubscriber = fromEvent(window, "click").subscribe((e: Event) => {
108
+ if (el.value && el.value.contains(e.target as Node)) {
109
+ return;
110
+ }
111
+
112
+ isShowMenu.value = false;
113
+ });
114
+ }
115
+
116
+ function hide() {
117
+ if (!menuEl.value || !popperInstance) return;
118
+
119
+ menuEl.value.removeAttribute("data-show");
120
+ popperInstance.setOptions((options) => ({
121
+ ...options,
122
+ modifiers: [
123
+ ...(options.modifiers || []),
124
+ { name: "eventListeners", enabled: false },
125
+ ],
126
+ }));
127
+
128
+ destorySubscriber();
129
+ }
130
+
131
+ function onClickedItem(optionValue: string | number) {
132
+ emit("update:modelValue", optionValue);
133
+ isShowMenu.value = false;
134
+ }
135
+
136
+ watch(isShowMenu, () => {
137
+ if (isShowMenu.value) {
138
+ show();
139
+ } else {
140
+ hide();
141
+ }
142
+ });
143
+
144
+ onMounted(() => {
145
+ createPopperInstance();
146
+ });
147
+
148
+ onBeforeUnmount(() => {
149
+ destroyPopper();
150
+ });
151
+
152
+ return {
153
+ el,
154
+ toggleEl,
155
+ menuEl,
156
+ selectedOption,
157
+ onToggle,
158
+ onClickedItem,
159
+ };
160
+ },
161
+ });
162
+ </script>
163
+
164
+ <style lang="stylus" scoped>
165
+ .sort-by-dropdown
166
+ @apply inline-flex
167
+
168
+ &.single
169
+ .sort-by-dropdown-toggle
170
+ @apply bg-white cursor-default
171
+ .icon
172
+ @apply hidden
173
+
174
+ &-toggle
175
+ @apply inline-flex items-center px-1 s('py-0.5') space-x-2 bg-bg-middle rounded text-sm text-primary
176
+ .icon
177
+ @apply text-xs
178
+
179
+ &-menu
180
+ @apply s('z-[2]') flex-col s('min-w-[84px]') bg-white border border-primary-light rounded overflow-hidden hidden
181
+
182
+ &[data-show]
183
+ @apply inline-flex
184
+
185
+ .sort-by-dropdown-item
186
+ @apply inline-flex p-2 bg-white text-sm text-gray-3
187
+ &.active
188
+ @apply bg-bg text-primary
189
+ </style>
@@ -0,0 +1,24 @@
1
+ <template lang="pug">
2
+ SLIcon(:icon='icon').spin-icon
3
+ </template>
4
+
5
+ <script lang="ts">
6
+ export default defineComponent({
7
+ name: "SLSpinIcon",
8
+ components: {},
9
+ props: {
10
+ icon: {
11
+ type: String,
12
+ default: "",
13
+ },
14
+ },
15
+ setup() {
16
+ return {};
17
+ },
18
+ });
19
+ </script>
20
+
21
+ <style lang="stylus">
22
+ i.spin-icon
23
+ @apply animate-spin
24
+ </style>
@@ -0,0 +1,306 @@
1
+ <template lang="pug">
2
+ .stay-range-input(
3
+ :class="{ inline, disabled, readonly: beReadonly }"
4
+ )
5
+ label(v-if="label") {{ label }}
6
+ .form-control(
7
+ :class="{ 'is-invalid': isInvalid !== null && isInvalid, 'is-valid': isInvalid !== null && !isInvalid }"
8
+ ref="toggle"
9
+ )
10
+ .form-control-container
11
+ .input-group
12
+ input(
13
+ type='text'
14
+ :value='stayStart'
15
+ placeholder='1'
16
+ maxlength='3'
17
+ :disabled='disabled'
18
+ @input='onInputedStayStart'
19
+ )
20
+ SLSelect(
21
+ :modelValue='stayStartLevel'
22
+ :options='stayLevelOptions'
23
+ placeholder=''
24
+ :disabled='disabled'
25
+ :beReadonly='beReadonly'
26
+ :isInvalid='isInvalid'
27
+ ref='startSelectComp'
28
+ @update:modelValue='onInputedStayStartLevel'
29
+ )
30
+ .input-group-splitter
31
+ .input-group
32
+ input(
33
+ type='text'
34
+ :value='stayEnd'
35
+ placeholder='24'
36
+ maxlength='3'
37
+ :disabled='disabled'
38
+ @input='onInputedStayEnd'
39
+ )
40
+ SLSelect(
41
+ :modelValue='stayEndLevel'
42
+ :options='stayLevelOptions'
43
+ placeholder=''
44
+ :disabled='disabled'
45
+ :beReadonly='beReadonly'
46
+ :isInvalid='isInvalid'
47
+ ref='endSelectComp'
48
+ @update:modelValue='onInputedStayEndLevel'
49
+ )
50
+ .invalid-feedback
51
+ slot(name="invalid-feedback") {{ invalidFeedback }}
52
+ </template>
53
+
54
+ <script lang="ts">
55
+ import type { PropType } from "vue";
56
+ import { SLSelect } from "#components";
57
+ import type IStayRange from "~ui/interface/IStayRange";
58
+ import { StayRangeLevel } from "~ui/interface/IStayRange";
59
+
60
+ type SLSelectType = InstanceType<typeof SLSelect>;
61
+
62
+ export default defineComponent({
63
+ name: "SLStayRangeInput",
64
+ components: {},
65
+ props: {
66
+ label: {
67
+ type: String,
68
+ default: undefined,
69
+ },
70
+ inline: {
71
+ type: Boolean,
72
+ default: false,
73
+ },
74
+ modelValue: {
75
+ type: Object as PropType<IStayRange | null>,
76
+ default: null,
77
+ },
78
+ step: {
79
+ type: Number,
80
+ default: 1,
81
+ },
82
+ isInvalid: {
83
+ type: Boolean,
84
+ default: false,
85
+ },
86
+ invalidFeedback: {
87
+ type: String,
88
+ default: "",
89
+ },
90
+ disabled: {
91
+ type: Boolean,
92
+ default: false,
93
+ },
94
+ beReadonly: {
95
+ type: Boolean,
96
+ default: false,
97
+ },
98
+ },
99
+ emits: ["update:modelValue"],
100
+ setup(props, { emit }) {
101
+ const { modelValue } = toRefs(props);
102
+
103
+ const toggle = shallowRef<HTMLElement | null>(null);
104
+ const startSelectComp = shallowRef<SLSelectType | null>(null);
105
+ const endSelectComp = shallowRef<SLSelectType | null>(null);
106
+
107
+ const stayLevelOptions = computed(() => [
108
+ { label: "分鐘", value: "minutes" },
109
+ { label: "小時", value: "hours" },
110
+ ]);
111
+ const stayStart = computed(() => {
112
+ if (
113
+ !modelValue.value ||
114
+ !modelValue.value.start ||
115
+ modelValue.value.start.value === undefined ||
116
+ modelValue.value.start.value === null
117
+ ) {
118
+ return "";
119
+ }
120
+
121
+ return modelValue.value.start.value;
122
+ });
123
+ const stayEnd = computed(() => {
124
+ if (
125
+ !modelValue.value ||
126
+ !modelValue.value.end ||
127
+ modelValue.value.end.value === undefined ||
128
+ modelValue.value.end.value === null
129
+ ) {
130
+ return "";
131
+ }
132
+
133
+ return modelValue.value.end.value;
134
+ });
135
+ const stayStartLevel = computed(() => {
136
+ return modelValue.value?.start?.level || "minutes";
137
+ });
138
+ const stayEndLevel = computed(() => {
139
+ return modelValue.value?.end?.level || "hours";
140
+ });
141
+
142
+ function onInputedStayStart(e: Event) {
143
+ const target = e.target as HTMLInputElement;
144
+ let start = target.value === "" ? null : Number(target.value);
145
+
146
+ if (
147
+ start === null ||
148
+ Number.isNaN(start) ||
149
+ start < 1 ||
150
+ (stayStartLevel.value === "hours" && start > 24)
151
+ ) {
152
+ start = null;
153
+ }
154
+
155
+ emit("update:modelValue", {
156
+ start: {
157
+ value: start,
158
+ level: stayStartLevel.value,
159
+ },
160
+ end: {
161
+ value: modelValue.value?.end?.value || null,
162
+ level: stayEndLevel.value,
163
+ },
164
+ });
165
+ }
166
+
167
+ function onInputedStayEnd(e: Event) {
168
+ const target = e.target as HTMLInputElement;
169
+ let end = target.value === "" ? null : Number(target.value);
170
+
171
+ if (
172
+ end === null ||
173
+ Number.isNaN(end) ||
174
+ (stayEndLevel.value === "hours" && end > 24)
175
+ ) {
176
+ end = null;
177
+ }
178
+
179
+ emit("update:modelValue", {
180
+ start: {
181
+ value: modelValue.value?.start?.value || null,
182
+ level: stayStartLevel.value,
183
+ },
184
+ end: {
185
+ value: end,
186
+ level: stayEndLevel.value,
187
+ },
188
+ });
189
+ }
190
+
191
+ function onInputedStayStartLevel(newLevel: StayRangeLevel) {
192
+ let start = modelValue.value?.start?.value || null;
193
+
194
+ if (newLevel === "hours" && start !== null && start > 24) {
195
+ start = null;
196
+ }
197
+
198
+ emit("update:modelValue", {
199
+ start: {
200
+ value: start,
201
+ level: newLevel,
202
+ },
203
+ end: {
204
+ value: modelValue.value?.end?.value || null,
205
+ level: stayEndLevel.value,
206
+ },
207
+ });
208
+ }
209
+
210
+ function onInputedStayEndLevel(newLevel: StayRangeLevel) {
211
+ let end = modelValue.value?.end?.value || null;
212
+
213
+ if (newLevel === "hours" && end !== null && end > 24) {
214
+ end = null;
215
+ }
216
+
217
+ emit("update:modelValue", {
218
+ start: {
219
+ value: modelValue.value?.start?.value || null,
220
+ level: stayStartLevel.value,
221
+ },
222
+ end: {
223
+ value: end,
224
+ level: newLevel,
225
+ },
226
+ });
227
+ }
228
+
229
+ function hide() {
230
+ if (startSelectComp.value) {
231
+ startSelectComp.value.hide();
232
+ }
233
+
234
+ if (endSelectComp.value) {
235
+ endSelectComp.value.hide();
236
+ }
237
+ }
238
+
239
+ return {
240
+ toggle,
241
+ startSelectComp,
242
+ endSelectComp,
243
+ stayLevelOptions,
244
+ stayStart,
245
+ stayEnd,
246
+ stayStartLevel,
247
+ stayEndLevel,
248
+ onInputedStayStart,
249
+ onInputedStayEnd,
250
+ onInputedStayStartLevel,
251
+ onInputedStayEndLevel,
252
+ hide,
253
+ };
254
+ },
255
+ });
256
+ </script>
257
+
258
+ <style lang="stylus">
259
+ .stay-range-input
260
+ @apply flex flex-col
261
+
262
+ &.inline
263
+ @apply flex flex-row
264
+
265
+ & > label
266
+ @apply flex-grow-0 flex-shrink-0 mb-0 mr-2 py-2 border-t border-b border-transparent
267
+
268
+ .form-control
269
+ @apply flex-grow
270
+
271
+ &.disabled, &.readonly
272
+ .input-group
273
+ input[type=text]
274
+ @apply border-primary-light bg-bg
275
+
276
+
277
+ & > label
278
+ @apply mb-2 text-base leading-normal text-gray-2
279
+
280
+ .is-invalid
281
+ .input-group
282
+ input[type=text]
283
+ @apply border-danger
284
+
285
+ .invalid-feedback
286
+ @apply block
287
+
288
+
289
+ .form-control-container
290
+ @apply flex items-center space-x-2
291
+
292
+ .input-group
293
+ @apply flex-grow flex flex-nowrap space-x-2
294
+
295
+ input[type=text]
296
+ @apply flex-grow-0 flex-shrink-0 w-11 border border-primary-light rounded text-base text-center text-gray-2 outline-none
297
+
298
+ .custom-select
299
+ @apply w-full
300
+
301
+ .input-group-splitter
302
+ @apply flex-grow-0 flex-shrink-0 w-3 h-px bg-primary
303
+
304
+ .invalid-feedback
305
+ @apply hidden text-danger text-xs
306
+ </style>
@@ -0,0 +1,159 @@
1
+ <template lang="pug">
2
+ li(
3
+ v-if="distributed && distributed.header"
4
+ :class="tabNavItemClass"
5
+ @click="navClick"
6
+ ref='tabPaneEl'
7
+ )
8
+ a(
9
+ href="javascript:;"
10
+ ).tab-nav-item-link
11
+ .tab-nav-item-link-title
12
+ .inline-flex.items-center.justify-center.w-full.space-x-1
13
+ slot(name="title")
14
+ SLIcon(v-if="icon", :icon="icon")
15
+ span {{ title }}
16
+ div(
17
+ v-else
18
+ :class="{ active: isActive }"
19
+ ref='tabPaneEl'
20
+ )
21
+ .tab-pane(
22
+ v-if="isActive"
23
+ :class="{ active: isActive }"
24
+ )
25
+ slot
26
+ </template>
27
+
28
+ <script lang="ts">
29
+ import type { Ref } from "vue";
30
+
31
+ export default defineComponent({
32
+ name: "SLTab",
33
+ components: {},
34
+ props: {
35
+ icon: {
36
+ type: String,
37
+ default: "",
38
+ },
39
+ title: {
40
+ type: String,
41
+ default: "",
42
+ },
43
+ order: {
44
+ type: Number,
45
+ require: true,
46
+ default: -1,
47
+ },
48
+ activeTabBorderColor: {
49
+ type: String,
50
+ default: "",
51
+ validator: (val: string) =>
52
+ [
53
+ "",
54
+ "insight-web-1",
55
+ "insight-poi-1",
56
+ "insight-1",
57
+ "insight-2",
58
+ "insight-3",
59
+ ].includes(val),
60
+ },
61
+ single: {
62
+ type: Boolean,
63
+ default: false,
64
+ },
65
+ },
66
+ setup(props) {
67
+ const { order, activeTabBorderColor, single } = toRefs(props);
68
+
69
+ const distributed = inject<{
70
+ header: boolean;
71
+ changeTabTo: (newTab: number) => void;
72
+ }>("distributed");
73
+ const activeTab = inject<Ref<number>>("activeTab");
74
+ const initialTab = inject<Ref<number>>("initialTab");
75
+ const self = getCurrentInstance();
76
+ const parent = self?.parent?.parent;
77
+
78
+ const tabPaneEl = shallowRef<HTMLElement | null>(null);
79
+ const index = ref<number | null>(null);
80
+
81
+ const isActive = computed(() => {
82
+ return activeTab && activeTab.value === index.value;
83
+ });
84
+ const tabNavItemClass = computed(() => {
85
+ const classes = ["tab-nav-item"];
86
+
87
+ if (isActive.value) {
88
+ classes.push("active");
89
+ }
90
+
91
+ if (activeTabBorderColor.value !== "") {
92
+ classes.push(`tab-nav-item-${activeTabBorderColor.value}`);
93
+ }
94
+
95
+ if (single.value) {
96
+ classes.push("single");
97
+ }
98
+
99
+ return classes.join(" ");
100
+ });
101
+
102
+ function navClick() {
103
+ if (!isActive.value && distributed && distributed.changeTabTo) {
104
+ distributed.changeTabTo(index.value || 0);
105
+ }
106
+ }
107
+
108
+ function setupIndex() {
109
+ if (!distributed) return;
110
+
111
+ if (order.value < 0) {
112
+ const contentBody = (
113
+ distributed.header
114
+ ? parent?.refs?.tabsNavLeftEl
115
+ : parent?.refs?.tabsContentBody
116
+ ) as HTMLElement;
117
+ if (!contentBody) return;
118
+
119
+ const tabsElement = distributed.header
120
+ ? contentBody.querySelectorAll(".tab-nav-item")
121
+ : contentBody.children;
122
+ index.value = tabPaneEl.value
123
+ ? Array.from(tabsElement).indexOf(tabPaneEl.value)
124
+ : null;
125
+ } else {
126
+ index.value = order.value;
127
+ }
128
+ }
129
+
130
+ watch(order, () => {
131
+ setupIndex();
132
+ });
133
+
134
+ onMounted(() => {
135
+ setupIndex();
136
+
137
+ if (
138
+ isActive.value &&
139
+ distributed &&
140
+ distributed.header &&
141
+ (!initialTab || !initialTab.value)
142
+ ) {
143
+ distributed.changeTabTo(index.value || 0);
144
+ }
145
+ });
146
+
147
+ return {
148
+ distributed,
149
+ activeTab,
150
+ tabPaneEl,
151
+ isActive,
152
+ tabNavItemClass,
153
+ navClick,
154
+ };
155
+ },
156
+ });
157
+ </script>
158
+
159
+ <style lang="stylus"></style>