@didaoktv/didaoui-uniapp 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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +89 -0
  3. package/components/dd-action-sheet/dd-action-sheet.vue +207 -0
  4. package/components/dd-alert/dd-alert.vue +240 -0
  5. package/components/dd-avatar/dd-avatar.vue +168 -0
  6. package/components/dd-backtop/dd-backtop.vue +75 -0
  7. package/components/dd-badge/dd-badge.vue +150 -0
  8. package/components/dd-button/dd-button.vue +215 -0
  9. package/components/dd-capsule-button/dd-capsule-button.vue +109 -0
  10. package/components/dd-card/dd-card.vue +155 -0
  11. package/components/dd-cell/dd-cell.vue +201 -0
  12. package/components/dd-cell-group/dd-cell-group.vue +56 -0
  13. package/components/dd-champion-card/dd-champion-card.vue +258 -0
  14. package/components/dd-checkbox/dd-checkbox.vue +145 -0
  15. package/components/dd-collapse/dd-collapse.vue +63 -0
  16. package/components/dd-collapse-item/dd-collapse-item.vue +154 -0
  17. package/components/dd-count-down/dd-count-down.vue +163 -0
  18. package/components/dd-date-picker/dd-date-picker.vue +253 -0
  19. package/components/dd-dialog/dd-dialog.vue +264 -0
  20. package/components/dd-divider/dd-divider.vue +104 -0
  21. package/components/dd-drawer/dd-drawer.vue +214 -0
  22. package/components/dd-dropdown-item/dd-dropdown-item.vue +203 -0
  23. package/components/dd-dropdown-menu/dd-dropdown-menu.vue +177 -0
  24. package/components/dd-empty-state/dd-empty-state.vue +140 -0
  25. package/components/dd-feature-grid/dd-feature-grid.vue +139 -0
  26. package/components/dd-field/dd-field.vue +240 -0
  27. package/components/dd-icon/dd-icon.vue +464 -0
  28. package/components/dd-image/dd-image.vue +158 -0
  29. package/components/dd-input/dd-input.vue +172 -0
  30. package/components/dd-list-cell/dd-list-cell.vue +152 -0
  31. package/components/dd-loading/dd-loading.vue +187 -0
  32. package/components/dd-loadmore/dd-loadmore.vue +152 -0
  33. package/components/dd-mini-program-navbar/dd-mini-program-navbar.vue +245 -0
  34. package/components/dd-modal/dd-modal.vue +286 -0
  35. package/components/dd-navigation/dd-navigation.vue +134 -0
  36. package/components/dd-overlay/dd-overlay.vue +114 -0
  37. package/components/dd-picker/dd-picker.vue +203 -0
  38. package/components/dd-popover/dd-popover.vue +190 -0
  39. package/components/dd-popover-item/dd-popover-item.vue +88 -0
  40. package/components/dd-popup/dd-popup.vue +243 -0
  41. package/components/dd-progress/dd-progress.vue +255 -0
  42. package/components/dd-pull-refresh/dd-pull-refresh.vue +232 -0
  43. package/components/dd-radio/dd-radio.vue +129 -0
  44. package/components/dd-rate/dd-rate.vue +133 -0
  45. package/components/dd-room-card/dd-room-card.vue +309 -0
  46. package/components/dd-search-bar/dd-search-bar.vue +176 -0
  47. package/components/dd-segmented-tab/dd-segmented-tab.vue +187 -0
  48. package/components/dd-skeleton/dd-skeleton.vue +184 -0
  49. package/components/dd-slider/dd-slider.vue +227 -0
  50. package/components/dd-stat-card/dd-stat-card.vue +174 -0
  51. package/components/dd-step/dd-step.vue +188 -0
  52. package/components/dd-stepper/dd-stepper.vue +171 -0
  53. package/components/dd-steps/dd-steps.vue +61 -0
  54. package/components/dd-sticky/dd-sticky.vue +132 -0
  55. package/components/dd-swipe/dd-swipe.vue +146 -0
  56. package/components/dd-swipe-action/dd-swipe-action.vue +248 -0
  57. package/components/dd-swipe-item/dd-swipe-item.vue +27 -0
  58. package/components/dd-swipeable-tab/dd-swipeable-tab.vue +202 -0
  59. package/components/dd-switch/dd-switch.vue +106 -0
  60. package/components/dd-tabbar/dd-tabbar.vue +112 -0
  61. package/components/dd-tabbar-item/dd-tabbar-item.vue +122 -0
  62. package/components/dd-tag/dd-tag.vue +178 -0
  63. package/components/dd-toast/dd-toast.vue +195 -0
  64. package/components/dd-top-navbar/dd-top-navbar.vue +184 -0
  65. package/components/dd-upload/dd-upload.vue +187 -0
  66. package/index.ts +127 -0
  67. package/libs/utils.ts +106 -0
  68. package/package.json +58 -0
  69. package/scss/_functions.scss +68 -0
  70. package/scss/_mixins.scss +154 -0
  71. package/scss/_reset.scss +30 -0
  72. package/scss/_variables.scss +317 -0
  73. package/uni.scss +4 -0
