@atooyu/uxto-ui 1.0.7 → 1.0.9

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.
@@ -1,117 +1,117 @@
1
- <template>
2
- <view class="u-read-more">
3
- <view
4
- class="u-read-more__content"
5
- :style="contentStyle"
6
- >
7
- <slot />
8
- </view>
9
- <view
10
- v-if="showToggle"
11
- class="u-read-more__toggle"
12
- @click="handleToggle"
13
- >
14
- <text class="u-read-more__toggle-text">{{ toggleText }}</text>
15
- <text class="u-read-more__toggle-icon">{{ expanded ? '↑' : '↓' }}</text>
16
- </view>
17
- </view>
18
- </template>
19
-
20
- <script setup lang="ts">
21
- import { computed, ref, watch } from 'vue'
22
-
23
- interface Props {
24
- maxLength?: number
25
- rows?: number
26
- expandText?: string
27
- collapseText?: string
28
- autoCollapse?: boolean
29
- }
30
-
31
- const props = withDefaults(defineProps<Props>(), {
32
- maxLength: 200,
33
- rows: 3,
34
- expandText: '展开',
35
- collapseText: '收起',
36
- autoCollapse: false
37
- })
38
-
39
- const emit = defineEmits<{
40
- (e: 'expand'): void
41
- (e: 'collapse'): void
42
- }>()
43
-
44
- const expanded = ref(false)
45
- const showToggle = ref(true)
46
-
47
- // 内容区域样式
48
- const contentStyle = computed(() => {
49
- if (expanded.value) {
50
- return {}
51
- }
52
- // 使用 line-clamp 限制行数
53
- return {
54
- display: '-webkit-box',
55
- overflow: 'hidden',
56
- textOverflow: 'ellipsis',
57
- webkitLineClamp: String(props.rows),
58
- webkitBoxOrient: 'vertical'
59
- }
60
- })
61
-
62
- // 切换按钮文字
63
- const toggleText = computed(() => {
64
- return expanded.value ? props.collapseText : props.expandText
65
- })
66
-
67
- // 切换展开/收起
68
- const handleToggle = () => {
69
- expanded.value = !expanded.value
70
-
71
- if (expanded.value) {
72
- emit('expand')
73
- } else {
74
- emit('collapse')
75
- }
76
- }
77
- </script>
78
-
79
- <script lang="ts">
80
- export default {
81
- options: {
82
- virtualHost: true,
83
- styleIsolation: 'shared'
84
- }
85
- }
86
- </script>
87
-
88
- <style lang="scss" scoped>
89
- .u-read-more {
90
- &__content {
91
- font-size: $--font-size-md;
92
- color: $--text-color;
93
- line-height: 1.6;
94
- word-break: break-all;
95
- }
96
-
97
- &__toggle {
98
- display: inline-flex;
99
- align-items: center;
100
- margin-top: $--spacing-sm;
101
- color: $--color-primary;
102
- font-size: $--font-size-md;
103
-
104
- &:active {
105
- opacity: 0.7;
106
- }
107
- }
108
-
109
- &__toggle-text {
110
- margin-right: $--spacing-xs;
111
- }
112
-
113
- &__toggle-icon {
114
- font-size: $--font-size-sm;
115
- }
116
- }
1
+ <template>
2
+ <view class="u-read-more">
3
+ <view
4
+ class="u-read-more__content"
5
+ :style="contentStyle"
6
+ >
7
+ <slot />
8
+ </view>
9
+ <view
10
+ v-if="showToggle"
11
+ class="u-read-more__toggle"
12
+ @click="handleToggle"
13
+ >
14
+ <text class="u-read-more__toggle-text">{{ toggleText }}</text>
15
+ <text class="u-read-more__toggle-icon">{{ expanded ? '↑' : '↓' }}</text>
16
+ </view>
17
+ </view>
18
+ </template>
19
+
20
+ <script setup lang="ts">
21
+ import { computed, ref, watch } from 'vue'
22
+
23
+ interface Props {
24
+ maxLength?: number
25
+ rows?: number
26
+ expandText?: string
27
+ collapseText?: string
28
+ autoCollapse?: boolean
29
+ }
30
+
31
+ const props = withDefaults(defineProps<Props>(), {
32
+ maxLength: 200,
33
+ rows: 3,
34
+ expandText: '展开',
35
+ collapseText: '收起',
36
+ autoCollapse: false
37
+ })
38
+
39
+ const emit = defineEmits<{
40
+ (e: 'expand'): void
41
+ (e: 'collapse'): void
42
+ }>()
43
+
44
+ const expanded = ref(false)
45
+ const showToggle = ref(true)
46
+
47
+ // 内容区域样式
48
+ const contentStyle = computed(() => {
49
+ if (expanded.value) {
50
+ return {}
51
+ }
52
+ // 使用 line-clamp 限制行数
53
+ return {
54
+ display: '-webkit-box',
55
+ overflow: 'hidden',
56
+ textOverflow: 'ellipsis',
57
+ webkitLineClamp: String(props.rows),
58
+ webkitBoxOrient: 'vertical'
59
+ }
60
+ })
61
+
62
+ // 切换按钮文字
63
+ const toggleText = computed(() => {
64
+ return expanded.value ? props.collapseText : props.expandText
65
+ })
66
+
67
+ // 切换展开/收起
68
+ const handleToggle = () => {
69
+ expanded.value = !expanded.value
70
+
71
+ if (expanded.value) {
72
+ emit('expand')
73
+ } else {
74
+ emit('collapse')
75
+ }
76
+ }
77
+ </script>
78
+
79
+ <script lang="ts">
80
+ export default {
81
+ options: {
82
+ virtualHost: true,
83
+ styleIsolation: 'shared'
84
+ }
85
+ }
86
+ </script>
87
+
88
+ <style lang="scss" scoped>
89
+ .u-read-more {
90
+ &__content {
91
+ font-size: $--font-size-md;
92
+ color: $--text-color;
93
+ line-height: 1.6;
94
+ word-break: break-all;
95
+ }
96
+
97
+ &__toggle {
98
+ display: inline-flex;
99
+ align-items: center;
100
+ margin-top: $--spacing-sm;
101
+ color: $--color-primary;
102
+ font-size: $--font-size-md;
103
+
104
+ &:active {
105
+ opacity: 0.7;
106
+ }
107
+ }
108
+
109
+ &__toggle-text {
110
+ margin-right: $--spacing-xs;
111
+ }
112
+
113
+ &__toggle-icon {
114
+ font-size: $--font-size-sm;
115
+ }
116
+ }
117
117
  </style>
