@coffic/cosy-ui 0.3.12 → 0.3.33

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.
@@ -62,6 +62,7 @@ interface Props {
62
62
  type?: 'button' | 'submit' | 'reset';
63
63
  class?: string;
64
64
  onClick?: string;
65
+ formmethod?: string;
65
66
  }
66
67
 
67
68
  const {
@@ -75,27 +76,74 @@ const {
75
76
  type = 'button',
76
77
  class: className,
77
78
  onClick,
79
+ formmethod,
78
80
  } = Astro.props;
81
+
82
+ // 计算按钮的类名
83
+ const getButtonClasses = () => {
84
+ const classes = ['cosy:btn'];
85
+
86
+ // Variant classes
87
+ const variantClasses = {
88
+ primary: 'cosy:btn-primary',
89
+ secondary: 'cosy:btn-secondary',
90
+ accent: 'cosy:btn-accent',
91
+ info: 'cosy:btn-info',
92
+ success: 'cosy:btn-success',
93
+ warning: 'cosy:btn-warning',
94
+ error: 'cosy:btn-error',
95
+ ghost: 'cosy:btn-ghost',
96
+ link: 'cosy:btn-link',
97
+ outline: 'cosy:btn-outline',
98
+ neutral: 'cosy:btn-neutral'
99
+ };
100
+
101
+ // Size classes
102
+ const sizeClasses = {
103
+ lg: 'cosy:btn-lg',
104
+ md: 'cosy:btn-md',
105
+ sm: 'cosy:btn-sm',
106
+ xs: 'cosy:btn-xs'
107
+ };
108
+
109
+ // Shape classes
110
+ const shapeClasses = {
111
+ circle: 'cosy:btn-circle',
112
+ square: 'cosy:btn-square'
113
+ };
114
+
115
+ if (variantClasses[variant]) {
116
+ classes.push(variantClasses[variant]);
117
+ }
118
+
119
+ if (sizeClasses[size]) {
120
+ classes.push(sizeClasses[size]);
121
+ }
122
+
123
+ if (shape && shapeClasses[shape]) {
124
+ classes.push(shapeClasses[shape]);
125
+ }
126
+
127
+ if (wide) classes.push('cosy:btn-wide');
128
+ if (block) classes.push('cosy:btn-block');
129
+ if (loading) classes.push('cosy:loading');
130
+ if (className) classes.push(className);
131
+
132
+ return classes;
133
+ };
134
+
135
+ const buttonClasses = getButtonClasses();
79
136
  ---
80
137
 
81
138
  <button
82
- type={type}
83
- class:list={[
84
- 'button',
85
- `button-${variant}`,
86
- `button-${size}`,
87
- shape && `button-${shape}`,
88
- wide && 'button-wide',
89
- block && 'button-block',
90
- loading && 'button-loading',
91
- className
92
- ]}
139
+ type={formmethod === 'dialog' ? 'submit' : type}
140
+ class:list={buttonClasses}
93
141
  disabled={disabled}
94
142
  onclick={onClick}
143
+ formmethod={formmethod}
95
144
  data-variant={variant}
96
145
  >
97
- {loading && <span class="loading-spinner"></span>}
98
- <span class="button-content">
146
+ <span class="cosy:flex cosy:items-center cosy:gap-2">
99
147
  <slot name="icon-left" />
100
148
  <slot />
101
149
  <slot name="icon-right" />
@@ -157,33 +157,72 @@ const isRemoteImage = typeof src === 'string' && (src.startsWith('http') || src.
157
157
  // 获取图片源
158
158
  const imgSrc = typeof src === 'string' ? src : src.src;
159
159
 
160
+ // 对象映射定义所有可能的类名
161
+ const objectFitClasses = {
162
+ 'contain': 'object-contain',
163
+ 'cover': 'object-cover',
164
+ 'fill': 'object-fill',
165
+ 'none': 'object-none',
166
+ 'scale-down': 'object-scale-down'
167
+ };
168
+
169
+ const roundedClasses = {
170
+ 'none': '',
171
+ 'sm': 'rounded-sm',
172
+ 'md': 'rounded-md',
173
+ 'lg': 'rounded-lg',
174
+ 'xl': 'rounded-xl',
175
+ '2xl': 'rounded-2xl',
176
+ '3xl': 'rounded-3xl',
177
+ 'full': 'rounded-full'
178
+ };
179
+
180
+ const shadowClasses = {
181
+ 'none': '',
182
+ 'sm': 'shadow-sm',
183
+ 'md': 'shadow-md',
184
+ 'lg': 'shadow-lg',
185
+ 'xl': 'shadow-xl',
186
+ '2xl': 'shadow-2xl'
187
+ };
188
+
189
+ const hoverClasses = {
190
+ 'none': '',
191
+ 'scale': 'hover:scale-110',
192
+ 'brightness': 'hover:brightness-110',
193
+ 'blur': 'hover:blur-sm'
194
+ };
195
+
196
+ const transitionClasses = {
197
+ 'none': '',
198
+ 'fade': 'transition-opacity duration-300',
199
+ 'slide': 'transition-transform duration-300',
200
+ 'zoom': 'transition-all duration-300'
201
+ };
202
+
160
203
  // 构建图片类名
161
204
  const imgClasses = [
162
- // DaisyUI 和 Tailwind 类
163
205
  'object-center',
164
- objectFit === 'cover' ? 'object-cover' : `object-${objectFit}`,
165
- rounded !== 'none' ? `rounded-${rounded}` : '',
166
- shadow !== 'none' ? `shadow-${shadow}` : '',
167
- hover === 'scale' ? 'hover:scale-110' : '',
168
- hover === 'brightness' ? 'hover:brightness-110' : '',
169
- hover === 'blur' ? 'hover:blur-sm' : '',
170
- transition !== 'none' ? 'transition-all duration-300' : '',
206
+ objectFitClasses[objectFit] || objectFitClasses['cover'],
207
+ roundedClasses[rounded],
208
+ shadowClasses[shadow],
209
+ hoverClasses[hover],
210
+ transitionClasses[transition],
171
211
  className
172
212
  ].filter(Boolean).join(' ');
173
213
 
174
214
  // 构建占位图类名
175
215
  const placeholderClasses = [
176
216
  'absolute inset-0',
177
- rounded !== 'none' ? `rounded-${rounded}` : '',
178
- loadingIndicator === 'skeleton' ? 'animate-pulse bg-base-300' : '',
179
- loadingIndicator === 'pulse' ? 'animate-pulse bg-base-300' : '',
217
+ roundedClasses[rounded],
218
+ loadingIndicator === 'skeleton' || loadingIndicator === 'pulse' ? 'animate-pulse bg-base-300' : ''
180
219
  ].filter(Boolean).join(' ');
181
220
 
182
221
  // 构建错误占位图类名
183
222
  const errorClasses = [
184
223
  'absolute inset-0 flex items-center justify-center',
185
- rounded !== 'none' ? `rounded-${rounded}` : '',
186
- 'bg-error bg-opacity-10',
224
+ roundedClasses[rounded],
225
+ 'bg-error bg-opacity-10'
187
226
  ].filter(Boolean).join(' ');
188
227
  ---
189
228
 
@@ -204,12 +243,12 @@ const errorClasses = [
204
243
  <div class={placeholderClasses} data-placeholder>
205
244
  {/* 远程图片加载指示器 */}
206
245
  {isRemoteImage && loadingIndicator === 'spinner' && (
207
- <div class="loading loading-spinner loading-lg text-primary absolute inset-0 m-auto" />
246
+ <div class="absolute inset-0 m-auto text-primary loading loading-spinner loading-lg" />
208
247
  )}
209
248
 
210
249
  {isRemoteImage && loadingIndicator === 'progress' && (
211
- <div class="absolute bottom-0 left-0 right-0">
212
- <progress class="progress progress-primary w-full" />
250
+ <div class="right-0 bottom-0 left-0 absolute">
251
+ <progress class="w-full progress progress-primary" />
213
252
  </div>
214
253
  )}
215
254
  </div>
@@ -76,6 +76,8 @@ interface Props extends HTMLAttributes<'a'> {
76
76
  variant?: LinkVariant;
77
77
  animation?: LinkAnimation;
78
78
  size?: LinkSize;
79
+ debug?: boolean;
80
+ centerText?: boolean;
79
81
  }
80
82
 
81
83
  const {
@@ -87,6 +89,8 @@ const {
87
89
  size = 'md',
88
90
  class: className = '',
89
91
  'class:list': classList,
92
+ debug = false,
93
+ centerText = false,
90
94
  ...rest
91
95
  } = Astro.props;
92
96
 
@@ -119,6 +123,16 @@ const classes = [
119
123
  // 自定义类名
120
124
  className
121
125
  ];
126
+
127
+ // 文本居中样式
128
+ if (centerText) {
129
+ classes.push('cosy:justify-center cosy:text-center');
130
+ }
131
+
132
+ // 调试样式
133
+ if (debug) {
134
+ classes.push('cosy:border cosy:border-dashed cosy:border-red-500');
135
+ }
122
136
  ---
123
137
 
124
138
  <a
@@ -41,6 +41,13 @@
41
41
  * <p>不居中的容器,靠左对齐</p>
42
42
  * </Container>
43
43
  * ```
44
+ *
45
+ * 带边框的容器:
46
+ * ```astro
47
+ * <Container border>
48
+ * <p>带有边框的容器</p>
49
+ * </Container>
50
+ * ```
44
51
  */
45
52
 
46
53
  import type { HTMLAttributes } from 'astro/types';
@@ -66,6 +73,12 @@ interface Props extends HTMLAttributes<'div'> {
66
73
  * @default true
67
74
  */
68
75
  centered?: boolean;
76
+
77
+ /**
78
+ * 是否显示边框
79
+ * @default false
80
+ */
81
+ border?: boolean;
69
82
 
70
83
  /**
71
84
  * 自定义类名
@@ -82,17 +95,37 @@ const {
82
95
  size = 'md',
83
96
  padding = 'md',
84
97
  centered = true,
98
+ border = false,
85
99
  class: className = '',
86
100
  'class:list': classList,
87
101
  ...rest
88
102
  } = Astro.props;
89
103
 
104
+ // 静态类名映射
105
+ const sizeClasses = {
106
+ 'xs': 'container-xs',
107
+ 'sm': 'container-sm',
108
+ 'md': 'container-md',
109
+ 'lg': 'container-lg',
110
+ 'xl': 'container-xl',
111
+ 'full': 'container-full'
112
+ } as const;
113
+
114
+ const paddingClasses = {
115
+ 'none': 'container-padding-none',
116
+ 'sm': 'container-padding-sm',
117
+ 'md': 'container-padding-md',
118
+ 'lg': 'container-padding-lg',
119
+ 'xl': 'container-padding-xl'
120
+ } as const;
121
+
90
122
  // 构建CSS类名
91
123
  const containerClasses = [
92
124
  'container',
93
- `container-${size}`,
94
- `container-padding-${padding}`,
125
+ sizeClasses[size],
126
+ paddingClasses[padding],
95
127
  centered ? 'container-centered' : '',
128
+ border ? 'cosy:border cosy:rounded-lg' : '',
96
129
  className
97
130
  ];
98
131
  ---
@@ -11,15 +11,16 @@
11
11
  * <p>内容将被包裹在一个合适的区块中</p>
12
12
  * </Section>
13
13
  *
14
- * <Section padding="lg" background="gray" centered={true}>
14
+ * <Section padding="lg" background="gray" centered={true} border={true}>
15
15
  * <h2>自定义区块</h2>
16
- * <p>大内边距,灰色背景,内容居中</p>
16
+ * <p>大内边距,灰色背景,内容居中,带边框</p>
17
17
  * </Section>
18
18
  * ```
19
19
  */
20
20
 
21
21
  import type { HTMLAttributes } from 'astro/types';
22
22
  import Container from './Container.astro';
23
+ import "../../app.css"
23
24
 
24
25
  interface Props extends HTMLAttributes<'section'> {
25
26
  /**
@@ -51,6 +52,12 @@ interface Props extends HTMLAttributes<'section'> {
51
52
  * @default false
52
53
  */
53
54
  centered?: boolean;
55
+
56
+ /**
57
+ * 是否显示边框
58
+ * @default false
59
+ */
60
+ border?: boolean;
54
61
 
55
62
  /**
56
63
  * 自定义类名
@@ -79,6 +86,7 @@ const {
79
86
  container = true,
80
87
  containerSize = 'md',
81
88
  centered = false,
89
+ border = false,
82
90
  class: className = '',
83
91
  'class:list': classList,
84
92
  id,
@@ -88,32 +96,33 @@ const {
88
96
 
89
97
  // 内边距映射
90
98
  const paddingClasses = {
91
- 'none': 'py-0',
92
- 'sm': 'py-6',
93
- 'md': 'py-12',
94
- 'lg': 'py-16',
95
- 'xl': 'py-24'
99
+ 'none': 'cosy:py-0',
100
+ 'sm': 'cosy:py-6',
101
+ 'md': 'cosy:py-12',
102
+ 'lg': 'cosy:py-16',
103
+ 'xl': 'cosy:py-24'
96
104
  };
97
105
 
98
106
  // 背景颜色映射
99
107
  const backgroundClasses = {
100
- 'transparent': 'bg-transparent',
101
- 'white': 'bg-white',
102
- 'gray': 'bg-gray-100',
103
- 'primary': 'bg-blue-50',
104
- 'secondary': 'bg-gray-50',
105
- 'dark': 'bg-gray-900 text-white'
108
+ 'transparent': 'cosy:bg-transparent',
109
+ 'white': 'cosy:bg-base-100',
110
+ 'gray': 'cosy:bg-base-200',
111
+ 'primary': 'cosy:bg-primary/10',
112
+ 'secondary': 'cosy:bg-secondary/10',
113
+ 'dark': 'cosy:bg-neutral cosy:text-neutral-content'
106
114
  };
107
115
 
108
116
  // 构建最终类名
109
117
  const sectionClasses = [
110
118
  paddingClasses[padding as keyof typeof paddingClasses],
111
119
  backgroundClasses[background as keyof typeof backgroundClasses],
120
+ border ? 'cosy:border cosy:rounded-lg' : '',
112
121
  className
113
122
  ].join(' ');
114
123
 
115
124
  // 内容类名
116
- const contentClasses = centered ? 'text-center' : '';
125
+ const contentClasses = centered ? 'cosy:text-center' : '';
117
126
  ---
118
127
 
119
128
  <section id={id} class:list={[sectionClasses, classList]} style={style} {...rest}>
@@ -127,19 +136,3 @@ const contentClasses = centered ? 'text-center' : '';
127
136
  </div>
128
137
  )}
129
138
  </section>
130
-
131
- <style>
132
- /* 背景颜色 */
133
- .bg-transparent { background-color: transparent; }
134
- .bg-white { background-color: #ffffff; }
135
- .bg-gray-50 { background-color: #f9fafb; }
136
- .bg-gray-100 { background-color: #f3f4f6; }
137
- .bg-blue-50 { background-color: #eff6ff; }
138
- .bg-gray-900 { background-color: #111827; }
139
-
140
- /* 文字颜色 */
141
- .text-white { color: #ffffff; }
142
-
143
- /* 文本对齐 */
144
- .text-center { text-align: center; }
145
- </style>
@@ -46,6 +46,7 @@
46
46
 
47
47
  // 导入样式
48
48
  import '../../app.css';
49
+ import Button from '../base/Button.astro';
49
50
 
50
51
  interface Props {
51
52
  /**
@@ -75,26 +76,32 @@ const {
75
76
  } = Astro.props;
76
77
  ---
77
78
 
78
- <dialog id={id} class="modal">
79
- <div class:list={["modal-box", className]}>
79
+ <dialog id={id} class="cosy:modal">
80
+ <div class:list={["cosy:modal-box", className]}>
80
81
  {showCloseButton && (
81
82
  <form method="dialog">
82
- <button class="modal-close-button">✕</button>
83
+ <Button
84
+ variant="ghost"
85
+ size="sm"
86
+ shape="circle"
87
+ formmethod="dialog"
88
+ class="cosy:modal-close-button"
89
+ >✕</Button>
83
90
  </form>
84
91
  )}
85
92
 
86
- {title && <h3 class="modal-title">{title}</h3>}
93
+ {title && <h3 class="cosy:modal-title">{title}</h3>}
87
94
 
88
- <div class="modal-content">
95
+ <div class="cosy:modal-content">
89
96
  <slot />
90
97
  </div>
91
98
 
92
- <div class="modal-action">
99
+ <div class="cosy:modal-action">
93
100
  <slot name="actions" />
94
101
  </div>
95
102
  </div>
96
103
 
97
- <form method="dialog" class="modal-backdrop">
104
+ <form method="dialog" class="cosy:modal-backdrop">
98
105
  <button>关闭</button>
99
106
  </form>
100
107
  </dialog>
@@ -1,4 +1,7 @@
1
1
  ---
2
+ /**
3
+ * 菜单图标组件
4
+ */
2
5
  interface Props {
3
6
  /**
4
7
  * 图标的大小
@@ -14,13 +17,9 @@ interface Props {
14
17
  * 自定义类名
15
18
  */
16
19
  class?: string;
17
- /**
18
- * 插槽名称
19
- */
20
- slot?: string;
21
20
  }
22
21
 
23
- const { size = '24px', color = 'currentColor', class: className = '', slot } = Astro.props;
22
+ const { size = '24px', color = 'currentColor', class: className = '' } = Astro.props;
24
23
  ---
25
24
 
26
25
  <svg
@@ -35,7 +34,5 @@ const { size = '24px', color = 'currentColor', class: className = '', slot } = A
35
34
  stroke-linejoin="round"
36
35
  class={className}
37
36
  >
38
- <line x1="3" y1="12" x2="21" y2="12" />
39
- <line x1="3" y1="6" x2="21" y2="6" />
40
- <line x1="3" y1="18" x2="21" y2="18" />
37
+ <path d="M4 6h16M4 12h16M4 18h16" />
41
38
  </svg>