@atooyu/uxto-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 (141) hide show
  1. package/README.md +259 -0
  2. package/dist/index.js +5055 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.mjs +5055 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/dist/style.css +2528 -0
  7. package/package.json +93 -0
  8. package/src/components/index.ts +51 -0
  9. package/src/components/u-avatar/u-avatar.vue +205 -0
  10. package/src/components/u-badge/u-badge.vue +145 -0
  11. package/src/components/u-button/u-button.vue +239 -0
  12. package/src/components/u-cell/u-cell.vue +179 -0
  13. package/src/components/u-cell-group/u-cell-group.vue +46 -0
  14. package/src/components/u-checkbox/u-checkbox.vue +174 -0
  15. package/src/components/u-checkbox-group/u-checkbox-group.vue +72 -0
  16. package/src/components/u-code-input/u-code-input.vue +248 -0
  17. package/src/components/u-count-down/u-count-down.vue +182 -0
  18. package/src/components/u-datetime-picker/u-datetime-picker.vue +377 -0
  19. package/src/components/u-divider/u-divider.vue +71 -0
  20. package/src/components/u-empty/u-empty.vue +98 -0
  21. package/src/components/u-grid/u-grid.vue +63 -0
  22. package/src/components/u-grid-item/u-grid-item.vue +170 -0
  23. package/src/components/u-icon/icons/account.svg +3 -0
  24. package/src/components/u-icon/icons/arrow-down.svg +3 -0
  25. package/src/components/u-icon/icons/arrow-left.svg +3 -0
  26. package/src/components/u-icon/icons/arrow-right.svg +3 -0
  27. package/src/components/u-icon/icons/arrow-up.svg +3 -0
  28. package/src/components/u-icon/icons/bell.svg +3 -0
  29. package/src/components/u-icon/icons/bookmark-o.svg +3 -0
  30. package/src/components/u-icon/icons/bookmark.svg +3 -0
  31. package/src/components/u-icon/icons/chat.svg +3 -0
  32. package/src/components/u-icon/icons/check-circle.svg +3 -0
  33. package/src/components/u-icon/icons/check.svg +3 -0
  34. package/src/components/u-icon/icons/chevron-left.svg +3 -0
  35. package/src/components/u-icon/icons/chevron-right.svg +3 -0
  36. package/src/components/u-icon/icons/clear-o.svg +3 -0
  37. package/src/components/u-icon/icons/clear.svg +3 -0
  38. package/src/components/u-icon/icons/clipboard.svg +3 -0
  39. package/src/components/u-icon/icons/clock.svg +3 -0
  40. package/src/components/u-icon/icons/close.svg +3 -0
  41. package/src/components/u-icon/icons/code.svg +3 -0
  42. package/src/components/u-icon/icons/copy.svg +3 -0
  43. package/src/components/u-icon/icons/delete.svg +3 -0
  44. package/src/components/u-icon/icons/download.svg +3 -0
  45. package/src/components/u-icon/icons/edit.svg +3 -0
  46. package/src/components/u-icon/icons/email.svg +3 -0
  47. package/src/components/u-icon/icons/error-o.svg +3 -0
  48. package/src/components/u-icon/icons/error.svg +3 -0
  49. package/src/components/u-icon/icons/exit-fullscreen.svg +3 -0
  50. package/src/components/u-icon/icons/expand-less.svg +3 -0
  51. package/src/components/u-icon/icons/expand-more.svg +3 -0
  52. package/src/components/u-icon/icons/eye-off.svg +3 -0
  53. package/src/components/u-icon/icons/eye.svg +3 -0
  54. package/src/components/u-icon/icons/flag-o.svg +3 -0
  55. package/src/components/u-icon/icons/flag.svg +3 -0
  56. package/src/components/u-icon/icons/fullscreen.svg +3 -0
  57. package/src/components/u-icon/icons/grid.svg +3 -0
  58. package/src/components/u-icon/icons/group.svg +3 -0
  59. package/src/components/u-icon/icons/heart-o.svg +3 -0
  60. package/src/components/u-icon/icons/heart.svg +3 -0
  61. package/src/components/u-icon/icons/info-o.svg +3 -0
  62. package/src/components/u-icon/icons/info.svg +3 -0
  63. package/src/components/u-icon/icons/keyboard-arrow-down.svg +3 -0
  64. package/src/components/u-icon/icons/keyboard-arrow-left.svg +3 -0
  65. package/src/components/u-icon/icons/keyboard-arrow-right.svg +3 -0
  66. package/src/components/u-icon/icons/keyboard-arrow-up.svg +3 -0
  67. package/src/components/u-icon/icons/like-o.svg +3 -0
  68. package/src/components/u-icon/icons/like.svg +3 -0
  69. package/src/components/u-icon/icons/link.svg +3 -0
  70. package/src/components/u-icon/icons/list.svg +3 -0
  71. package/src/components/u-icon/icons/loading.svg +3 -0
  72. package/src/components/u-icon/icons/lock.svg +3 -0
  73. package/src/components/u-icon/icons/menu-o.svg +3 -0
  74. package/src/components/u-icon/icons/menu.svg +3 -0
  75. package/src/components/u-icon/icons/message.svg +3 -0
  76. package/src/components/u-icon/icons/minus.svg +3 -0
  77. package/src/components/u-icon/icons/notification.svg +3 -0
  78. package/src/components/u-icon/icons/phone.svg +3 -0
  79. package/src/components/u-icon/icons/plus.svg +3 -0
  80. package/src/components/u-icon/icons/question.svg +3 -0
  81. package/src/components/u-icon/icons/redo.svg +3 -0
  82. package/src/components/u-icon/icons/refresh-o.svg +3 -0
  83. package/src/components/u-icon/icons/refresh.svg +3 -0
  84. package/src/components/u-icon/icons/reload.svg +3 -0
  85. package/src/components/u-icon/icons/search-o.svg +3 -0
  86. package/src/components/u-icon/icons/search.svg +3 -0
  87. package/src/components/u-icon/icons/setting.svg +3 -0
  88. package/src/components/u-icon/icons/share.svg +3 -0
  89. package/src/components/u-icon/icons/smile-o.svg +3 -0
  90. package/src/components/u-icon/icons/smile.svg +3 -0
  91. package/src/components/u-icon/icons/star-o.svg +3 -0
  92. package/src/components/u-icon/icons/star.svg +3 -0
  93. package/src/components/u-icon/icons/success-o.svg +3 -0
  94. package/src/components/u-icon/icons/success.svg +3 -0
  95. package/src/components/u-icon/icons/sync.svg +3 -0
  96. package/src/components/u-icon/icons/tick.svg +3 -0
  97. package/src/components/u-icon/icons/undo.svg +3 -0
  98. package/src/components/u-icon/icons/unlock.svg +3 -0
  99. package/src/components/u-icon/icons/upload.svg +3 -0
  100. package/src/components/u-icon/icons/user.svg +3 -0
  101. package/src/components/u-icon/icons/warning-o.svg +3 -0
  102. package/src/components/u-icon/icons/warning.svg +3 -0
  103. package/src/components/u-icon/icons/zoom-in.svg +3 -0
  104. package/src/components/u-icon/icons/zoom-out.svg +3 -0
  105. package/src/components/u-icon/index.ts +219 -0
  106. package/src/components/u-icon/u-icon.vue +117 -0
  107. package/src/components/u-image/u-image.vue +106 -0
  108. package/src/components/u-input/u-input.vue +208 -0
  109. package/src/components/u-keyboard/u-keyboard.vue +213 -0
  110. package/src/components/u-layout/u-layout.vue +58 -0
  111. package/src/components/u-line-progress/u-line-progress.vue +156 -0
  112. package/src/components/u-link/u-link.vue +113 -0
  113. package/src/components/u-list/u-list.vue +148 -0
  114. package/src/components/u-list-item/u-list-item.vue +180 -0
  115. package/src/components/u-loading/u-loading.vue +80 -0
  116. package/src/components/u-loading-page/u-loading-page.vue +94 -0
  117. package/src/components/u-modal/u-modal.vue +159 -0
  118. package/src/components/u-notice-bar/u-notice-bar.vue +113 -0
  119. package/src/components/u-number-box/u-number-box.vue +262 -0
  120. package/src/components/u-parse/u-parse.vue +197 -0
  121. package/src/components/u-picker/u-picker.vue +219 -0
  122. package/src/components/u-popup/u-popup.vue +257 -0
  123. package/src/components/u-radio/u-radio.vue +159 -0
  124. package/src/components/u-radio-group/u-radio-group.vue +61 -0
  125. package/src/components/u-rate/u-rate.vue +187 -0
  126. package/src/components/u-read-more/u-read-more.vue +117 -0
  127. package/src/components/u-search/u-search.vue +238 -0
  128. package/src/components/u-skeleton/u-skeleton.vue +192 -0
  129. package/src/components/u-slider/u-slider.vue +453 -0
  130. package/src/components/u-swiper/u-swiper.vue +301 -0
  131. package/src/components/u-swiper-item/u-swiper-item.vue +82 -0
  132. package/src/components/u-switch/u-switch.vue +105 -0
  133. package/src/components/u-tabbar/u-tabbar.vue +221 -0
  134. package/src/components/u-tag/u-tag.vue +144 -0
  135. package/src/components/u-textarea/u-textarea.vue +189 -0
  136. package/src/components/u-toast/u-toast.vue +186 -0
  137. package/src/components/u-tooltip/u-tooltip.vue +364 -0
  138. package/src/components/u-transition/u-transition.vue +216 -0
  139. package/src/components/u-upload/u-upload.vue +403 -0
  140. package/src/styles/index.scss +59 -0
  141. package/src/styles/variables.scss +68 -0