@@ -0,0 +1,88 @@
1
+ <template>
2
+ <view
3
+ class="dd-popover-item"
4
+ :class="{ 'dd-popover-item--disabled': disabled }"
5
+ :style="itemStyle"
6
+ @click="onClick"
7
+ >
8
+ <dd-icon v-if="icon" :name="icon" class="dd-popover-item__icon" />
9
+ <text class="dd-popover-item__text">{{ text }}</text>
10
+ </view>
11
+ </template>
12
+
13
+ <script setup lang="ts">
14
+ import { computed, inject } from 'vue'
15
+ import DdIcon from '../dd-icon/dd-icon.vue'
16
+
17
+ interface Props {
18
+ text?: string
19
+ icon?: string
20
+ value?: any
21
+ disabled?: boolean
22
+ color?: string
23
+ }
24
+
25
+ const props = withDefaults(defineProps<Props>(), {
26
+ text: '',
27
+ icon: '',
28
+ value: undefined,
29
+ disabled: false,
30
+ color: '',
31
+ })
32
+
33
+ const emit = defineEmits<{
34
+ (e: 'click', value: any): void
35
+ }>()
36
+
37
+ // inject 父级 dd-popover 的点击中继;不在 dd-popover 内时为 null,点击静默忽略
38
+ const popover = inject<{ onSelect: (value: any) => void } | null>('ddPopover', null)
39
+
40
+ const itemStyle = computed(() => (props.color ? { color: props.color } : {}))
41
+
42
+ function onClick() {
43
+ if (props.disabled) return
44
+ emit('click', props.value)
45
+ popover?.onSelect(props.value)
46
+ }
47
+ </script>
48
+
49
+ <style lang="scss" scoped>
50
+ @import '../../scss/variables';
51
+ @import '../../scss/mixins';
52
+
53
+ .dd-popover-item {
54
+ display: flex;
55
+ align-items: center;
56
+ height: 80rpx;
57
+ padding: 0 32rpx;
58
+ gap: 16rpx;
59
+ color: inherit;
60
+ background: transparent;
61
+ @include dd-transition(background 0.15s ease);
62
+
63
+ // 首项不显示顶部分隔线,其余项之间用 hairline 分隔
64
+ &:not(:first-child) {
65
+ @include dd-hairline-top($dd-border-default);
66
+ }
67
+
68
+ &:active {
69
+ background: $dd-surface-container;
70
+ }
71
+
72
+ &--disabled {
73
+ opacity: 0.5;
74
+ @include dd-no-touch;
75
+ }
76
+
77
+ &__icon {
78
+ font-size: 32rpx;
79
+ line-height: 1;
80
+ }
81
+
82
+ &__text {
83
+ flex: 1;
84
+ font-size: $dd-font-size-body;
85
+ @include dd-ellipsis(1);
86
+ }
87
+ }
88
+ </style>
@@ -0,0 +1,243 @@
1
+ <template>
2
+ <view class="dd-popup" :style="{ '--dd-popup-duration': `${props.duration}s` }">
3
+ <view
4
+ v-if="visible && overlay"
5
+ class="dd-popup__overlay"
6
+ :class="{ 'dd-popup__overlay--show': showClass }"
7
+ :style="{ zIndex: overlayZIndex }"
8
+ @click="onOverlayClick"
9
+ @touchmove.stop.prevent="noop"
10
+ ></view>
11
+ <view
12
+ v-if="visible"
13
+ class="dd-popup__panel"
14
+ :class="[
15
+ `dd-popup__panel--${position}`,
16
+ { 'dd-popup__panel--show': showClass, 'dd-popup__panel--round': round }
17
+ ]"
18
+ :style="panelStyle"
19
+ >
20
+ <view v-if="closeable" class="dd-popup__close" :class="`dd-popup__close--${closeIconPosition}`" @click="onCloseIcon">
21
+ <dd-icon name="cross" />
22
+ </view>
23
+ <view v-if="position === 'bottom' && safeAreaInsetBottom" class="dd-popup__safe-bottom"></view>
24
+ <slot></slot>
25
+ </view>
26
+ </view>
27
+ </template>
28
+
29
+ <script setup lang="ts">
30
+ import { computed, ref, watch, onUnmounted, nextTick } from 'vue'
31
+ import DdIcon from '../dd-icon/dd-icon.vue'
32
+
33
+ interface Props {
34
+ modelValue?: boolean
35
+ position?: 'top' | 'bottom' | 'left' | 'right' | 'center'
36
+ round?: boolean
37
+ overlay?: boolean
38
+ closeable?: boolean
39
+ closeIconPosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
40
+ safeAreaInsetBottom?: boolean
41
+ duration?: number
42
+ width?: string
43
+ height?: string
44
+ closeOnClickOverlay?: boolean
45
+ zIndex?: number
46
+ }
47
+
48
+ const props = withDefaults(defineProps<Props>(), {
49
+ modelValue: false,
50
+ position: 'bottom',
51
+ round: false,
52
+ overlay: true,
53
+ closeable: false,
54
+ closeIconPosition: 'top-right',
55
+ safeAreaInsetBottom: true,
56
+ duration: 0.3,
57
+ width: '',
58
+ height: '',
59
+ closeOnClickOverlay: true,
60
+ zIndex: 2000,
61
+ })
62
+
63
+ const emit = defineEmits<{
64
+ (e: 'update:modelValue', val: boolean): void
65
+ (e: 'open'): void
66
+ (e: 'close'): void
67
+ (e: 'opened'): void
68
+ (e: 'closed'): void
69
+ (e: 'click-overlay'): void
70
+ (e: 'click-close-icon'): void
71
+ }>()
72
+
73
+ const overlayZIndex = computed(() => props.zIndex)
74
+ const panelZIndex = computed(() => props.zIndex + 1)
75
+
76
+ const panelStyle = computed(() => {
77
+ const s: Record<string, string> = {
78
+ zIndex: String(panelZIndex.value),
79
+ }
80
+ if (props.width && (props.position === 'left' || props.position === 'right')) {
81
+ s.width = props.width
82
+ }
83
+ if (props.height && (props.position === 'top' || props.position === 'bottom')) {
84
+ s.height = props.height
85
+ }
86
+ return s
87
+ })
88
+
89
+ // 两阶段控制:visible 控制挂载,showClass 控制动画
90
+ const visible = ref(false)
91
+ const showClass = ref(false)
92
+ let timer: ReturnType<typeof setTimeout> | null = null
93
+
94
+ watch(
95
+ () => props.modelValue,
96
+ async (val) => {
97
+ if (timer) {
98
+ clearTimeout(timer)
99
+ timer = null
100
+ }
101
+
102
+ if (val) {
103
+ // Phase 1: 挂载到 DOM(初始态:translateX/Y 离屏 / scale(0.9))
104
+ visible.value = true
105
+ emit('open')
106
+
107
+ // Phase 2: 双 RAF 确保 paint 初始帧,再加 show class
108
+ await nextTick()
109
+ await new Promise<void>(r => requestAnimationFrame(() => r()))
110
+ await new Promise<void>(r => requestAnimationFrame(() => r()))
111
+ showClass.value = true
112
+ timer = setTimeout(() => emit('opened'), props.duration * 1000)
113
+ } else {
114
+ if (!visible.value) return
115
+
116
+ // 关闭:移除 show class 触发退出过渡,等动画结束再卸载
117
+ showClass.value = false
118
+ emit('close')
119
+ timer = setTimeout(() => {
120
+ visible.value = false
121
+ emit('closed')
122
+ }, props.duration * 1000)
123
+ }
124
+ },
125
+ { immediate: true }
126
+ )
127
+
128
+ function noop() {}
129
+
130
+ function close() {
131
+ emit('update:modelValue', false)
132
+ }
133
+
134
+ function onOverlayClick() {
135
+ emit('click-overlay')
136
+ if (props.closeOnClickOverlay) close()
137
+ }
138
+
139
+ function onCloseIcon() {
140
+ emit('click-close-icon')
141
+ close()
142
+ }
143
+
144
+ onUnmounted(() => {
145
+ if (timer) clearTimeout(timer)
146
+ })
147
+ </script>
148
+
149
+ <style lang="scss" scoped>
150
+ @import '../../scss/variables';
151
+ @import '../../scss/mixins';
152
+
153
+ .dd-popup {
154
+ &__overlay {
155
+ position: fixed;
156
+ inset: 0;
157
+ background: rgba(0, 0, 0, 0.7);
158
+ backdrop-filter: blur(8px);
159
+ -webkit-backdrop-filter: blur(8px);
160
+ opacity: 0;
161
+ transition: opacity var(--dd-popup-duration, 0.3s) ease;
162
+
163
+ &--show {
164
+ opacity: 1;
165
+ }
166
+ }
167
+
168
+ &__panel {
169
+ position: fixed;
170
+ background: $dd-bg-elevated;
171
+ box-shadow: $dd-shadow-3;
172
+ transition: transform var(--dd-popup-duration, 0.3s) ease,
173
+ opacity var(--dd-popup-duration, 0.3s) ease;
174
+
175
+ &--top {
176
+ top: 0;
177
+ left: 0;
178
+ right: 0;
179
+ transform: translateY(-100%);
180
+ &.dd-popup__panel--round { border-radius: 0 0 $dd-radius-lg $dd-radius-lg; }
181
+ &.dd-popup__panel--show { transform: translateY(0); }
182
+ }
183
+
184
+ &--bottom {
185
+ bottom: 0;
186
+ left: 0;
187
+ right: 0;
188
+ transform: translateY(100%);
189
+ &.dd-popup__panel--round { border-radius: $dd-radius-lg $dd-radius-lg 0 0; }
190
+ &.dd-popup__panel--show { transform: translateY(0); }
191
+ }
192
+
193
+ &--left {
194
+ top: 0;
195
+ bottom: 0;
196
+ left: 0;
197
+ transform: translateX(-100%);
198
+ &.dd-popup__panel--round { border-radius: 0 $dd-radius-lg $dd-radius-lg 0; }
199
+ &.dd-popup__panel--show { transform: translateX(0); }
200
+ }
201
+
202
+ &--right {
203
+ top: 0;
204
+ bottom: 0;
205
+ right: 0;
206
+ transform: translateX(100%);
207
+ &.dd-popup__panel--round { border-radius: $dd-radius-lg 0 0 $dd-radius-lg; }
208
+ &.dd-popup__panel--show { transform: translateX(0); }
209
+ }
210
+
211
+ &--center {
212
+ top: 50%;
213
+ left: 50%;
214
+ transform: translate(-50%, -50%) scale(0.9);
215
+ opacity: 0;
216
+ &.dd-popup__panel--round { border-radius: $dd-radius-lg; }
217
+ &.dd-popup__panel--show {
218
+ transform: translate(-50%, -50%) scale(1);
219
+ opacity: 1;
220
+ }
221
+ }
222
+ }
223
+
224
+ &__close {
225
+ position: absolute;
226
+ width: 56rpx;
227
+ height: 56rpx;
228
+ color: $dd-text-tertiary;
229
+ font-size: 44rpx;
230
+ @include dd-flex-center;
231
+ z-index: 2;
232
+
233
+ &--top-left { top: 16rpx; left: 16rpx; }
234
+ &--top-right { top: 16rpx; right: 16rpx; }
235
+ &--bottom-left { bottom: 16rpx; left: 16rpx; }
236
+ &--bottom-right { bottom: 16rpx; right: 16rpx; }
237
+ }
238
+
239
+ &__safe-bottom {
240
+ @include dd-safe-area-bottom;
241
+ }
242
+ }
243
+ </style>
@@ -0,0 +1,255 @@
1
+ <template>
2
+ <view class="dd-progress" :class="[`dd-progress--${type}`]">
3
+ <!-- linear -->
4
+ <template v-if="type === 'linear'">
5
+ <view class="dd-progress__track">
6
+ <view
7
+ v-if="!indeterminate"
8
+ class="dd-progress__fill"
9
+ :style="{ width: pct + '%', background: fillColor }"
10
+ ></view>
11
+ <view v-else class="dd-progress__fill dd-progress__fill--indeterminate" :style="{ background: fillColor }"></view>
12
+ </view>
13
+ <text v-if="showText && !indeterminate" class="dd-progress__text">{{ pct }}%</text>
14
+ </template>
15
+
16
+ <!-- circular -->
17
+ <template v-else-if="type === 'circular'">
18
+ <view
19
+ class="dd-progress__circle"
20
+ :style="{
21
+ width: size + 'rpx',
22
+ height: size + 'rpx',
23
+ background: `conic-gradient(${ringColor} ${pct}%, ${trackColor} ${pct}% 100%)`,
24
+ }"
25
+ >
26
+ <view class="dd-progress__circle-mask" :style="{ width: `calc(100% - ${strokeWidth * 2}rpx)`, height: `calc(100% - ${strokeWidth * 2}rpx)` }">
27
+ <text v-if="showText" class="dd-progress__circle-text">{{ pct }}%</text>
28
+ </view>
29
+ </view>
30
+ </template>
31
+
32
+ <!-- steps -->
33
+ <template v-else>
34
+ <view class="dd-progress__steps">
35
+ <view v-for="i in stepCount" :key="i" class="dd-progress__step-node">
36
+ <view
37
+ class="dd-progress__dot"
38
+ :class="[
39
+ `dd-progress__dot--${stepStatus(i - 1)}`,
40
+ { 'dd-progress__dot--current': stepStatus(i - 1) === 'current' },
41
+ ]"
42
+ ></view>
43
+ <view
44
+ v-if="i < stepCount"
45
+ class="dd-progress__connector"
46
+ :class="{ 'dd-progress__connector--done': i - 1 < completedCount }"
47
+ ></view>
48
+ </view>
49
+ </view>
50
+ </template>
51
+ </view>
52
+ </template>
53
+
54
+ <script setup lang="ts">
55
+ import { computed } from 'vue'
56
+
57
+ interface Props {
58
+ type?: 'linear' | 'circular' | 'steps'
59
+ percentage?: number
60
+ showText?: boolean
61
+ /** steps 类型的步数 (默认 5) */
62
+ steps?: number
63
+ /** 填充色 (linear/circular),默认金色渐变 */
64
+ color?: string
65
+ trackColor?: string
66
+ /** circular 描边宽度 (rpx) */
67
+ strokeWidth?: number
68
+ /** circular 直径 (rpx) */
69
+ size?: number
70
+ indeterminate?: boolean
71
+ }
72
+
73
+ const props = withDefaults(defineProps<Props>(), {
74
+ type: 'linear',
75
+ percentage: 0,
76
+ showText: true,
77
+ steps: 5,
78
+ color: '',
79
+ trackColor: '',
80
+ strokeWidth: 8,
81
+ size: 200,
82
+ indeterminate: false,
83
+ })
84
+
85
+ const pct = computed(() => Math.max(0, Math.min(100, Math.round(props.percentage))))
86
+
87
+ const fillColor = computed(
88
+ () => props.color || `linear-gradient(90deg, #FFC107, #D4891A)` // primary-400 → primary-600
89
+ )
90
+
91
+ const trackColor = computed(() => props.trackColor || '#2A2A2A')
92
+
93
+ const ringColor = computed(() => props.color || '#F5A623')
94
+
95
+ const stepCount = computed(() => Math.max(1, props.steps))
96
+
97
+ const completedCount = computed(() =>
98
+ Math.min(stepCount.value, Math.round((pct.value / 100) * stepCount.value))
99
+ )
100
+
101
+ function stepStatus(i: number): 'done' | 'current' | 'pending' {
102
+ if (i < completedCount.value) return 'done'
103
+ if (i === completedCount.value && completedCount.value < stepCount.value) return 'current'
104
+ return 'pending'
105
+ }
106
+ </script>
107
+
108
+ <style lang="scss" scoped>
109
+ @import '../../scss/variables';
110
+ @import '../../scss/mixins';
111
+
112
+ .dd-progress {
113
+ width: 100%;
114
+
115
+ &--linear {
116
+ display: flex;
117
+ align-items: center;
118
+ gap: $dd-space-2;
119
+ }
120
+
121
+ &__track {
122
+ flex: 1;
123
+ height: 12rpx;
124
+ background: #2a2a2a;
125
+ border-radius: $dd-radius-full;
126
+ overflow: hidden;
127
+ position: relative;
128
+ }
129
+
130
+ &__fill {
131
+ height: 100%;
132
+ border-radius: $dd-radius-full;
133
+ @include dd-transition(width 0.3s ease);
134
+ box-shadow: 0 0 16rpx rgba(245, 166, 35, 0.5);
135
+ position: relative;
136
+ overflow: hidden;
137
+
138
+ &::after {
139
+ content: '';
140
+ position: absolute;
141
+ top: 0;
142
+ left: 0;
143
+ bottom: 0;
144
+ width: 100%;
145
+ background: linear-gradient(
146
+ 90deg,
147
+ transparent,
148
+ rgba(255, 255, 255, 0.3),
149
+ transparent
150
+ );
151
+ animation: dd-progress-shimmer 1.5s linear infinite;
152
+ }
153
+
154
+ &--indeterminate {
155
+ width: 40% !important;
156
+ animation: dd-progress-indeterminate 1.5s ease-in-out infinite;
157
+ }
158
+ }
159
+
160
+ &__text {
161
+ font-size: $dd-font-size-caption;
162
+ color: $dd-text-secondary;
163
+ font-variant-numeric: tabular-nums;
164
+ flex-shrink: 0;
165
+ }
166
+
167
+ // circular
168
+ // ponytail: conic-gradient 在部分小程序旧版本不支持,升级路径为 transform 旋转双半圆或 SVG
169
+ &__circle {
170
+ border-radius: 50%;
171
+ margin: 0 auto;
172
+ @include dd-flex-center;
173
+ }
174
+
175
+ &__circle-mask {
176
+ border-radius: 50%;
177
+ background: $dd-surface;
178
+ @include dd-flex-center;
179
+ }
180
+
181
+ &__circle-text {
182
+ font-size: $dd-font-size-lead;
183
+ font-weight: 700;
184
+ color: $dd-text-primary;
185
+ font-variant-numeric: tabular-nums;
186
+ }
187
+
188
+ // steps
189
+ &__steps {
190
+ display: flex;
191
+ align-items: center;
192
+ width: 100%;
193
+ }
194
+
195
+ &__step-node {
196
+ flex: 1;
197
+ display: flex;
198
+ align-items: center;
199
+ position: relative;
200
+
201
+ &:last-child {
202
+ flex: 0 0 24rpx;
203
+ }
204
+ }
205
+
206
+ &__dot {
207
+ width: 24rpx;
208
+ height: 24rpx;
209
+ border-radius: 50%;
210
+ background: #2a2a2a;
211
+ flex-shrink: 0;
212
+ @include dd-transition(all 0.3s ease);
213
+
214
+ &--done,
215
+ &--current {
216
+ background: $dd-gradient-primary;
217
+ box-shadow: 0 0 12rpx rgba(245, 166, 35, 0.5);
218
+ }
219
+
220
+ &--current {
221
+ transform: scale(1.2);
222
+ }
223
+ }
224
+
225
+ &__connector {
226
+ flex: 1;
227
+ height: 4rpx;
228
+ margin: 0 8rpx;
229
+ background: #2a2a2a;
230
+ @include dd-transition(background 0.3s ease);
231
+
232
+ &--done {
233
+ background: $dd-primary-500;
234
+ }
235
+ }
236
+ }
237
+
238
+ @keyframes dd-progress-shimmer {
239
+ 0% {
240
+ transform: translateX(-100%);
241
+ }
242
+ 100% {
243
+ transform: translateX(100%);
244
+ }
245
+ }
246
+
247
+ @keyframes dd-progress-indeterminate {
248
+ 0% {
249
+ transform: translateX(-100%);
250
+ }
251
+ 100% {
252
+ transform: translateX(250%);
253
+ }
254
+ }
255
+ </style>