@@ -1,192 +1,192 @@
1
- <template>
2
- <view v-if="!loading" class="u-skeleton__content">
3
- <slot />
4
- </view>
5
- <view v-else class="u-skeleton" :class="{ 'u-skeleton--animate': animate }">
6
- <!-- 头像骨架 -->
7
- <view
8
- v-if="avatar"
9
- class="u-skeleton__avatar"
10
- :class="`u-skeleton__avatar--${avatarShape}`"
11
- :style="avatarStyle"
12
- />
13
- <!-- 内容区域 -->
14
- <view class="u-skeleton__content">
15
- <!-- 标题骨架 -->
16
- <view
17
- v-if="title"
18
- class="u-skeleton__title"
19
- :style="titleStyle"
20
- />
21
- <!-- 段落骨架 -->
22
- <view class="u-skeleton__paragraphs">
23
- <view
24
- v-for="(row, index) in rowList"
25
- :key="index"
26
- class="u-skeleton__paragraph"
27
- :style="getRowStyle(index)"
28
- />
29
- </view>
30
- </view>
31
- </view>
32
- </template>
33
-
34
- <script setup lang="ts">
35
- import { computed } from 'vue'
36
-
37
- type AvatarShape = 'circle' | 'square'
38
- type TitleWidth = number | string
39
-
40
- interface Props {
41
- loading?: boolean
42
- animate?: boolean
43
- avatar?: boolean
44
- avatarSize?: number | string
45
- avatarShape?: AvatarShape
46
- title?: boolean
47
- titleWidth?: TitleWidth
48
- row?: number
49
- rowWidth?: number | string | (number | string)[]
50
- rowHeight?: number | string | (number | string)[]
51
- }
52
-
53
- const props = withDefaults(defineProps<Props>(), {
54
- loading: true,
55
- animate: true,
56
- avatar: false,
57
- avatarSize: 40,
58
- avatarShape: 'circle',
59
- title: true,
60
- titleWidth: '40%',
61
- row: 3,
62
- rowWidth: '100%',
63
- rowHeight: 16
64
- })
65
-
66
- const avatarStyle = computed(() => {
67
- const size = typeof props.avatarSize === 'number'
68
- ? `${props.avatarSize}px`
69
- : props.avatarSize
70
- return {
71
- width: size,
72
- height: size
73
- }
74
- })
75
-
76
- const titleStyle = computed(() => {
77
- const width = typeof props.titleWidth === 'number'
78
- ? `${props.titleWidth}px`
79
- : props.titleWidth
80
- return { width }
81
- })
82
-
83
- const rowList = computed(() => {
84
- return Array.from({ length: props.row }, (_, i) => i)
85
- })
86
-
87
- const getRowStyle = (index: number) => {
88
- const style: Record<string, string> = {}
89
-
90
- // 处理宽度
91
- if (Array.isArray(props.rowWidth)) {
92
- const width = props.rowWidth[index]
93
- if (width !== undefined) {
94
- style.width = typeof width === 'number' ? `${width}px` : width
95
- }
96
- } else if (index === props.row - 1 && props.rowWidth === '100%') {
97
- // 最后一行默认 60% 宽度(如果是 100% 才处理)
98
- style.width = '60%'
99
- } else {
100
- style.width = typeof props.rowWidth === 'number'
101
- ? `${props.rowWidth}px`
102
- : props.rowWidth
103
- }
104
-
105
- // 处理高度
106
- if (Array.isArray(props.rowHeight)) {
107
- const height = props.rowHeight[index]
108
- if (height !== undefined) {
109
- style.height = typeof height === 'number' ? `${height}px` : height
110
- }
111
- } else {
112
- style.height = typeof props.rowHeight === 'number'
113
- ? `${props.rowHeight}px`
114
- : props.rowHeight
115
- }
116
-
117
- return style
118
- }
119
- </script>
120
-
121
- <script lang="ts">
122
- export default {
123
- options: {
124
- virtualHost: true,
125
- styleIsolation: 'shared'
126
- }
127
- }
128
- </script>
129
-
130
- <style lang="scss" scoped>
131
- .u-skeleton {
132
- display: flex;
133
- gap: $--spacing-md;
134
-
135
- &--animate {
136
- .u-skeleton__avatar,
137
- .u-skeleton__title,
138
- .u-skeleton__paragraph {
139
- animation: skeleton-blink 1.2s ease-in-out infinite;
140
- }
141
- }
142
-
143
- &__avatar {
144
- flex-shrink: 0;
145
- background-color: $--bg-color-3;
146
- border-radius: 50%;
147
-
148
- &--circle {
149
- border-radius: 50%;
150
- }
151
-
152
- &--square {
153
- border-radius: $--radius-sm;
154
- }
155
- }
156
-
157
- &__content {
158
- flex: 1;
159
- min-width: 0;
160
- }
161
-
162
- &__title {
163
- height: 20px;
164
- margin-bottom: $--spacing-md;
165
- background-color: $--bg-color-3;
166
- border-radius: $--radius-sm;
167
- }
168
-
169
- &__paragraphs {
170
- display: flex;
171
- flex-direction: column;
172
- gap: $--spacing-sm;
173
- }
174
-
175
- &__paragraph {
176
- background-color: $--bg-color-3;
177
- border-radius: $--radius-sm;
178
- }
179
- }
180
-
181
- @keyframes skeleton-blink {
182
- 0% {
183
- opacity: 1;
184
- }
185
- 50% {
186
- opacity: 0.5;
187
- }
188
- 100% {
189
- opacity: 1;
190
- }
191
- }
1
+ <template>
2
+ <view v-if="!loading" class="u-skeleton__content">
3
+ <slot />
4
+ </view>
5
+ <view v-else class="u-skeleton" :class="{ 'u-skeleton--animate': animate }">
6
+ <!-- 头像骨架 -->
7
+ <view
8
+ v-if="avatar"
9
+ class="u-skeleton__avatar"
10
+ :class="`u-skeleton__avatar--${avatarShape}`"
11
+ :style="avatarStyle"
12
+ />
13
+ <!-- 内容区域 -->
14
+ <view class="u-skeleton__content">
15
+ <!-- 标题骨架 -->
16
+ <view
17
+ v-if="title"
18
+ class="u-skeleton__title"
19
+ :style="titleStyle"
20
+ />
21
+ <!-- 段落骨架 -->
22
+ <view class="u-skeleton__paragraphs">
23
+ <view
24
+ v-for="(row, index) in rowList"
25
+ :key="index"
26
+ class="u-skeleton__paragraph"
27
+ :style="getRowStyle(index)"
28
+ />
29
+ </view>
30
+ </view>
31
+ </view>
32
+ </template>
33
+
34
+ <script setup lang="ts">
35
+ import { computed } from 'vue'
36
+
37
+ type AvatarShape = 'circle' | 'square'
38
+ type TitleWidth = number | string
39
+
40
+ interface Props {
41
+ loading?: boolean
42
+ animate?: boolean
43
+ avatar?: boolean
44
+ avatarSize?: number | string
45
+ avatarShape?: AvatarShape
46
+ title?: boolean
47
+ titleWidth?: TitleWidth
48
+ row?: number
49
+ rowWidth?: number | string | (number | string)[]
50
+ rowHeight?: number | string | (number | string)[]
51
+ }
52
+
53
+ const props = withDefaults(defineProps<Props>(), {
54
+ loading: true,
55
+ animate: true,
56
+ avatar: false,
57
+ avatarSize: 40,
58
+ avatarShape: 'circle',
59
+ title: true,
60
+ titleWidth: '40%',
61
+ row: 3,
62
+ rowWidth: '100%',
63
+ rowHeight: 16
64
+ })
65
+
66
+ const avatarStyle = computed(() => {
67
+ const size = typeof props.avatarSize === 'number'
68
+ ? `${props.avatarSize}px`
69
+ : props.avatarSize
70
+ return {
71
+ width: size,
72
+ height: size
73
+ }
74
+ })
75
+
76
+ const titleStyle = computed(() => {
77
+ const width = typeof props.titleWidth === 'number'
78
+ ? `${props.titleWidth}px`
79
+ : props.titleWidth
80
+ return { width }
81
+ })
82
+
83
+ const rowList = computed(() => {
84
+ return Array.from({ length: props.row }, (_, i) => i)
85
+ })
86
+
87
+ const getRowStyle = (index: number) => {
88
+ const style: Record<string, string> = {}
89
+
90
+ // 处理宽度
91
+ if (Array.isArray(props.rowWidth)) {
92
+ const width = props.rowWidth[index]
93
+ if (width !== undefined) {
94
+ style.width = typeof width === 'number' ? `${width}px` : width
95
+ }
96
+ } else if (index === props.row - 1 && props.rowWidth === '100%') {
97
+ // 最后一行默认 60% 宽度(如果是 100% 才处理)
98
+ style.width = '60%'
99
+ } else {
100
+ style.width = typeof props.rowWidth === 'number'
101
+ ? `${props.rowWidth}px`
102
+ : props.rowWidth
103
+ }
104
+
105
+ // 处理高度
106
+ if (Array.isArray(props.rowHeight)) {
107
+ const height = props.rowHeight[index]
108
+ if (height !== undefined) {
109
+ style.height = typeof height === 'number' ? `${height}px` : height
110
+ }
111
+ } else {
112
+ style.height = typeof props.rowHeight === 'number'
113
+ ? `${props.rowHeight}px`
114
+ : props.rowHeight
115
+ }
116
+
117
+ return style
118
+ }
119
+ </script>
120
+
121
+ <script lang="ts">
122
+ export default {
123
+ options: {
124
+ virtualHost: true,
125
+ styleIsolation: 'shared'
126
+ }
127
+ }
128
+ </script>
129
+
130
+ <style lang="scss" scoped>
131
+ .u-skeleton {
132
+ display: flex;
133
+ gap: $--spacing-md;
134
+
135
+ &--animate {
136
+ .u-skeleton__avatar,
137
+ .u-skeleton__title,
138
+ .u-skeleton__paragraph {
139
+ animation: skeleton-blink 1.2s ease-in-out infinite;
140
+ }
141
+ }
142
+
143
+ &__avatar {
144
+ flex-shrink: 0;
145
+ background-color: $--bg-color-3;
146
+ border-radius: 50%;
147
+
148
+ &--circle {
149
+ border-radius: 50%;
150
+ }
151
+
152
+ &--square {
153
+ border-radius: $--radius-sm;
154
+ }
155
+ }
156
+
157
+ &__content {
158
+ flex: 1;
159
+ min-width: 0;
160
+ }
161
+
162
+ &__title {
163
+ height: 20px;
164
+ margin-bottom: $--spacing-md;
165
+ background-color: $--bg-color-3;
166
+ border-radius: $--radius-sm;
167
+ }
168
+
169
+ &__paragraphs {
170
+ display: flex;
171
+ flex-direction: column;
172
+ gap: $--spacing-sm;
173
+ }
174
+
175
+ &__paragraph {
176
+ background-color: $--bg-color-3;
177
+ border-radius: $--radius-sm;
178
+ }
179
+ }
180
+
181
+ @keyframes skeleton-blink {
182
+ 0% {
183
+ opacity: 1;
184
+ }
185
+ 50% {
186
+ opacity: 0.5;
187
+ }
188
+ 100% {
189
+ opacity: 1;
190
+ }
191
+ }
192
192
  </style>