@@ -0,0 +1,453 @@
1
+ <template>
2
+ <view
3
+ class="u-slider"
4
+ :class="{
5
+ 'u-slider--disabled': disabled
6
+ }"
7
+ >
8
+ <!-- 最小值标签 -->
9
+ <view v-if="showMinMax" class="u-slider__min">
10
+ <text class="u-slider__label">{{ min }}</text>
11
+ </view>
12
+
13
+ <!-- 滑动轨道 -->
14
+ <view
15
+ class="u-slider__track"
16
+ :style="trackStyle"
17
+ @click="handleTrackClick"
18
+ @touchstart="handleTouchStart"
19
+ @touchmove="handleTouchMove"
20
+ @touchend="handleTouchEnd"
21
+ >
22
+ <!-- 已选择区域 -->
23
+ <view class="u-slider__bar" :style="barStyle">
24
+ <!-- 滑块 -->
25
+ <view
26
+ v-if="!range"
27
+ class="u-slider__button"
28
+ :style="buttonStyle"
29
+ @touchstart.stop="handleButtonTouchStart"
30
+ @touchmove.stop="handleButtonTouchMove"
31
+ @touchend.stop="handleButtonTouchEnd"
32
+ >
33
+ <view v-if="showValue" class="u-slider__tooltip">
34
+ <text class="u-slider__tooltip-text">{{ currentValue }}</text>
35
+ </view>
36
+ </view>
37
+
38
+ <!-- 双滑块 -->
39
+ <template v-else>
40
+ <view
41
+ class="u-slider__button u-slider__button--start"
42
+ :style="startButtonStyle"
43
+ @touchstart.stop="handleStartButtonTouchStart"
44
+ @touchmove.stop="handleStartButtonTouchMove"
45
+ @touchend.stop="handleButtonTouchEnd"
46
+ >
47
+ <view v-if="showValue" class="u-slider__tooltip">
48
+ <text class="u-slider__tooltip-text">{{ startValue }}</text>
49
+ </view>
50
+ </view>
51
+ <view
52
+ class="u-slider__button u-slider__button--end"
53
+ :style="endButtonStyle"
54
+ @touchstart.stop="handleEndButtonTouchStart"
55
+ @touchmove.stop="handleEndButtonTouchMove"
56
+ @touchend.stop="handleButtonTouchEnd"
57
+ >
58
+ <view v-if="showValue" class="u-slider__tooltip">
59
+ <text class="u-slider__tooltip-text">{{ endValue }}</text>
60
+ </view>
61
+ </view>
62
+ </template>
63
+ </view>
64
+
65
+ <!-- 刻度标记 -->
66
+ <view v-if="showTicks" class="u-slider__ticks">
67
+ <view
68
+ v-for="(tick, index) in ticks"
69
+ :key="index"
70
+ class="u-slider__tick"
71
+ :style="{ left: tick.position + '%' }"
72
+ ></view>
73
+ </view>
74
+ </view>
75
+
76
+ <!-- 最大值标签 -->
77
+ <view v-if="showMinMax" class="u-slider__max">
78
+ <text class="u-slider__label">{{ max }}</text>
79
+ </view>
80
+ </view>
81
+ </template>
82
+
83
+ <script setup lang="ts">
84
+ import { ref, computed, watch } from 'vue'
85
+
86
+ interface Props {
87
+ modelValue?: number | [number, number]
88
+ min?: number
89
+ max?: number
90
+ step?: number
91
+ disabled?: boolean
92
+ range?: boolean
93
+ showValue?: boolean
94
+ showMinMax?: boolean
95
+ showTicks?: boolean
96
+ barHeight?: number | string
97
+ activeColor?: string
98
+ inactiveColor?: string
99
+ buttonColor?: string
100
+ buttonSize?: number | string
101
+ }
102
+
103
+ const props = withDefaults(defineProps<Props>(), {
104
+ modelValue: 0,
105
+ min: 0,
106
+ max: 100,
107
+ step: 1,
108
+ disabled: false,
109
+ range: false,
110
+ showValue: false,
111
+ showMinMax: false,
112
+ showTicks: false,
113
+ barHeight: 2,
114
+ activeColor: '#1989fa',
115
+ inactiveColor: '#e5e5e5',
116
+ buttonColor: '#fff',
117
+ buttonSize: 24
118
+ })
119
+
120
+ const emit = defineEmits<{
121
+ 'update:modelValue': [value: number | [number, number]]
122
+ change: [value: number | [number, number]]
123
+ dragstart: []
124
+ dragend: []
125
+ }>()
126
+
127
+ const currentValue = ref(0)
128
+ const startValue = ref(0)
129
+ const endValue = ref(100)
130
+ const trackWidth = ref(0)
131
+ const trackLeft = ref(0)
132
+ const isDragging = ref(false)
133
+ const dragType = ref<'single' | 'start' | 'end'>('single')
134
+
135
+ const barHeightStyle = computed(() => {
136
+ const height = props.barHeight
137
+ return typeof height === 'number' ? `${height}px` : height
138
+ })
139
+
140
+ const buttonSizeStyle = computed(() => {
141
+ const size = props.buttonSize
142
+ return typeof size === 'number' ? `${size}px` : size
143
+ })
144
+
145
+ const trackStyle = computed(() => ({
146
+ height: barHeightStyle.value,
147
+ backgroundColor: props.inactiveColor
148
+ }))
149
+
150
+ const barStyle = computed(() => {
151
+ if (props.range) {
152
+ const startPercent = ((startValue.value - props.min) / (props.max - props.min)) * 100
153
+ const endPercent = ((endValue.value - props.min) / (props.max - props.min)) * 100
154
+ return {
155
+ left: `${startPercent}%`,
156
+ width: `${endPercent - startPercent}%`,
157
+ height: barHeightStyle.value,
158
+ backgroundColor: props.activeColor
159
+ }
160
+ }
161
+ const percent = ((currentValue.value - props.min) / (props.max - props.min)) * 100
162
+ return {
163
+ width: `${percent}%`,
164
+ height: barHeightStyle.value,
165
+ backgroundColor: props.activeColor
166
+ }
167
+ })
168
+
169
+ const buttonStyle = computed(() => ({
170
+ width: buttonSizeStyle.value,
171
+ height: buttonSizeStyle.value,
172
+ backgroundColor: props.buttonColor,
173
+ borderColor: props.activeColor
174
+ }))
175
+
176
+ const startButtonStyle = computed(() => ({
177
+ ...buttonStyle.value,
178
+ left: `-${parseInt(buttonSizeStyle.value) / 2}px`
179
+ }))
180
+
181
+ const endButtonStyle = computed(() => ({
182
+ ...buttonStyle.value,
183
+ right: `-${parseInt(buttonSizeStyle.value) / 2}px`
184
+ }))
185
+
186
+ const ticks = computed(() => {
187
+ const tickCount = Math.floor((props.max - props.min) / props.step)
188
+ const result = []
189
+ for (let i = 0; i <= tickCount; i++) {
190
+ result.push({
191
+ position: (i / tickCount) * 100
192
+ })
193
+ }
194
+ return result
195
+ })
196
+
197
+ watch(() => props.modelValue, (val) => {
198
+ if (props.range && Array.isArray(val)) {
199
+ startValue.value = val[0]
200
+ endValue.value = val[1]
201
+ } else if (typeof val === 'number') {
202
+ currentValue.value = val
203
+ }
204
+ }, { immediate: true })
205
+
206
+ const updateTrackRect = () => {
207
+ // uni-app 中需要使用 createSelectorQuery
208
+ // 这里简化处理,在touch事件中动态计算
209
+ const query = uni.createSelectorQuery?.()
210
+ if (query) {
211
+ query.select('.u-slider__track').boundingClientRect((rect: any) => {
212
+ if (rect) {
213
+ trackWidth.value = rect.width
214
+ trackLeft.value = rect.left
215
+ }
216
+ }).exec()
217
+ }
218
+ }
219
+
220
+ const getStepValue = (value: number): number => {
221
+ const stepCount = Math.round((value - props.min) / props.step)
222
+ return props.min + stepCount * props.step
223
+ }
224
+
225
+ const updateValue = (value: number) => {
226
+ const stepped = getStepValue(value)
227
+ currentValue.value = stepped
228
+ emit('update:modelValue', stepped)
229
+ emit('change', stepped)
230
+ }
231
+
232
+ const updateRangeValue = (type: 'start' | 'end', value: number) => {
233
+ const stepped = getStepValue(value)
234
+ if (type === 'start') {
235
+ if (stepped < endValue.value) {
236
+ startValue.value = stepped
237
+ }
238
+ } else {
239
+ if (stepped > startValue.value) {
240
+ endValue.value = stepped
241
+ }
242
+ }
243
+ emit('update:modelValue', [startValue.value, endValue.value])
244
+ emit('change', [startValue.value, endValue.value])
245
+ }
246
+
247
+ const handleTrackClick = (event: any) => {
248
+ if (props.disabled) return
249
+ if (!trackWidth.value) updateTrackRect()
250
+
251
+ // 获取触摸/点击位置(兼容各平台)
252
+ const touch = event.touches?.[0] || event
253
+ const x = touch.clientX || touch.x || 0
254
+ const percent = (x - trackLeft.value) / trackWidth.value
255
+ const value = props.min + percent * (props.max - props.min)
256
+
257
+ if (props.range) {
258
+ if (Math.abs(value - startValue.value) < Math.abs(value - endValue.value)) {
259
+ updateRangeValue('start', value)
260
+ } else {
261
+ updateRangeValue('end', value)
262
+ }
263
+ } else {
264
+ updateValue(value)
265
+ }
266
+ }
267
+
268
+ const handleTouchStart = (event: any) => {
269
+ if (props.disabled) return
270
+ // 初始化轨道位置信息
271
+ const touch = event.touches?.[0]
272
+ if (touch) {
273
+ trackWidth.value = 1 // 初始化避免为0
274
+ }
275
+ }
276
+
277
+ const handleTouchMove = (event: any) => {
278
+ // 轨道触摸移动处理
279
+ }
280
+
281
+ const handleButtonTouchStart = () => {
282
+ if (props.disabled) return
283
+ isDragging.value = true
284
+ dragType.value = 'single'
285
+ emit('dragstart')
286
+ updateTrackRect()
287
+ }
288
+
289
+ const handleButtonTouchMove = (event: any) => {
290
+ if (!isDragging.value || props.disabled) return
291
+
292
+ // 获取触摸位置(兼容各平台)
293
+ const touch = event.touches?.[0] || event
294
+ const x = touch.clientX || touch.x || 0
295
+
296
+ const percent = (x - trackLeft.value) / trackWidth.value
297
+ const value = props.min + Math.max(0, Math.min(1, percent)) * (props.max - props.min)
298
+ updateValue(value)
299
+ }
300
+
301
+ const handleButtonTouchEnd = () => {
302
+ isDragging.value = false
303
+ emit('dragend')
304
+ }
305
+
306
+ const handleStartButtonTouchStart = () => {
307
+ if (props.disabled) return
308
+ isDragging.value = true
309
+ dragType.value = 'start'
310
+ emit('dragstart')
311
+ updateTrackRect()
312
+ }
313
+
314
+ const handleStartButtonTouchMove = (event: any) => {
315
+ if (!isDragging.value || props.disabled) return
316
+
317
+ // 获取触摸位置(兼容各平台)
318
+ const touch = event.touches?.[0] || event
319
+ const x = touch.clientX || touch.x || 0
320
+
321
+ const percent = (x - trackLeft.value) / trackWidth.value
322
+ const value = props.min + Math.max(0, Math.min(1, percent)) * (props.max - props.min)
323
+ updateRangeValue('start', value)
324
+ }
325
+
326
+ const handleEndButtonTouchStart = () => {
327
+ if (props.disabled) return
328
+ isDragging.value = true
329
+ dragType.value = 'end'
330
+ emit('dragstart')
331
+ updateTrackRect()
332
+ }
333
+
334
+ const handleEndButtonTouchMove = (event: any) => {
335
+ if (!isDragging.value || props.disabled) return
336
+
337
+ // 获取触摸位置(兼容各平台)
338
+ const touch = event.touches?.[0] || event
339
+ const x = touch.clientX || touch.x || 0
340
+
341
+ const percent = (x - trackLeft.value) / trackWidth.value
342
+ const value = props.min + Math.max(0, Math.min(1, percent)) * (props.max - props.min)
343
+ updateRangeValue('end', value)
344
+ }
345
+ </script>
346
+
347
+ <script lang="ts">
348
+ export default {
349
+ options: {
350
+ virtualHost: true,
351
+ styleIsolation: 'shared'
352
+ }
353
+ }
354
+ </script>
355
+
356
+ <style lang="scss" scoped>
357
+ .u-slider {
358
+ display: flex;
359
+ align-items: center;
360
+ width: 100%;
361
+ padding: $--spacing-md 0;
362
+ -webkit-user-select: none;
363
+ -moz-user-select: none;
364
+ -ms-user-select: none;
365
+ user-select: none;
366
+
367
+ &--disabled {
368
+ opacity: 0.5;
369
+ }
370
+
371
+ &__min,
372
+ &__max {
373
+ min-width: 32px;
374
+ text-align: center;
375
+ }
376
+
377
+ &__label {
378
+ font-size: $--font-size-sm;
379
+ color: $--text-color-2;
380
+ }
381
+
382
+ &__track {
383
+ flex: 1;
384
+ position: relative;
385
+ border-radius: 999px;
386
+ }
387
+
388
+ &__bar {
389
+ position: absolute;
390
+ border-radius: 999px;
391
+ transition: width 0.1s, left 0.1s;
392
+ }
393
+
394
+ &__button {
395
+ position: absolute;
396
+ top: 50%;
397
+ transform: translateY(-50%);
398
+ border-radius: 50%;
399
+ border: 2px solid $--color-primary;
400
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
401
+ transition: transform 0.1s;
402
+
403
+ &:active {
404
+ transform: translateY(-50%) scale(1.2);
405
+ }
406
+
407
+ &--start {
408
+ left: calc(-1 * $--slider-button-size / 2);
409
+ }
410
+
411
+ &--end {
412
+ right: calc(-1 * $--slider-button-size / 2);
413
+ }
414
+ }
415
+
416
+ &__tooltip {
417
+ position: absolute;
418
+ left: 50%;
419
+ bottom: 100%;
420
+ transform: translateX(-50%);
421
+ padding: 4px 8px;
422
+ background: $--text-color;
423
+ color: #fff;
424
+ font-size: $--font-size-xs;
425
+ border-radius: $--border-radius-sm;
426
+ white-space: nowrap;
427
+ margin-bottom: 8px;
428
+
429
+ &::after {
430
+ content: '';
431
+ position: absolute;
432
+ top: 100%;
433
+ left: 50%;
434
+ transform: translateX(-50%);
435
+ border: 4px solid transparent;
436
+ border-top-color: $--text-color;
437
+ }
438
+ }
439
+
440
+ &__ticks {
441
+ position: absolute;
442
+ inset: 0;
443
+ }
444
+
445
+ &__tick {
446
+ position: absolute;
447
+ width: 2px;
448
+ height: 100%;
449
+ background: rgba(0, 0, 0, 0.1);
450
+ transform: translateX(-50%);
451
+ }
452
+ }
453
+ </style>