@coffic/cosy-ui 0.8.24 → 0.8.26

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.
@@ -27,13 +27,25 @@
27
27
  * </Alert>
28
28
  * ```
29
29
  *
30
+ * 自定义操作按钮:
31
+ * ```astro
32
+ * <Alert type="info">
33
+ * 这是带自定义操作的提示
34
+ * <slot name="action">
35
+ * <button>操作</button>
36
+ * </slot>
37
+ * </Alert>
38
+ * ```
39
+ *
30
40
  * @props
31
41
  * @prop {('info'|'success'|'warning'|'error')} [type='info'] - 提示类型,影响颜色和图标
32
42
  * @prop {string} [title] - 提示标题,可选
33
43
  * @prop {string} [class] - 自定义 CSS 类名
44
+ * @prop {boolean} [closable=true] - 是否可关闭
34
45
  *
35
46
  * @slots
36
47
  * @slot default - 提示内容
48
+ * @slot action - 自定义操作按钮,显示在 alert 右侧
37
49
  */
38
50
 
39
51
  // 注意:
@@ -46,15 +58,22 @@ import {
46
58
  SuccessIcon,
47
59
  WarningIcon,
48
60
  ErrorIcon,
61
+ CloseIcon,
49
62
  } from '../../index-astro';
50
63
 
51
64
  interface Props {
52
65
  type?: 'info' | 'success' | 'warning' | 'error';
53
66
  title?: string;
54
67
  class?: string;
68
+ closable?: boolean;
55
69
  }
56
70
 
57
- const { type = 'info', title, class: className = '' } = Astro.props;
71
+ const {
72
+ type = 'info',
73
+ title,
74
+ class: className = '',
75
+ closable = true,
76
+ } = Astro.props;
58
77
 
59
78
  // 根据类型设置样式
60
79
  const alertClass = {
@@ -73,12 +92,17 @@ const IconComponent = {
73
92
  }[type as 'info' | 'success' | 'warning' | 'error'];
74
93
  ---
75
94
 
76
- <div class={`cosy:alert ${alertClass} ${className}`} role="alert">
95
+ <div
96
+ class={`cosy:alert cosy:w-full cosy:flex ${alertClass} ${className}`}
97
+ role="alert">
77
98
  <div
78
- class="cosy:flex cosy:flex-row cosy:items-center cosy:gap-4 cosy:alert-content">
79
- <IconComponent />
99
+ class="cosy:flex cosy:flex-row cosy:items-center cosy:gap-4 cosy:justify-between cosy:w-full">
100
+ <IconComponent
101
+ class="cosy:btn cosy:btn-sm cosy:btn-ghost cosy:btn-circle"
102
+ />
80
103
 
81
- <div class="cosy:flex cosy:flex-col cosy:items-center cosy:h-full">
104
+ <div
105
+ class="cosy:flex cosy:flex-col cosy:items-start cosy:h-full cosy:flex-1">
82
106
  {
83
107
  title && (
84
108
  <h3 class="cosy:font-bold" style="margin-top: 0 !important">
@@ -96,5 +120,21 @@ const IconComponent = {
96
120
 
97
121
  {!title && <slot />}
98
122
  </div>
123
+
124
+ <div
125
+ class="cosy:flex cosy:flex-row cosy:items-center cosy:gap-2"
126
+ data-role="actions">
127
+ <slot name="action" />
128
+
129
+ {
130
+ closable && (
131
+ <button
132
+ class="cosy:ml-auto cosy:btn cosy:btn-ghost cosy:btn-sm cosy:btn-circle"
133
+ onclick="this.parentElement.parentElement.style.display = 'none';">
134
+ <CloseIcon class="cosy:h-5 cosy:w-5" />
135
+ </button>
136
+ )
137
+ }
138
+ </div>
99
139
  </div>
100
140
  </div>
@@ -1,45 +1,71 @@
1
1
  ---
2
2
  /**
3
3
  * @component ListItem
4
- * @description 支持加载中进度条的列表项组件。点击后可显示从左到右的进度条,适合异步操作场景。
5
- * @usage
6
- * <ListItem loading={loading} duration={1500} on:click={...}>内容</ListItem>
7
- * @props loading?: boolean 是否加载中
8
- * @props duration?: number 进度条动画时长(毫秒),默认1500
9
- * @slots default 默认插槽,列表项内容
4
+ * @description List item component with loading animations
5
+ * @props loading?: boolean
6
+ * @props duration?: number
7
+ * @props animationType?: string
10
8
  */
11
9
  import '../../style.ts';
12
- const { loading = false, duration = 1500 } = Astro.props;
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;
13
23
  ---
14
24
 
15
- <li
16
- class="cosy:mb-2 cosy:rounded-md cosy:p-2 cosy:flex cosy:items-center cosy:gap-3 cosy:bg-base-300 cosy:hover:bg-accent/10 cosy:relative cosy:overflow-hidden"
17
- {...Astro.props}>
18
- {
19
- loading && (
20
- <div
21
- class="cosy:absolute cosy:left-0 cosy:top-0 cosy:h-full cosy:bg-accent/40 cosy:z-0 loading-bar"
22
- style={`animation-duration: ${duration}ms;`}
23
- />
24
- )
25
- }
26
- <div
27
- class="cosy:relative cosy:z-10 cosy:w-full cosy:flex cosy:items-center cosy:gap-3">
28
- <slot />
29
- </div>
30
- </li>
31
- <style scoped>
32
- .loading-bar {
33
- width: 0%;
34
- height: 100%;
35
- animation: loading-bar-anim linear forwards;
36
- }
37
- @keyframes loading-bar-anim {
38
- 0% {
39
- width: 0%;
40
- }
41
- 100% {
42
- width: 100%;
43
- }
44
- }
45
- </style>
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>
@@ -0,0 +1,59 @@
1
+ ---
2
+ /**
3
+ * @component ListItemRing
4
+ * @description ListItem Ring 外环脉冲动画子组件
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 ? 'cosy:ring-2 cosy:ring-accent ring-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
+ /* Ring 外环脉冲动画 */
32
+ @keyframes ring-pulse {
33
+ 0%,
34
+ 100% {
35
+ transform: scale(1);
36
+ }
37
+ 50% {
38
+ transform: scale(1.02);
39
+ }
40
+ }
41
+ .ring-pulse-anim {
42
+ animation: ring-pulse 1.5s ease-in-out infinite;
43
+ }
44
+
45
+ /* 进度条动画 */
46
+ .loading-bar {
47
+ width: 0%;
48
+ height: 100%;
49
+ animation: loading-bar-anim linear forwards;
50
+ }
51
+ @keyframes loading-bar-anim {
52
+ 0% {
53
+ width: 0%;
54
+ }
55
+ 100% {
56
+ width: 100%;
57
+ }
58
+ }
59
+ </style>
@@ -1 +1,7 @@
1
- export { default as ListItem } from './ListItem.astro';
1
+ export { default as ListItem } from './ListItem.astro';
2
+
3
+ export type ListItemProps = {
4
+ loading?: boolean;
5
+ duration?: number; // 进度条动画时长,毫秒
6
+ animationType?: 'ring' | 'icon-left' | 'icon-right' | 'breath' | 'pulse' | 'glow'; // 无限动画类型,默认 'ring'
7
+ };