@coffic/cosy-ui 0.1.29 → 0.2.2
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.
- package/README.md +43 -22
- package/dist/app.css +1 -0
- package/dist/assets/logo-rounded.png +0 -0
- package/dist/assets/logo.png +0 -0
- package/dist/components/base/Alert.astro +186 -0
- package/dist/components/base/Button.astro +103 -0
- package/dist/components/base/Image.astro +291 -0
- package/dist/components/base/Link.astro +131 -0
- package/dist/components/containers/Container.astro +103 -0
- package/dist/components/containers/Main.astro +167 -0
- package/dist/components/containers/Section.astro +145 -0
- package/dist/components/containers/index.ts +3 -0
- package/dist/components/data-display/Blog.astro +195 -0
- package/dist/components/data-display/TeamMember.astro +135 -0
- package/dist/components/data-display/TeamMembers.astro +101 -0
- package/dist/components/display/Banner.astro +57 -0
- package/dist/components/display/Card.astro +135 -0
- package/dist/components/display/CodeBlock.astro +147 -0
- package/dist/components/display/CodeExample.astro +330 -0
- package/dist/components/display/Hero.astro +119 -0
- package/dist/components/display/Modal.astro +115 -0
- package/dist/components/icons/AlertTriangle.astro +35 -0
- package/dist/components/icons/CalendarIcon.astro +38 -0
- package/dist/components/icons/CheckCircle.astro +36 -0
- package/dist/components/icons/CheckIcon.astro +38 -0
- package/dist/components/icons/ClipboardIcon.astro +39 -0
- package/dist/components/icons/CloseIcon.astro +38 -0
- package/dist/components/icons/ErrorIcon.astro +35 -0
- package/dist/components/icons/GithubIcon.astro +31 -0
- package/dist/components/icons/InfoCircle.astro +37 -0
- package/dist/components/icons/InfoIcon.astro +38 -0
- package/dist/components/icons/LinkIcon.astro +39 -0
- package/dist/components/icons/LinkedinIcon.astro +31 -0
- package/dist/components/icons/MenuIcon.astro +41 -0
- package/dist/components/icons/SearchIcon.astro +40 -0
- package/dist/components/icons/SocialIcon.astro +100 -0
- package/dist/components/icons/SuccessIcon.astro +35 -0
- package/dist/components/icons/SunCloudyIcon.astro +45 -0
- package/dist/components/icons/TwitterIcon.astro +31 -0
- package/dist/components/icons/UserIcon.astro +35 -0
- package/dist/components/icons/WarningIcon.astro +38 -0
- package/dist/components/icons/XCircle.astro +37 -0
- package/dist/components/layouts/BaseLayout.astro +144 -0
- package/dist/components/layouts/DashboardLayout.astro +660 -0
- package/dist/components/layouts/DefaultLayout.astro +170 -0
- package/dist/components/layouts/DocumentationLayout.astro +469 -0
- package/dist/components/layouts/Flex.astro +138 -0
- package/dist/components/layouts/Footer.astro +284 -0
- package/dist/components/layouts/Grid.astro +182 -0
- package/dist/components/layouts/Header.astro +114 -0
- package/dist/components/layouts/LandingLayout.astro +388 -0
- package/dist/components/layouts/Stack.astro +149 -0
- package/dist/components/navigation/LanguageSwitcher.astro +81 -0
- package/dist/components/navigation/TableOfContents.astro +352 -0
- package/dist/components/navigation/ThemeSwitcher.astro +89 -0
- package/dist/components/typography/Article.astro +144 -0
- package/dist/components/typography/Heading.astro +205 -0
- package/dist/components/typography/Text.astro +187 -0
- package/dist/index.ts +70 -0
- package/dist/integration.ts +14 -0
- package/dist/style.ts +1 -0
- package/{src → dist}/types/footer.ts +1 -0
- package/dist/utils/theme.ts +55 -0
- package/package.json +67 -59
- package/index.ts +0 -18
- package/src/components/Alert.astro +0 -78
- package/src/components/Article.astro +0 -11
- package/src/components/Banner.astro +0 -49
- package/src/components/Blog.astro +0 -115
- package/src/components/Button.astro +0 -49
- package/src/components/Card.astro +0 -113
- package/src/components/CodeBlock.astro +0 -186
- package/src/components/Footer.astro +0 -148
- package/src/components/Header.astro +0 -305
- package/src/components/Hero.astro +0 -69
- package/src/components/Image.astro +0 -251
- package/src/components/Link.astro +0 -82
- package/src/components/Modal.astro +0 -67
- package/src/components/SocialIcon.astro +0 -36
- package/src/components/TeamMember.astro +0 -68
- package/src/components/TeamMembers.astro +0 -43
- package/src/env.d.ts +0 -0
- /package/{src/components → dist/components/base}/ThemeItem.astro +0 -0
- /package/{src → dist}/utils/social.ts +0 -0
@@ -0,0 +1,291 @@
|
|
1
|
+
---
|
2
|
+
/**
|
3
|
+
* @component Image
|
4
|
+
*
|
5
|
+
* @description
|
6
|
+
* Image 组件是一个增强的图片组件,提供了丰富的功能,包括懒加载、加载状态指示、错误处理、
|
7
|
+
* 以及各种视觉效果。它旨在提供更好的用户体验和性能优化。
|
8
|
+
*
|
9
|
+
* @design
|
10
|
+
* 设计理念:
|
11
|
+
* 1. 用户体验优先 - 提供加载状态反馈,减少用户等待焦虑
|
12
|
+
* 2. 性能优化 - 支持懒加载,减少初始加载时间
|
13
|
+
* 3. 错误处理 - 优雅地处理图片加载失败的情况
|
14
|
+
* 4. 视觉一致性 - 提供统一的圆角、阴影和过渡效果
|
15
|
+
* 5. 灵活配置 - 支持多种自定义选项,适应不同场景
|
16
|
+
*
|
17
|
+
* @usage
|
18
|
+
* 基本用法:
|
19
|
+
* ```astro
|
20
|
+
* <Image src="/images/photo.jpg" alt="一张照片" />
|
21
|
+
* ```
|
22
|
+
*
|
23
|
+
* 带样式效果:
|
24
|
+
* ```astro
|
25
|
+
* <Image
|
26
|
+
* src="/images/photo.jpg"
|
27
|
+
* alt="一张照片"
|
28
|
+
* rounded="lg"
|
29
|
+
* shadow="md"
|
30
|
+
* hover="scale"
|
31
|
+
* />
|
32
|
+
* ```
|
33
|
+
*
|
34
|
+
* 自定义加载指示器:
|
35
|
+
* ```astro
|
36
|
+
* <Image
|
37
|
+
* src="https://example.com/large-image.jpg"
|
38
|
+
* alt="远程大图"
|
39
|
+
* loadingIndicator="progress"
|
40
|
+
* />
|
41
|
+
* ```
|
42
|
+
*/
|
43
|
+
|
44
|
+
import "../../app.css";
|
45
|
+
import { AlertTriangle } from '../../index';
|
46
|
+
|
47
|
+
// 自定义图片元数据接口
|
48
|
+
interface ImageMetadata {
|
49
|
+
src: string;
|
50
|
+
width: number;
|
51
|
+
height: number;
|
52
|
+
format: string;
|
53
|
+
}
|
54
|
+
|
55
|
+
interface Props {
|
56
|
+
/**
|
57
|
+
* 图片源,可以是本地图片或远程URL
|
58
|
+
*/
|
59
|
+
src: ImageMetadata | string;
|
60
|
+
/**
|
61
|
+
* 图片的替代文本
|
62
|
+
*/
|
63
|
+
alt: string;
|
64
|
+
/**
|
65
|
+
* 图片的宽度
|
66
|
+
*/
|
67
|
+
width?: number;
|
68
|
+
/**
|
69
|
+
* 图片的高度
|
70
|
+
*/
|
71
|
+
height?: number;
|
72
|
+
/**
|
73
|
+
* 图片的加载方式
|
74
|
+
* @default "lazy"
|
75
|
+
*/
|
76
|
+
loading?: 'lazy' | 'eager';
|
77
|
+
/**
|
78
|
+
* 图片的填充方式
|
79
|
+
* @default "cover"
|
80
|
+
*/
|
81
|
+
objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
|
82
|
+
/**
|
83
|
+
* 图片的位置
|
84
|
+
* @default "center"
|
85
|
+
*/
|
86
|
+
objectPosition?: string;
|
87
|
+
/**
|
88
|
+
* 是否显示加载中的占位图
|
89
|
+
* @default true
|
90
|
+
*/
|
91
|
+
showPlaceholder?: boolean;
|
92
|
+
/**
|
93
|
+
* 是否显示加载失败的错误图
|
94
|
+
* @default true
|
95
|
+
*/
|
96
|
+
showError?: boolean;
|
97
|
+
/**
|
98
|
+
* 自定义类名
|
99
|
+
*/
|
100
|
+
class?: string;
|
101
|
+
/**
|
102
|
+
* 是否启用图片懒加载
|
103
|
+
* @default true
|
104
|
+
*/
|
105
|
+
lazy?: boolean;
|
106
|
+
/**
|
107
|
+
* 图片的圆角大小
|
108
|
+
* @default "none"
|
109
|
+
*/
|
110
|
+
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full';
|
111
|
+
/**
|
112
|
+
* 图片的阴影效果
|
113
|
+
* @default "none"
|
114
|
+
*/
|
115
|
+
shadow?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
116
|
+
/**
|
117
|
+
* 图片的悬停效果
|
118
|
+
* @default "none"
|
119
|
+
*/
|
120
|
+
hover?: 'none' | 'scale' | 'brightness' | 'blur';
|
121
|
+
/**
|
122
|
+
* 图片的过渡动画
|
123
|
+
* @default "none"
|
124
|
+
*/
|
125
|
+
transition?: 'none' | 'fade' | 'slide' | 'zoom';
|
126
|
+
|
127
|
+
/**
|
128
|
+
* 加载指示器类型
|
129
|
+
* @default "skeleton"
|
130
|
+
*/
|
131
|
+
loadingIndicator?: 'pulse' | 'spinner' | 'progress' | 'skeleton';
|
132
|
+
}
|
133
|
+
|
134
|
+
const {
|
135
|
+
src,
|
136
|
+
alt,
|
137
|
+
width,
|
138
|
+
height,
|
139
|
+
loading = 'lazy',
|
140
|
+
objectFit = 'cover',
|
141
|
+
objectPosition = 'center',
|
142
|
+
showPlaceholder = true,
|
143
|
+
showError = true,
|
144
|
+
class: className = '',
|
145
|
+
lazy = true,
|
146
|
+
rounded = 'none',
|
147
|
+
shadow = 'none',
|
148
|
+
hover = 'none',
|
149
|
+
transition = 'none',
|
150
|
+
loadingIndicator = 'skeleton',
|
151
|
+
} = Astro.props;
|
152
|
+
|
153
|
+
// 判断是否为本地图片
|
154
|
+
const isLocalImage = typeof src !== 'string' && 'src' in src;
|
155
|
+
// 判断是否为远程图片
|
156
|
+
const isRemoteImage = typeof src === 'string' && (src.startsWith('http') || src.startsWith('//'));
|
157
|
+
// 获取图片源
|
158
|
+
const imgSrc = typeof src === 'string' ? src : src.src;
|
159
|
+
|
160
|
+
// 构建图片类名
|
161
|
+
const imgClasses = [
|
162
|
+
// DaisyUI 和 Tailwind 类
|
163
|
+
'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' : '',
|
171
|
+
className
|
172
|
+
].filter(Boolean).join(' ');
|
173
|
+
|
174
|
+
// 构建占位图类名
|
175
|
+
const placeholderClasses = [
|
176
|
+
'absolute inset-0',
|
177
|
+
rounded !== 'none' ? `rounded-${rounded}` : '',
|
178
|
+
loadingIndicator === 'skeleton' ? 'animate-pulse bg-base-300' : '',
|
179
|
+
loadingIndicator === 'pulse' ? 'animate-pulse bg-base-300' : '',
|
180
|
+
].filter(Boolean).join(' ');
|
181
|
+
|
182
|
+
// 构建错误占位图类名
|
183
|
+
const errorClasses = [
|
184
|
+
'absolute inset-0 flex items-center justify-center',
|
185
|
+
rounded !== 'none' ? `rounded-${rounded}` : '',
|
186
|
+
'bg-error bg-opacity-10',
|
187
|
+
].filter(Boolean).join(' ');
|
188
|
+
---
|
189
|
+
|
190
|
+
<div class="relative w-full h-full">
|
191
|
+
<img
|
192
|
+
src={imgSrc}
|
193
|
+
alt={alt}
|
194
|
+
width={width}
|
195
|
+
height={height}
|
196
|
+
loading={loading}
|
197
|
+
class={imgClasses}
|
198
|
+
style={{ objectPosition }}
|
199
|
+
data-remote={isRemoteImage ? 'true' : 'false'}
|
200
|
+
/>
|
201
|
+
|
202
|
+
{/* 加载占位图 */}
|
203
|
+
{showPlaceholder && (
|
204
|
+
<div class={placeholderClasses} data-placeholder>
|
205
|
+
{/* 远程图片加载指示器 */}
|
206
|
+
{isRemoteImage && loadingIndicator === 'spinner' && (
|
207
|
+
<div class="loading loading-spinner loading-lg text-primary absolute inset-0 m-auto" />
|
208
|
+
)}
|
209
|
+
|
210
|
+
{isRemoteImage && loadingIndicator === 'progress' && (
|
211
|
+
<div class="absolute bottom-0 left-0 right-0">
|
212
|
+
<progress class="progress progress-primary w-full" />
|
213
|
+
</div>
|
214
|
+
)}
|
215
|
+
</div>
|
216
|
+
)}
|
217
|
+
|
218
|
+
{/* 错误占位图 */}
|
219
|
+
{showError && (
|
220
|
+
<div class={errorClasses} data-error hidden>
|
221
|
+
<AlertTriangle size="32px" class="text-error" />
|
222
|
+
</div>
|
223
|
+
)}
|
224
|
+
</div>
|
225
|
+
|
226
|
+
<script is:inline>
|
227
|
+
function handleImageLoad(img) {
|
228
|
+
if (!(img instanceof HTMLImageElement)) return;
|
229
|
+
const placeholder = img.parentElement?.querySelector('[data-placeholder]');
|
230
|
+
if (placeholder) {
|
231
|
+
placeholder.classList.add('opacity-0');
|
232
|
+
setTimeout(() => placeholder.remove(), 300);
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
function handleImageError(img) {
|
237
|
+
if (!(img instanceof HTMLImageElement)) return;
|
238
|
+
const placeholder = img.parentElement?.querySelector('[data-placeholder]');
|
239
|
+
if (placeholder) {
|
240
|
+
placeholder.remove();
|
241
|
+
}
|
242
|
+
const errorElement = img.parentElement?.querySelector('[data-error]');
|
243
|
+
if (errorElement) {
|
244
|
+
errorElement.classList.remove('hidden');
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
function simulateLoadingProgress(img) {
|
249
|
+
if (!(img instanceof HTMLImageElement) || img.getAttribute('data-remote') !== 'true') return;
|
250
|
+
const progressBar = img.parentElement?.querySelector('progress');
|
251
|
+
if (!progressBar) return;
|
252
|
+
|
253
|
+
let progress = 0;
|
254
|
+
const interval = setInterval(() => {
|
255
|
+
progress += Math.random() * 15;
|
256
|
+
if (progress >= 100 || img.complete) {
|
257
|
+
clearInterval(interval);
|
258
|
+
progress = 100;
|
259
|
+
}
|
260
|
+
progressBar.value = Math.min(progress, 100);
|
261
|
+
}, 200);
|
262
|
+
|
263
|
+
img.addEventListener('load', () => {
|
264
|
+
clearInterval(interval);
|
265
|
+
progressBar.value = 100;
|
266
|
+
});
|
267
|
+
|
268
|
+
img.addEventListener('error', () => {
|
269
|
+
clearInterval(interval);
|
270
|
+
});
|
271
|
+
}
|
272
|
+
|
273
|
+
function initializeImageHandlers() {
|
274
|
+
document.querySelectorAll('img[data-remote]').forEach(img => {
|
275
|
+
if (img instanceof HTMLImageElement) {
|
276
|
+
if (img.complete) {
|
277
|
+
handleImageLoad(img);
|
278
|
+
} else {
|
279
|
+
img.addEventListener('load', () => handleImageLoad(img));
|
280
|
+
img.addEventListener('error', () => handleImageError(img));
|
281
|
+
if (img.getAttribute('data-remote') === 'true') {
|
282
|
+
simulateLoadingProgress(img);
|
283
|
+
}
|
284
|
+
}
|
285
|
+
}
|
286
|
+
});
|
287
|
+
}
|
288
|
+
|
289
|
+
document.addEventListener('astro:page-load', initializeImageHandlers);
|
290
|
+
initializeImageHandlers();
|
291
|
+
</script>
|
@@ -0,0 +1,131 @@
|
|
1
|
+
---
|
2
|
+
/**
|
3
|
+
* @component Link
|
4
|
+
*
|
5
|
+
* @description
|
6
|
+
* Link 组件是一个增强的链接组件,提供了丰富的样式变体和动画效果。
|
7
|
+
* 它可以用于导航、按钮、行动号召等多种场景。
|
8
|
+
*
|
9
|
+
* @design
|
10
|
+
* 设计理念:
|
11
|
+
* 1. 灵活多变 - 提供多种样式变体,适应不同场景
|
12
|
+
* 2. 视觉反馈 - 通过悬停效果提供用户交互反馈
|
13
|
+
* 3. 一致性 - 保持与整体设计系统的一致性
|
14
|
+
* 4. 可访问性 - 确保链接可被键盘导航和屏幕阅读器识别
|
15
|
+
*
|
16
|
+
* @usage
|
17
|
+
* 基本用法:
|
18
|
+
* ```astro
|
19
|
+
* <Link href="/about">关于我们</Link>
|
20
|
+
* ```
|
21
|
+
*
|
22
|
+
* 外部链接:
|
23
|
+
* ```astro
|
24
|
+
* <Link href="https://example.com" external>访问外部网站</Link>
|
25
|
+
* ```
|
26
|
+
*
|
27
|
+
* 样式变体:
|
28
|
+
* ```astro
|
29
|
+
* <Link href="/signup" variant="primary">注册</Link>
|
30
|
+
* <Link href="/learn-more" variant="secondary">了解更多</Link>
|
31
|
+
* <Link href="/docs" variant="text">查看文档</Link>
|
32
|
+
* <Link href="/get-started" variant="cta">立即开始</Link>
|
33
|
+
* <Link href="/preview" variant="ghost">预览</Link>
|
34
|
+
* ```
|
35
|
+
*
|
36
|
+
* 块级显示:
|
37
|
+
* ```astro
|
38
|
+
* <Link href="/contact" block>独占一行的链接</Link>
|
39
|
+
* <p>这是一段文字,其中包含一个<Link href="/inline">内联链接</Link>。</p>
|
40
|
+
* ```
|
41
|
+
*
|
42
|
+
* 动画效果:
|
43
|
+
* ```astro
|
44
|
+
* <Link href="/contact" animation="hover-lift">联系我们</Link>
|
45
|
+
* <Link href="/features" animation="hover-glow">功能特性</Link>
|
46
|
+
* <Link href="/pricing" animation="hover-scale">查看价格</Link>
|
47
|
+
* ```
|
48
|
+
*
|
49
|
+
* 尺寸变体:
|
50
|
+
* ```astro
|
51
|
+
* <Link href="/small" size="sm">小型链接</Link>
|
52
|
+
* <Link href="/medium" size="md">中型链接</Link>
|
53
|
+
* <Link href="/large" size="lg">大型链接</Link>
|
54
|
+
* ```
|
55
|
+
*/
|
56
|
+
|
57
|
+
import "../../app.css";
|
58
|
+
|
59
|
+
import type { HTMLAttributes } from 'astro/types';
|
60
|
+
|
61
|
+
// 定义链接尺寸类型
|
62
|
+
type LinkSize = 'sm' | 'md' | 'lg';
|
63
|
+
|
64
|
+
// 定义链接变体类型
|
65
|
+
type LinkVariant = 'default' | 'primary' | 'secondary' | 'text' | 'cta' | 'ghost';
|
66
|
+
|
67
|
+
// 定义链接动画类型
|
68
|
+
type LinkAnimation = 'none' | 'hover-lift' | 'hover-glow' | 'hover-scale';
|
69
|
+
|
70
|
+
interface Props extends HTMLAttributes<'a'> {
|
71
|
+
href: string;
|
72
|
+
external?: boolean;
|
73
|
+
block?: boolean;
|
74
|
+
class?: string;
|
75
|
+
'class:list'?: any;
|
76
|
+
variant?: LinkVariant;
|
77
|
+
animation?: LinkAnimation;
|
78
|
+
size?: LinkSize;
|
79
|
+
}
|
80
|
+
|
81
|
+
const {
|
82
|
+
href,
|
83
|
+
external = false,
|
84
|
+
block = false,
|
85
|
+
variant = 'default',
|
86
|
+
animation = 'none',
|
87
|
+
size = 'md',
|
88
|
+
class: className = '',
|
89
|
+
'class:list': classList,
|
90
|
+
...rest
|
91
|
+
} = Astro.props;
|
92
|
+
|
93
|
+
// 构建类名
|
94
|
+
const classes = [
|
95
|
+
// 基础链接样式
|
96
|
+
'items-center cursor-pointer no-underline transition-all duration-200',
|
97
|
+
|
98
|
+
// 显示方式
|
99
|
+
block ? 'flex w-full' : 'inline-flex',
|
100
|
+
|
101
|
+
// 变体样式
|
102
|
+
variant === 'primary' && 'text-primary hover:text-primary-focus',
|
103
|
+
variant === 'secondary' && 'text-secondary hover:text-secondary-focus',
|
104
|
+
variant === 'text' && 'text-neutral hover:text-neutral-focus',
|
105
|
+
variant === 'cta' && 'text-accent hover:text-accent-focus font-medium',
|
106
|
+
variant === 'ghost' && 'text-base-content hover:text-base-content/80',
|
107
|
+
variant === 'default' && 'text-base-content hover:text-base-content/90',
|
108
|
+
|
109
|
+
// 尺寸样式
|
110
|
+
size === 'sm' && 'text-sm',
|
111
|
+
size === 'md' && 'text-base',
|
112
|
+
size === 'lg' && 'text-lg',
|
113
|
+
|
114
|
+
// 动画效果
|
115
|
+
animation === 'hover-lift' && 'hover:-translate-y-0.5 transition-transform',
|
116
|
+
animation === 'hover-glow' && 'hover:brightness-125 transition-[filter]',
|
117
|
+
animation === 'hover-scale' && 'hover:scale-105 transition-transform',
|
118
|
+
|
119
|
+
// 自定义类名
|
120
|
+
className
|
121
|
+
];
|
122
|
+
---
|
123
|
+
|
124
|
+
<a
|
125
|
+
href={href}
|
126
|
+
class:list={[classes, classList]}
|
127
|
+
{...external ? { target: '_blank', rel: 'noopener noreferrer' } : {}}
|
128
|
+
{...rest}
|
129
|
+
>
|
130
|
+
<slot />
|
131
|
+
</a>
|
@@ -0,0 +1,103 @@
|
|
1
|
+
---
|
2
|
+
/**
|
3
|
+
* @component Container
|
4
|
+
*
|
5
|
+
* @description
|
6
|
+
* Container 组件是一个基础的布局容器,用于限制内容宽度并居中显示。
|
7
|
+
* 它提供了多种尺寸和内边距选项,适用于各种布局需求。
|
8
|
+
*
|
9
|
+
* @design
|
10
|
+
* 设计理念:
|
11
|
+
* 1. 内容约束 - 限制内容宽度,提高可读性和视觉美感
|
12
|
+
* 2. 响应式设计 - 在不同屏幕尺寸下自动调整内边距
|
13
|
+
* 3. 灵活配置 - 支持多种尺寸和内边距选项
|
14
|
+
* 4. 简单易用 - 提供直观的API,易于集成到各种页面布局中
|
15
|
+
*
|
16
|
+
* @usage
|
17
|
+
* 基本用法:
|
18
|
+
* ```astro
|
19
|
+
* <Container>
|
20
|
+
* <p>内容将被限制在一个合理的宽度内并居中显示</p>
|
21
|
+
* </Container>
|
22
|
+
* ```
|
23
|
+
*
|
24
|
+
* 自定义尺寸和内边距:
|
25
|
+
* ```astro
|
26
|
+
* <Container size="sm" padding="lg">
|
27
|
+
* <p>小尺寸容器,大内边距</p>
|
28
|
+
* </Container>
|
29
|
+
* ```
|
30
|
+
*
|
31
|
+
* 全宽容器:
|
32
|
+
* ```astro
|
33
|
+
* <Container size="full" padding="none">
|
34
|
+
* <p>全宽容器,无内边距</p>
|
35
|
+
* </Container>
|
36
|
+
* ```
|
37
|
+
*
|
38
|
+
* 不居中的容器:
|
39
|
+
* ```astro
|
40
|
+
* <Container centered={false}>
|
41
|
+
* <p>不居中的容器,靠左对齐</p>
|
42
|
+
* </Container>
|
43
|
+
* ```
|
44
|
+
*/
|
45
|
+
|
46
|
+
import type { HTMLAttributes } from 'astro/types';
|
47
|
+
|
48
|
+
// 导入样式
|
49
|
+
import '../../app.css';
|
50
|
+
|
51
|
+
interface Props extends HTMLAttributes<'div'> {
|
52
|
+
/**
|
53
|
+
* 容器尺寸
|
54
|
+
* @default "md"
|
55
|
+
*/
|
56
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
57
|
+
|
58
|
+
/**
|
59
|
+
* 内边距大小
|
60
|
+
* @default "md"
|
61
|
+
*/
|
62
|
+
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
63
|
+
|
64
|
+
/**
|
65
|
+
* 是否居中显示
|
66
|
+
* @default true
|
67
|
+
*/
|
68
|
+
centered?: boolean;
|
69
|
+
|
70
|
+
/**
|
71
|
+
* 自定义类名
|
72
|
+
*/
|
73
|
+
class?: string;
|
74
|
+
|
75
|
+
/**
|
76
|
+
* 类名列表
|
77
|
+
*/
|
78
|
+
'class:list'?: any;
|
79
|
+
}
|
80
|
+
|
81
|
+
const {
|
82
|
+
size = 'md',
|
83
|
+
padding = 'md',
|
84
|
+
centered = true,
|
85
|
+
class: className = '',
|
86
|
+
'class:list': classList,
|
87
|
+
...rest
|
88
|
+
} = Astro.props;
|
89
|
+
|
90
|
+
// 构建CSS类名
|
91
|
+
const containerClasses = [
|
92
|
+
'container',
|
93
|
+
`container-${size}`,
|
94
|
+
`container-padding-${padding}`,
|
95
|
+
centered ? 'container-centered' : '',
|
96
|
+
className
|
97
|
+
];
|
98
|
+
---
|
99
|
+
|
100
|
+
<div class:list={[containerClasses, classList]} {...rest}>
|
101
|
+
<slot />
|
102
|
+
</div>
|
103
|
+
|
@@ -0,0 +1,167 @@
|
|
1
|
+
---
|
2
|
+
/**
|
3
|
+
* @component Main
|
4
|
+
*
|
5
|
+
* @description
|
6
|
+
* Main 组件是页面的主要内容区域,使用 Container 组件提供响应式布局。
|
7
|
+
* 它适合作为页面的主体部分,自动处理不同屏幕尺寸下的布局和内边距。
|
8
|
+
*
|
9
|
+
* @design
|
10
|
+
* 设计理念:
|
11
|
+
* 1. 结构清晰 - 明确表示页面的主要内容区域,提高语义化
|
12
|
+
* 2. 响应式布局 - 在不同屏幕尺寸下自动调整内边距和宽度
|
13
|
+
* 3. 灵活配置 - 支持自定义容器尺寸、内边距和背景颜色
|
14
|
+
* 4. 与容器集成 - 无缝集成 Container 组件,保持布局一致性
|
15
|
+
*
|
16
|
+
* @usage
|
17
|
+
* 基本用法:
|
18
|
+
* ```astro
|
19
|
+
* ---
|
20
|
+
* import { Main } from '@coffic/cosy-ui';
|
21
|
+
* ---
|
22
|
+
*
|
23
|
+
* <Main>
|
24
|
+
* <h1>页面标题</h1>
|
25
|
+
* <p>页面内容</p>
|
26
|
+
* </Main>
|
27
|
+
* ```
|
28
|
+
*
|
29
|
+
* 自定义容器尺寸:
|
30
|
+
* ```astro
|
31
|
+
* <Main size="lg">
|
32
|
+
* <p>这是一个较宽的主内容区域</p>
|
33
|
+
* </Main>
|
34
|
+
* ```
|
35
|
+
*
|
36
|
+
* 自定义内边距:
|
37
|
+
* ```astro
|
38
|
+
* <Main verticalPadding="lg" padding="xl">
|
39
|
+
* <p>这个主内容区域有更大的内边距</p>
|
40
|
+
* </Main>
|
41
|
+
* ```
|
42
|
+
*
|
43
|
+
* 自定义背景颜色:
|
44
|
+
* ```astro
|
45
|
+
* <Main backgroundColor="primary">
|
46
|
+
* <p>这个主内容区域有主题色背景</p>
|
47
|
+
* </Main>
|
48
|
+
* ```
|
49
|
+
*/
|
50
|
+
|
51
|
+
import Container from './Container.astro';
|
52
|
+
|
53
|
+
// 导入样式
|
54
|
+
import '../../app.css';
|
55
|
+
|
56
|
+
export interface Props {
|
57
|
+
/**
|
58
|
+
* 容器大小
|
59
|
+
* @default "md"
|
60
|
+
*/
|
61
|
+
size?: "xs" | "sm" | "md" | "lg" | "xl" | "full";
|
62
|
+
|
63
|
+
/**
|
64
|
+
* 水平内边距(通过 Container 组件的 padding 属性设置)
|
65
|
+
* @default "md"
|
66
|
+
*/
|
67
|
+
padding?: "none" | "sm" | "md" | "lg" | "xl";
|
68
|
+
|
69
|
+
/**
|
70
|
+
* 垂直内边距
|
71
|
+
* @default "md"
|
72
|
+
*/
|
73
|
+
verticalPadding?: "none" | "sm" | "md" | "lg" | "xl" | string;
|
74
|
+
|
75
|
+
/**
|
76
|
+
* 是否居中显示内容
|
77
|
+
* @default true
|
78
|
+
*/
|
79
|
+
centered?: boolean;
|
80
|
+
|
81
|
+
/**
|
82
|
+
* 背景颜色
|
83
|
+
* @default undefined
|
84
|
+
*/
|
85
|
+
backgroundColor?: "primary" | "secondary" | "tertiary" | "light" | "dark" | string;
|
86
|
+
|
87
|
+
/**
|
88
|
+
* HTML id 属性
|
89
|
+
*/
|
90
|
+
id?: string;
|
91
|
+
|
92
|
+
/**
|
93
|
+
* 类名
|
94
|
+
*/
|
95
|
+
class?: string;
|
96
|
+
|
97
|
+
/**
|
98
|
+
* 类名列表
|
99
|
+
*/
|
100
|
+
'class:list'?: any;
|
101
|
+
}
|
102
|
+
|
103
|
+
const {
|
104
|
+
size = 'md',
|
105
|
+
padding = 'md',
|
106
|
+
verticalPadding = "md",
|
107
|
+
centered = true,
|
108
|
+
backgroundColor,
|
109
|
+
id,
|
110
|
+
class: className,
|
111
|
+
'class:list': classList,
|
112
|
+
...rest
|
113
|
+
} = Astro.props;
|
114
|
+
|
115
|
+
// 处理垂直内边距
|
116
|
+
const verticalPaddingClass =
|
117
|
+
verticalPadding === "none" || verticalPadding === "sm" ||
|
118
|
+
verticalPadding === "md" || verticalPadding === "lg" ||
|
119
|
+
verticalPadding === "xl"
|
120
|
+
? `main-padding-${verticalPadding}`
|
121
|
+
: "main-padding-custom";
|
122
|
+
|
123
|
+
// 处理背景颜色
|
124
|
+
const bgColorClass = backgroundColor &&
|
125
|
+
(backgroundColor === "primary" || backgroundColor === "secondary" ||
|
126
|
+
backgroundColor === "tertiary" || backgroundColor === "light" ||
|
127
|
+
backgroundColor === "dark")
|
128
|
+
? `main-bg-${backgroundColor}`
|
129
|
+
: "";
|
130
|
+
|
131
|
+
// 构建自定义样式
|
132
|
+
const customStyle =
|
133
|
+
(verticalPadding && verticalPaddingClass === "main-padding-custom")
|
134
|
+
? `padding-top: ${verticalPadding}; padding-bottom: ${verticalPadding};`
|
135
|
+
: "";
|
136
|
+
|
137
|
+
const customBgColor =
|
138
|
+
(backgroundColor && !bgColorClass)
|
139
|
+
? `background-color: ${backgroundColor};`
|
140
|
+
: "";
|
141
|
+
|
142
|
+
const inlineStyle = (customStyle || customBgColor)
|
143
|
+
? `${customStyle} ${customBgColor}`.trim()
|
144
|
+
: undefined;
|
145
|
+
---
|
146
|
+
|
147
|
+
<main
|
148
|
+
id={id}
|
149
|
+
class:list={[
|
150
|
+
"main-content",
|
151
|
+
verticalPaddingClass,
|
152
|
+
bgColorClass,
|
153
|
+
className,
|
154
|
+
classList
|
155
|
+
]}
|
156
|
+
style={inlineStyle}
|
157
|
+
{...rest}
|
158
|
+
>
|
159
|
+
<Container
|
160
|
+
size={size}
|
161
|
+
padding={padding}
|
162
|
+
centered={centered}
|
163
|
+
class="main-container"
|
164
|
+
>
|
165
|
+
<slot />
|
166
|
+
</Container>
|
167
|
+
</main>
|