@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,140 @@
1
+ <template>
2
+ <view class="dd-empty-state">
3
+ <slot name="image">
4
+ <view class="dd-empty-state__icon">
5
+ <dd-icon :name="icon" class="dd-empty-state__emoji" />
6
+ </view>
7
+ </slot>
8
+
9
+ <slot name="title">
10
+ <text class="dd-empty-state__title">{{ titleText }}</text>
11
+ </slot>
12
+
13
+ <slot v-if="description || $slots.description" name="description">
14
+ <text class="dd-empty-state__desc">{{ description }}</text>
15
+ </slot>
16
+
17
+ <slot v-if="showButton" name="button">
18
+ <view class="dd-empty-state__btn" @click="onAction">
19
+ <text class="dd-empty-state__btn-text">{{ buttonTextComputed }}</text>
20
+ </view>
21
+ </slot>
22
+
23
+ <slot name="bottom"></slot>
24
+ </view>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { computed } from 'vue'
29
+ import DdIcon from '../dd-icon/dd-icon.vue'
30
+
31
+ type EmptyType = 'no-data' | 'no-result' | 'error' | 'network'
32
+
33
+ interface Props {
34
+ type?: EmptyType
35
+ icon?: string
36
+ title?: string
37
+ description?: string
38
+ buttonText?: string
39
+ showButton?: boolean
40
+ }
41
+
42
+ const props = withDefaults(defineProps<Props>(), {
43
+ type: 'no-data',
44
+ icon: 'music',
45
+ title: '',
46
+ description: '',
47
+ buttonText: '',
48
+ showButton: true,
49
+ })
50
+
51
+ const emit = defineEmits<{
52
+ (e: 'action'): void
53
+ }>()
54
+
55
+ const titleMap: Record<EmptyType, string> = {
56
+ 'no-data': '暂无数据',
57
+ 'no-result': '未找到相关结果',
58
+ error: '加载失败',
59
+ network: '网络连接异常',
60
+ }
61
+
62
+ const buttonTextMap: Record<EmptyType, string> = {
63
+ 'no-data': '去添加',
64
+ 'no-result': '换个关键词',
65
+ error: '重新加载',
66
+ network: '检查网络',
67
+ }
68
+
69
+ const titleText = computed(() => props.title || titleMap[props.type])
70
+ const buttonTextComputed = computed(() => props.buttonText || buttonTextMap[props.type])
71
+
72
+ function onAction() {
73
+ emit('action')
74
+ }
75
+ </script>
76
+
77
+ <style lang="scss" scoped>
78
+ @import '../../scss/variables';
79
+ @import '../../scss/mixins';
80
+
81
+ .dd-empty-state {
82
+ display: flex;
83
+ flex-direction: column;
84
+ align-items: center;
85
+ justify-content: center;
86
+ padding: $dd-space-8 $dd-space-6;
87
+ text-align: center;
88
+
89
+ &__icon {
90
+ margin-bottom: $dd-space-4;
91
+ }
92
+
93
+ &__emoji {
94
+ font-size: 120rpx;
95
+ line-height: 1;
96
+ animation: dd-empty-float 3s ease-in-out infinite;
97
+ }
98
+
99
+ &__title {
100
+ font-size: $dd-font-size-h3;
101
+ font-weight: $dd-font-weight-h3;
102
+ color: $dd-text-primary;
103
+ line-height: $dd-line-height-h3;
104
+ }
105
+
106
+ &__desc {
107
+ margin-top: $dd-space-2;
108
+ font-size: $dd-font-size-body;
109
+ color: $dd-text-tertiary;
110
+ line-height: 1.5;
111
+ max-width: 560rpx;
112
+ }
113
+
114
+ &__btn {
115
+ margin-top: $dd-space-5;
116
+ padding: 0 $dd-space-5;
117
+ height: $dd-size-button-md;
118
+ border-radius: $dd-radius-full;
119
+ background: $dd-gradient-primary;
120
+ @include dd-flex-center;
121
+ box-shadow: $dd-shadow-glow-gold-md;
122
+ }
123
+
124
+ &__btn-text {
125
+ font-size: $dd-font-size-body;
126
+ font-weight: $dd-font-weight-body;
127
+ color: $dd-neutral-900;
128
+ }
129
+ }
130
+
131
+ @keyframes dd-empty-float {
132
+ 0%,
133
+ 100% {
134
+ transform: translateY(0);
135
+ }
136
+ 50% {
137
+ transform: translateY(-16rpx);
138
+ }
139
+ }
140
+ </style>
@@ -0,0 +1,139 @@
1
+ <template>
2
+ <view class="dd-feature-grid" :style="gridStyle">
3
+ <view
4
+ v-for="(item, index) in items"
5
+ :key="itemKey ? item[itemKey] : index"
6
+ class="dd-feature-grid__item"
7
+ :class="[`dd-feature-grid__item--${variant}`]"
8
+ :hover-class="'dd-feature-grid__item--press'"
9
+ :hover-stay-time="100"
10
+ @click="onItemClick(item, index)"
11
+ >
12
+ <view
13
+ class="dd-feature-grid__icon"
14
+ :style="iconStyle(item)"
15
+ >
16
+ <slot name="icon" :item="item" :index="index">
17
+ <dd-icon :name="iconOf(item)" class="dd-feature-grid__icon-text" />
18
+ </slot>
19
+ </view>
20
+ <text class="dd-feature-grid__label">{{ labelOf(item) }}</text>
21
+ </view>
22
+ </view>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import { computed } from 'vue'
27
+ import DdIcon from '../dd-icon/dd-icon.vue'
28
+
29
+ interface FeatureItem {
30
+ [key: string]: any
31
+ label?: string
32
+ icon?: string
33
+ color?: string
34
+ }
35
+
36
+ interface Props {
37
+ items?: FeatureItem[]
38
+ columns?: number
39
+ variant?: 'circle' | 'squircle'
40
+ labelKey?: string
41
+ iconKey?: string
42
+ colorKey?: string
43
+ itemKey?: string
44
+ }
45
+
46
+ const props = withDefaults(defineProps<Props>(), {
47
+ items: () => [],
48
+ columns: 4,
49
+ variant: 'circle',
50
+ labelKey: 'label',
51
+ iconKey: 'icon',
52
+ colorKey: 'color',
53
+ itemKey: '',
54
+ })
55
+
56
+ const emit = defineEmits<{
57
+ (e: 'item-click', val: { item: FeatureItem; index: number }): void
58
+ }>()
59
+
60
+ const gridStyle = computed(() => ({
61
+ gridTemplateColumns: `repeat(${props.columns}, 1fr)`,
62
+ }))
63
+
64
+ const defaultBg = 'linear-gradient(135deg, #FFD54F 0%, #D4891A 100%)'
65
+
66
+ function iconStyle(item: FeatureItem) {
67
+ const color = item[props.colorKey]
68
+ return {
69
+ background: color || defaultBg,
70
+ }
71
+ }
72
+
73
+ function labelOf(item: FeatureItem) {
74
+ return item[props.labelKey] ?? ''
75
+ }
76
+
77
+ function iconOf(item: FeatureItem) {
78
+ return item[props.iconKey] ?? ''
79
+ }
80
+
81
+ function onItemClick(item: FeatureItem, index: number) {
82
+ emit('item-click', { item, index })
83
+ }
84
+ </script>
85
+
86
+ <style lang="scss" scoped>
87
+ @import '../../scss/variables';
88
+ @import '../../scss/mixins';
89
+
90
+ .dd-feature-grid {
91
+ display: grid;
92
+ grid-template-columns: repeat(4, 1fr);
93
+ row-gap: $dd-space-4;
94
+ column-gap: $dd-space-2;
95
+ }
96
+
97
+ .dd-feature-grid__item {
98
+ display: flex;
99
+ flex-direction: column;
100
+ align-items: center;
101
+ gap: $dd-space-2;
102
+ @include dd-transition(transform 0.15s ease);
103
+
104
+ &--press {
105
+ transform: scale(0.92);
106
+ }
107
+ }
108
+
109
+ .dd-feature-grid__icon {
110
+ width: 84rpx;
111
+ height: 84rpx;
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ background: $dd-gradient-primary-wide;
116
+ }
117
+
118
+ .dd-feature-grid__item--circle .dd-feature-grid__icon {
119
+ border-radius: 50%;
120
+ }
121
+
122
+ .dd-feature-grid__item--squircle .dd-feature-grid__icon {
123
+ border-radius: $dd-radius-xl;
124
+ }
125
+
126
+ .dd-feature-grid__icon-text {
127
+ font-size: $dd-font-size-h2;
128
+ color: $dd-neutral-900;
129
+ line-height: 1;
130
+ }
131
+
132
+ .dd-feature-grid__label {
133
+ font-size: $dd-font-size-caption;
134
+ color: $dd-text-secondary;
135
+ text-align: center;
136
+ @include dd-ellipsis(1);
137
+ max-width: 100%;
138
+ }
139
+ </style>
@@ -0,0 +1,240 @@
1
+ <template>
2
+ <view
3
+ class="dd-field"
4
+ :class="{
5
+ 'dd-field--error': errorState,
6
+ 'dd-field--disabled': disabled,
7
+ 'dd-field--borderless': borderless,
8
+ }"
9
+ >
10
+ <view class="dd-field__row">
11
+ <view v-if="label || $slots.label" class="dd-field__label">
12
+ <text v-if="required" class="dd-field__required">*</text>
13
+ <text class="dd-field__label-text"><slot name="label">{{ label }}</slot></text>
14
+ </view>
15
+ <view class="dd-field__body">
16
+ <textarea
17
+ v-if="type === 'textarea'"
18
+ class="dd-field__control dd-field__textarea"
19
+ :value="modelValue"
20
+ :placeholder="placeholder"
21
+ placeholder-style="color:#9E9E9E"
22
+ :disabled="disabled"
23
+ :maxlength="maxlength"
24
+ :auto-height="autosize"
25
+ :style="{ textAlign: inputAlign }"
26
+ @input="onInput"
27
+ @focus="onFocus"
28
+ @blur="onBlur"
29
+ @confirm="onConfirm"
30
+ />
31
+ <input
32
+ v-else
33
+ class="dd-field__control"
34
+ :type="inputType"
35
+ :password="isPassword"
36
+ :value="modelValue"
37
+ :placeholder="placeholder"
38
+ placeholder-style="color:#9E9E9E"
39
+ :disabled="disabled"
40
+ :maxlength="maxlength"
41
+ :style="{ textAlign: inputAlign }"
42
+ @input="onInput"
43
+ @focus="onFocus"
44
+ @blur="onBlur"
45
+ @confirm="onConfirm"
46
+ />
47
+ <view v-if="showClear" class="dd-field__clear" @click="onClear"><dd-icon name="cross" /></view>
48
+ </view>
49
+ </view>
50
+ <view v-if="errorMessage || showWordLimit" class="dd-field__footer">
51
+ <text v-if="errorMessage" class="dd-field__error">{{ errorMessage }}</text>
52
+ <text v-if="showWordLimit" class="dd-field__counter">{{ len }}/{{ maxlength }}</text>
53
+ </view>
54
+ </view>
55
+ </template>
56
+
57
+ <script setup lang="ts">
58
+ import { computed } from 'vue'
59
+ import DdIcon from '../dd-icon/dd-icon.vue'
60
+
61
+ interface Props {
62
+ modelValue?: string | number
63
+ type?: 'text' | 'textarea' | 'password' | 'number' | 'digit'
64
+ label?: string
65
+ placeholder?: string
66
+ disabled?: boolean
67
+ required?: boolean
68
+ borderless?: boolean
69
+ inputAlign?: 'left' | 'center' | 'right'
70
+ clearable?: boolean
71
+ maxlength?: number
72
+ showWordLimit?: boolean
73
+ autosize?: boolean
74
+ error?: boolean
75
+ errorMessage?: string
76
+ }
77
+
78
+ const props = withDefaults(defineProps<Props>(), {
79
+ modelValue: '',
80
+ type: 'text',
81
+ label: '',
82
+ placeholder: '',
83
+ disabled: false,
84
+ required: false,
85
+ borderless: false,
86
+ inputAlign: 'left',
87
+ clearable: false,
88
+ maxlength: -1,
89
+ showWordLimit: false,
90
+ autosize: false,
91
+ error: false,
92
+ errorMessage: '',
93
+ })
94
+
95
+ const emit = defineEmits<{
96
+ (e: 'update:modelValue', val: string): void
97
+ (e: 'focus', val: Event): void
98
+ (e: 'blur', val: Event): void
99
+ (e: 'clear'): void
100
+ (e: 'confirm', val: string): void
101
+ }>()
102
+
103
+ // ponytail: password 用 uni 原生 password 布尔属性跨端
104
+ const inputType = computed<'text' | 'number' | 'digit'>(() => {
105
+ if (props.type === 'password') return 'text'
106
+ if (props.type === 'text') return 'text'
107
+ return props.type as 'number' | 'digit'
108
+ })
109
+ const isPassword = computed(() => props.type === 'password')
110
+ const errorState = computed(() => props.error || !!props.errorMessage)
111
+ const showClear = computed(() => props.clearable && !!props.modelValue && !props.disabled)
112
+ const showWordLimit = computed(() => props.showWordLimit && props.maxlength > 0)
113
+ const len = computed(() => String(props.modelValue ?? '').length)
114
+
115
+ function onInput(e: any) {
116
+ emit('update:modelValue', e?.detail?.value ?? e?.target?.value ?? '')
117
+ }
118
+ function onFocus(e: Event) {
119
+ emit('focus', e)
120
+ }
121
+ function onBlur(e: Event) {
122
+ emit('blur', e)
123
+ }
124
+ function onConfirm(e: any) {
125
+ const v = e?.detail?.value ?? e?.target?.value ?? ''
126
+ emit('confirm', v)
127
+ }
128
+ function onClear() {
129
+ emit('update:modelValue', '')
130
+ emit('clear')
131
+ }
132
+ </script>
133
+
134
+ <style lang="scss" scoped>
135
+ @import '../../scss/variables';
136
+ @import '../../scss/mixins';
137
+
138
+ .dd-field {
139
+ background: transparent;
140
+ padding: 16rpx 24rpx 0 32rpx;
141
+ box-sizing: border-box;
142
+ @include dd-hairline-bottom($dd-border-subtle);
143
+
144
+ &__row {
145
+ display: flex;
146
+ align-items: flex-start;
147
+ min-height: 112rpx;
148
+ }
149
+
150
+ &__label {
151
+ display: flex;
152
+ align-items: center;
153
+ flex-shrink: 0;
154
+ width: 6.2em;
155
+ min-height: 56rpx;
156
+ font-size: 28rpx;
157
+ color: $dd-text-secondary;
158
+ }
159
+ &__required {
160
+ color: $dd-error-500;
161
+ margin-right: 4rpx;
162
+ }
163
+ &__label-text {
164
+ @include dd-ellipsis(1);
165
+ }
166
+
167
+ &__body {
168
+ flex: 1;
169
+ min-width: 0;
170
+ display: flex;
171
+ align-items: center;
172
+ }
173
+
174
+ &__control {
175
+ flex: 1;
176
+ min-width: 0;
177
+ font-size: 28rpx;
178
+ color: $dd-text-primary;
179
+ background: transparent;
180
+ border: none;
181
+ }
182
+ &__textarea {
183
+ padding: 16rpx 0;
184
+ min-height: 60rpx;
185
+ line-height: 1.5;
186
+ }
187
+
188
+ &__clear {
189
+ @include dd-flex-center;
190
+ flex-shrink: 0;
191
+ width: 36rpx;
192
+ height: 36rpx;
193
+ margin-left: 16rpx;
194
+ border-radius: $dd-radius-full;
195
+ background: $dd-neutral-800;
196
+ color: $dd-text-secondary;
197
+ font-size: 24rpx;
198
+ line-height: 1;
199
+ }
200
+
201
+ &__footer {
202
+ display: flex;
203
+ align-items: center;
204
+ justify-content: flex-end;
205
+ min-height: 40rpx;
206
+ padding-bottom: 8rpx;
207
+ }
208
+ &__error {
209
+ flex: 1;
210
+ font-size: 24rpx;
211
+ color: $dd-error-500;
212
+ @include dd-ellipsis(1);
213
+ }
214
+ &__counter {
215
+ flex-shrink: 0;
216
+ font-size: 24rpx;
217
+ color: $dd-text-tertiary;
218
+ }
219
+
220
+ &--error {
221
+ .dd-field__control {
222
+ color: $dd-error-500;
223
+ }
224
+ .dd-field__label-text {
225
+ color: $dd-error-500;
226
+ }
227
+ }
228
+
229
+ &--disabled {
230
+ opacity: 0.5;
231
+ @include dd-no-touch;
232
+ }
233
+
234
+ &--borderless {
235
+ &::after {
236
+ display: none;
237
+ }
238
+ }
239
+ }
240
+ </style>