@coffic/cosy-ui 0.8.23 → 0.8.25

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.
@@ -46,6 +46,7 @@ export * from './src-astro/theme-switcher';
46
46
  export * from './src-astro/toc';
47
47
  export * from './src-astro/toast';
48
48
  export * from './src-astro/confirm-dialog';
49
+ export * from './src-astro/list';
49
50
 
50
51
  // 类型定义 (按字母顺序)
51
52
  export * from './src-astro/types/article';
@@ -114,29 +114,283 @@ const {
114
114
  ...rest
115
115
  } = Astro.props;
116
116
 
117
- // 处理响应式列数
117
+ // 处理响应式列数(所有 class 必须静态字符串,不能拼接)
118
118
  const getColsClasses = (cols: ResponsiveValue<number>) => {
119
+ // 单一数字
119
120
  if (typeof cols === 'number') {
120
- return `cosy:grid-cols-${cols}`;
121
+ switch (cols) {
122
+ case 1:
123
+ return 'cosy:grid-cols-1';
124
+ case 2:
125
+ return 'cosy:grid-cols-2';
126
+ case 3:
127
+ return 'cosy:grid-cols-3';
128
+ case 4:
129
+ return 'cosy:grid-cols-4';
130
+ case 5:
131
+ return 'cosy:grid-cols-5';
132
+ case 6:
133
+ return 'cosy:grid-cols-6';
134
+ case 7:
135
+ return 'cosy:grid-cols-7';
136
+ case 8:
137
+ return 'cosy:grid-cols-8';
138
+ case 9:
139
+ return 'cosy:grid-cols-9';
140
+ case 10:
141
+ return 'cosy:grid-cols-10';
142
+ case 11:
143
+ return 'cosy:grid-cols-11';
144
+ case 12:
145
+ return 'cosy:grid-cols-12';
146
+ default:
147
+ return '';
148
+ }
121
149
  }
122
-
123
- const breakpoints: Record<Breakpoint, string> = {
124
- base: '',
125
- sm: 'sm:',
126
- md: 'md:',
127
- lg: 'lg:',
128
- xl: 'xl:',
129
- '2xl': '2xl:',
130
- };
131
-
132
- return Object.entries(cols)
133
- .map(([breakpoint, value]) => {
134
- if (breakpoint === 'base') {
135
- return `cosy:grid-cols-${value}`;
136
- }
137
- return `cosy:${breakpoints[breakpoint as Breakpoint]}grid-cols-${value}`;
138
- })
139
- .join(' ');
150
+ // 响应式对象
151
+ let result: string[] = [];
152
+ const responsive = cols as any;
153
+ if (responsive.base) {
154
+ switch (responsive.base) {
155
+ case 1:
156
+ result.push('cosy:grid-cols-1');
157
+ break;
158
+ case 2:
159
+ result.push('cosy:grid-cols-2');
160
+ break;
161
+ case 3:
162
+ result.push('cosy:grid-cols-3');
163
+ break;
164
+ case 4:
165
+ result.push('cosy:grid-cols-4');
166
+ break;
167
+ case 5:
168
+ result.push('cosy:grid-cols-5');
169
+ break;
170
+ case 6:
171
+ result.push('cosy:grid-cols-6');
172
+ break;
173
+ case 7:
174
+ result.push('cosy:grid-cols-7');
175
+ break;
176
+ case 8:
177
+ result.push('cosy:grid-cols-8');
178
+ break;
179
+ case 9:
180
+ result.push('cosy:grid-cols-9');
181
+ break;
182
+ case 10:
183
+ result.push('cosy:grid-cols-10');
184
+ break;
185
+ case 11:
186
+ result.push('cosy:grid-cols-11');
187
+ break;
188
+ case 12:
189
+ result.push('cosy:grid-cols-12');
190
+ break;
191
+ }
192
+ }
193
+ if (responsive.sm) {
194
+ switch (responsive.sm) {
195
+ case 1:
196
+ result.push('cosy:sm:grid-cols-1');
197
+ break;
198
+ case 2:
199
+ result.push('cosy:sm:grid-cols-2');
200
+ break;
201
+ case 3:
202
+ result.push('cosy:sm:grid-cols-3');
203
+ break;
204
+ case 4:
205
+ result.push('cosy:sm:grid-cols-4');
206
+ break;
207
+ case 5:
208
+ result.push('cosy:sm:grid-cols-5');
209
+ break;
210
+ case 6:
211
+ result.push('cosy:sm:grid-cols-6');
212
+ break;
213
+ case 7:
214
+ result.push('cosy:sm:grid-cols-7');
215
+ break;
216
+ case 8:
217
+ result.push('cosy:sm:grid-cols-8');
218
+ break;
219
+ case 9:
220
+ result.push('cosy:sm:grid-cols-9');
221
+ break;
222
+ case 10:
223
+ result.push('cosy:sm:grid-cols-10');
224
+ break;
225
+ case 11:
226
+ result.push('cosy:sm:grid-cols-11');
227
+ break;
228
+ case 12:
229
+ result.push('cosy:sm:grid-cols-12');
230
+ break;
231
+ }
232
+ }
233
+ if (responsive.md) {
234
+ switch (responsive.md) {
235
+ case 1:
236
+ result.push('cosy:md:grid-cols-1');
237
+ break;
238
+ case 2:
239
+ result.push('cosy:md:grid-cols-2');
240
+ break;
241
+ case 3:
242
+ result.push('cosy:md:grid-cols-3');
243
+ break;
244
+ case 4:
245
+ result.push('cosy:md:grid-cols-4');
246
+ break;
247
+ case 5:
248
+ result.push('cosy:md:grid-cols-5');
249
+ break;
250
+ case 6:
251
+ result.push('cosy:md:grid-cols-6');
252
+ break;
253
+ case 7:
254
+ result.push('cosy:md:grid-cols-7');
255
+ break;
256
+ case 8:
257
+ result.push('cosy:md:grid-cols-8');
258
+ break;
259
+ case 9:
260
+ result.push('cosy:md:grid-cols-9');
261
+ break;
262
+ case 10:
263
+ result.push('cosy:md:grid-cols-10');
264
+ break;
265
+ case 11:
266
+ result.push('cosy:md:grid-cols-11');
267
+ break;
268
+ case 12:
269
+ result.push('cosy:md:grid-cols-12');
270
+ break;
271
+ }
272
+ }
273
+ if (responsive.lg) {
274
+ switch (responsive.lg) {
275
+ case 1:
276
+ result.push('cosy:lg:grid-cols-1');
277
+ break;
278
+ case 2:
279
+ result.push('cosy:lg:grid-cols-2');
280
+ break;
281
+ case 3:
282
+ result.push('cosy:lg:grid-cols-3');
283
+ break;
284
+ case 4:
285
+ result.push('cosy:lg:grid-cols-4');
286
+ break;
287
+ case 5:
288
+ result.push('cosy:lg:grid-cols-5');
289
+ break;
290
+ case 6:
291
+ result.push('cosy:lg:grid-cols-6');
292
+ break;
293
+ case 7:
294
+ result.push('cosy:lg:grid-cols-7');
295
+ break;
296
+ case 8:
297
+ result.push('cosy:lg:grid-cols-8');
298
+ break;
299
+ case 9:
300
+ result.push('cosy:lg:grid-cols-9');
301
+ break;
302
+ case 10:
303
+ result.push('cosy:lg:grid-cols-10');
304
+ break;
305
+ case 11:
306
+ result.push('cosy:lg:grid-cols-11');
307
+ break;
308
+ case 12:
309
+ result.push('cosy:lg:grid-cols-12');
310
+ break;
311
+ }
312
+ }
313
+ if (responsive.xl) {
314
+ switch (responsive.xl) {
315
+ case 1:
316
+ result.push('cosy:xl:grid-cols-1');
317
+ break;
318
+ case 2:
319
+ result.push('cosy:xl:grid-cols-2');
320
+ break;
321
+ case 3:
322
+ result.push('cosy:xl:grid-cols-3');
323
+ break;
324
+ case 4:
325
+ result.push('cosy:xl:grid-cols-4');
326
+ break;
327
+ case 5:
328
+ result.push('cosy:xl:grid-cols-5');
329
+ break;
330
+ case 6:
331
+ result.push('cosy:xl:grid-cols-6');
332
+ break;
333
+ case 7:
334
+ result.push('cosy:xl:grid-cols-7');
335
+ break;
336
+ case 8:
337
+ result.push('cosy:xl:grid-cols-8');
338
+ break;
339
+ case 9:
340
+ result.push('cosy:xl:grid-cols-9');
341
+ break;
342
+ case 10:
343
+ result.push('cosy:xl:grid-cols-10');
344
+ break;
345
+ case 11:
346
+ result.push('cosy:xl:grid-cols-11');
347
+ break;
348
+ case 12:
349
+ result.push('cosy:xl:grid-cols-12');
350
+ break;
351
+ }
352
+ }
353
+ if (responsive['2xl']) {
354
+ switch (responsive['2xl']) {
355
+ case 1:
356
+ result.push('cosy:2xl:grid-cols-1');
357
+ break;
358
+ case 2:
359
+ result.push('cosy:2xl:grid-cols-2');
360
+ break;
361
+ case 3:
362
+ result.push('cosy:2xl:grid-cols-3');
363
+ break;
364
+ case 4:
365
+ result.push('cosy:2xl:grid-cols-4');
366
+ break;
367
+ case 5:
368
+ result.push('cosy:2xl:grid-cols-5');
369
+ break;
370
+ case 6:
371
+ result.push('cosy:2xl:grid-cols-6');
372
+ break;
373
+ case 7:
374
+ result.push('cosy:2xl:grid-cols-7');
375
+ break;
376
+ case 8:
377
+ result.push('cosy:2xl:grid-cols-8');
378
+ break;
379
+ case 9:
380
+ result.push('cosy:2xl:grid-cols-9');
381
+ break;
382
+ case 10:
383
+ result.push('cosy:2xl:grid-cols-10');
384
+ break;
385
+ case 11:
386
+ result.push('cosy:2xl:grid-cols-11');
387
+ break;
388
+ case 12:
389
+ result.push('cosy:2xl:grid-cols-12');
390
+ break;
391
+ }
392
+ }
393
+ return result.join(' ');
140
394
  };