@@ -29,10 +29,10 @@
29
29
  :class="{ 'u-tabbar__center-btn--active': modelValue === centerTab.value }"
30
30
  @click="switchTab(centerTab.value)"
31
31
  >
32
- <text class="u-tabbar__center-brand" :style="{ color: modelValue === centerTab.value ? activeColor : '#ffffff' }">
32
+ <text class="u-tabbar__center-brand">
33
33
  {{ centerBrand }}
34
34
  </text>
35
- <text class="u-tabbar__center-text" :style="{ color: modelValue === centerTab.value ? activeColor : '#ffffff' }">
35
+ <text class="u-tabbar__center-text">
36
36
  {{ centerLabel }}
37
37
  </text>
38
38
  </view>
@@ -166,7 +166,6 @@ $--paper: #ffffff;
166
166
 
167
167
  // Tab按钮
168
168
  &__tab-btn {
169
- flex: 1;
170
169
  height: 40px;
171
170
  border-radius: 20px;
172
171
  background: transparent;
@@ -178,7 +177,7 @@ $--paper: #ffffff;
178
177
  transition: all 200ms ease;
179
178
  white-space: nowrap;
180
179
  overflow: hidden;
181
- min-width: 0;
180
+ padding: 0 16px;
182
181
 
183
182
  &--active {
184
183
  background: $--paper;