141
395
 
142
396
  // 间距映射
@@ -0,0 +1,71 @@
1
+ ---
2
+ /**
3
+ * @component ListItem
4
+ * @description List item component with loading animations
5
+ * @props loading?: boolean
6
+ * @props duration?: number
7
+ * @props animationType?: string
8
+ */
9
+ import '../../style.ts';
10
+ import ListItemRing from './ListItemRing.astro';
11
+ import ListItemIconLeft from './ListItemIconLeft.astro';
12
+ import ListItemIconRight from './ListItemIconRight.astro';
13
+ import ListItemBreath from './ListItemBreath.astro';
14
+ import ListItemPulse from './ListItemPulse.astro';
15
+ import ListItemGlow from './ListItemGlow.astro';
16
+
17
+ const {
18
+ loading = false,
19
+ duration,
20
+ animationType = 'ring',
21
+ ...restProps
22
+ } = Astro.props;
23
+ ---
24
+
25
+ {
26
+ animationType === 'ring' && (
27
+ <ListItemRing loading={loading} duration={duration} {...restProps}>
28
+ <slot />
29
+ </ListItemRing>
30
+ )
31
+ }
32
+
33
+ {
34
+ animationType === 'icon-left' && (
35
+ <ListItemIconLeft loading={loading} duration={duration} {...restProps}>
36
+ <slot />
37
+ </ListItemIconLeft>
38
+ )
39
+ }
40
+
41
+ {
42
+ animationType === 'icon-right' && (
43
+ <ListItemIconRight loading={loading} duration={duration} {...restProps}>
44
+ <slot />
45
+ </ListItemIconRight>
46
+ )
47
+ }
48
+
49
+ {
50
+ animationType === 'breath' && (
51
+ <ListItemBreath loading={loading} duration={duration} {...restProps}>
52
+ <slot />
53
+ </ListItemBreath>
54
+ )
55
+ }
56
+
57
+ {
58
+ animationType === 'pulse' && (
59
+ <ListItemPulse loading={loading} duration={duration} {...restProps}>
60
+ <slot />
61
+ </ListItemPulse>
62
+ )
63
+ }
64
+
65
+ {
66
+ animationType === 'glow' && (
67
+ <ListItemGlow loading={loading} duration={duration} {...restProps}>
68
+ <slot />
69
+ </ListItemGlow>
70
+ )
71
+ }
@@ -0,0 +1,60 @@
1
+ ---
2
+ /**
3
+ * @component ListItemBreath
4
+ * @description ListItem 背景呼吸动画子组件
5
+ */
6
+ import '../../style.ts';
7
+ const { loading = false, duration } = Astro.props;
8
+ ---
9
+
10
+ <li
11
+ class:list={[
12
+ 'cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden',
13
+ loading && !duration ? 'breath-anim' : '',
14
+ ]}
15
+ {...Astro.props}>
16
+ {
17
+ loading && duration && (
18
+ <div
19
+ class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
20
+ style={`animation-duration: ${duration}ms;`}
21
+ />
22
+ )
23
+ }
24
+ <div
25
+ class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3">
26
+ <slot />
27
+ </div>
28
+ </li>
29
+
30
+ <style scoped>
31
+ /* 背景色呼吸动画 */
32
+ @keyframes breath {
33
+ 0%,
34
+ 100% {
35
+ background-color: rgb(55 65 81); /* base-300 等效颜色 */
36
+ }
37
+ 50% {
38
+ background-color: rgb(139 92 246 / 0.3); /* accent 色彩 */
39
+ }
40
+ }
41
+ .breath-anim {
42
+ animation: breath 2s ease-in-out infinite;
43
+ background-color: rgb(55 65 81); /* 确保有初始背景色 */
44
+ }
45
+
46
+ /* 进度条动画 */
47
+ .loading-bar {
48
+ width: 0%;
49
+ height: 100%;
50
+ animation: loading-bar-anim linear forwards;
51
+ }
52
+ @keyframes loading-bar-anim {
53
+ 0% {
54
+ width: 0%;
55
+ }
56
+ 100% {
57
+ width: 100%;
58
+ }
59
+ }
60
+ </style>
@@ -0,0 +1,65 @@
1
+ ---
2
+ /**
3
+ * @component ListItemGlow
4
+ * @description ListItem 发光边框动画子组件
5
+ */
6
+ import '../../style.ts';
7
+ const { loading = false, duration } = Astro.props;
8
+ ---
9
+
10
+ <li
11
+ class:list={[
12
+ 'cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden',
13
+ loading && !duration ? 'glow-anim' : '',
14
+ ]}
15
+ {...Astro.props}>
16
+ {
17
+ loading && duration && (
18
+ <div
19
+ class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
20
+ style={`animation-duration: ${duration}ms;`}
21
+ />
22
+ )
23
+ }
24
+ <div
25
+ class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3">
26
+ <slot />
27
+ </div>
28
+ </li>
29
+
30
+ <style scoped>
31
+ /* 发光边框动画 */
32
+ @keyframes glow {
33
+ 0%,
34
+ 100% {
35
+ border: 1px solid rgb(139 92 246 / 0.3);
36
+ box-shadow: 0 0 5px rgb(139 92 246 / 0.3);
37
+ }
38
+ 50% {
39
+ border: 1px solid rgb(139 92 246 / 0.8);
40
+ box-shadow:
41
+ 0 0 20px rgb(139 92 246 / 0.6),
42
+ 0 0 30px rgb(139 92 246 / 0.4),
43
+ inset 0 0 10px rgb(139 92 246 / 0.2);
44
+ }
45
+ }
46
+ .glow-anim {
47
+ animation: glow 2s ease-in-out infinite;
48
+ border: 1px solid rgb(139 92 246 / 0.3); /* 确保有初始边框 */
49
+ }
50
+
51
+ /* 进度条动画 */
52
+ .loading-bar {
53
+ width: 0%;
54
+ height: 100%;
55
+ animation: loading-bar-anim linear forwards;
56
+ }
57
+ @keyframes loading-bar-anim {
58
+ 0% {
59
+ width: 0%;
60
+ }
61
+ 100% {
62
+ width: 100%;
63
+ }
64
+ }
65
+ </style>
@@ -0,0 +1,53 @@
1
+ ---
2
+ /**
3
+ * @component ListItemIconLeft
4
+ * @description ListItem 前置图标加载动画子组件
5
+ */
6
+ import '../../style.ts';
7
+ const { loading = false, duration } = Astro.props;
8
+ ---
9
+
10
+ <li
11
+ class="cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden"
12
+ {...Astro.props}>
13
+ {
14
+ loading && duration && (
15
+ <div
16
+ class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
17
+ style={`animation-duration: ${duration}ms;`}
18
+ />
19
+ )
20
+ }
21
+ <div
22
+ class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3">
23
+ {/* 前置 loading 图标 */}
24
+ {
25
+ loading && !duration && (
26
+ <div
27
+ class="cosy:flex-shrink-0 cosy:transform-none"
28
+ style="transform: none !important;">
29
+ <div class="cosy:loading cosy:loading-spinner cosy:loading-sm cosy:text-accent" />
30
+ </div>
31
+ )
32
+ }
33
+
34
+ <slot />
35
+ </div>
36
+ </li>
37
+
38
+ <style scoped>
39
+ /* 进度条动画 */
40
+ .loading-bar {
41
+ width: 0%;
42
+ height: 100%;
43
+ animation: loading-bar-anim linear forwards;
44
+ }
45
+ @keyframes loading-bar-anim {
46
+ 0% {
47
+ width: 0%;
48
+ }
49
+ 100% {
50
+ width: 100%;
51
+ }
52
+ }
53
+ </style>
@@ -0,0 +1,53 @@
1
+ ---
2
+ /**
3
+ * @component ListItemIconRight
4
+ * @description ListItem 后置图标加载动画子组件
5
+ */
6
+ import '../../style.ts';
7
+ const { loading = false, duration } = Astro.props;
8
+ ---
9
+
10
+ <li
11
+ class="cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden"
12
+ {...Astro.props}>
13
+ {
14
+ loading && duration && (
15
+ <div
16
+ class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
17
+ style={`animation-duration: ${duration}ms;`}
18
+ />
19
+ )
20
+ }
21
+ <div
22
+ class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3">
23
+ <slot />
24
+
25
+ {/* 后置 loading 图标 */}
26
+ {
27
+ loading && !duration && (
28
+ <div
29
+ class="cosy:flex-shrink-0 cosy:ml-auto cosy:transform-none"
30
+ style="transform: none !important;">
31
+ <div class="cosy:loading cosy:loading-dots cosy:loading-sm cosy:text-accent" />
32
+ </div>
33
+ )
34
+ }
35
+ </div>
36
+ </li>
37
+
38
+ <style scoped>
39
+ /* 进度条动画 */
40
+ .loading-bar {
41
+ width: 0%;
42
+ height: 100%;
43
+ animation: loading-bar-anim linear forwards;
44
+ }
45
+ @keyframes loading-bar-anim {
46
+ 0% {
47
+ width: 0%;
48
+ }
49
+ 100% {
50
+ width: 100%;
51
+ }
52
+ }
53
+ </style>
@@ -0,0 +1,61 @@
1
+ ---
2
+ /**
3
+ * @component ListItemPulse
4
+ * @description ListItem 整体脉冲动画子组件
5
+ */
6
+ import '../../style.ts';
7
+ const { loading = false, duration } = Astro.props;
8
+ ---
9
+
10
+ <li
11
+ class:list={[
12
+ 'cosy:mb-2 cosy:rounded-md cosy:bg-base-300 cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden',
13
+ loading && !duration ? 'pulse-anim' : '',
14
+ ]}
15
+ {...Astro.props}>
16
+ {
17
+ loading && duration && (
18
+ <div
19
+ class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
20
+ style={`animation-duration: ${duration}ms;`}
21
+ />
22
+ )
23
+ }
24
+ <div
25
+ class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3">
26
+ <slot />
27
+ </div>
28
+ </li>
29
+
30
+ <style scoped>
31
+ /* 整体脉冲动画 */
32
+ @keyframes pulse-scale {
33
+ 0%,
34
+ 100% {
35
+ transform: scale(1);
36
+ opacity: 1;
37
+ }
38
+ 50% {
39
+ transform: scale(1.01);
40
+ opacity: 0.9;
41
+ }
42
+ }
43
+ .pulse-anim {
44
+ animation: pulse-scale 1.5s ease-in-out infinite;
45
+ }
46
+
47
+ /* 进度条动画 */
48
+ .loading-bar {
49
+ width: 0%;
50
+ height: 100%;
51
+ animation: loading-bar-anim linear forwards;
52
+ }
53
+ @keyframes loading-bar-anim {
54
+ 0% {
55
+ width: 0%;
56
+ }
57
+ 100% {
58
+ width: 100%;
59
+ }
60
+ }
61
+ </style>