@coffic/cosy-ui 0.1.28 → 0.2.0
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 +67 -23
- 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/base/README.md +53 -0
- package/dist/components/base/index.ts +6 -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/README.md +37 -0
- package/dist/components/data-display/TeamMember.astro +135 -0
- package/dist/components/data-display/TeamMembers.astro +101 -0
- package/dist/components/data-display/index.ts +3 -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/display/README.md +32 -0
- package/dist/components/display/index.ts +6 -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/icons/index.ts +23 -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/README.md +37 -0
- package/dist/components/layouts/Stack.astro +149 -0
- package/dist/components/layouts/index.ts +6 -0
- package/dist/components/navigation/LanguageSwitcher.astro +81 -0
- package/dist/components/navigation/README.md +24 -0
- package/dist/components/navigation/TableOfContents.astro +352 -0
- package/dist/components/navigation/ThemeSwitcher.astro +89 -0
- package/dist/components/navigation/index.ts +3 -0
- package/dist/components/typography/Article.astro +144 -0
- package/dist/components/typography/Heading.astro +205 -0
- package/dist/components/typography/README.md +29 -0
- package/dist/components/typography/Text.astro +187 -0
- package/dist/components/typography/index.ts +3 -0
- package/dist/index.ts +9 -0
- package/dist/integration.ts +14 -0
- package/dist/style.ts +1 -0
- package/{src → dist}/types/footer.ts +11 -7
- package/{src → dist}/utils/social.ts +5 -12
- package/dist/utils/theme.ts +55 -0
- package/package.json +65 -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 -130
- 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
@@ -0,0 +1,330 @@
|
|
1
|
+
---
|
2
|
+
/**
|
3
|
+
* @component CodeExample
|
4
|
+
*
|
5
|
+
* @description
|
6
|
+
* 用于展示组件示例及其源代码的组件。
|
7
|
+
* 采用标签形式,默认显示预览,用户可以点击标签切换到源代码视图。
|
8
|
+
* 支持亮色和暗黑模式,会根据系统设置自动切换主题。
|
9
|
+
*
|
10
|
+
* @usage
|
11
|
+
* ```astro
|
12
|
+
* <CodeExample
|
13
|
+
* title="示例标题"
|
14
|
+
* description="示例描述"
|
15
|
+
* code={`<Alert type="info">这是一个示例</Alert>`}
|
16
|
+
* >
|
17
|
+
* <Alert type="info">这是一个示例</Alert>
|
18
|
+
* </CodeExample>
|
19
|
+
* ```
|
20
|
+
*
|
21
|
+
* @props
|
22
|
+
* @prop {string} [title] - 示例标题
|
23
|
+
* @prop {string} [description] - 示例描述
|
24
|
+
* @prop {string} code - 要展示的源代码
|
25
|
+
*
|
26
|
+
* @slots
|
27
|
+
* @slot default - 组件的实际渲染内容
|
28
|
+
*/
|
29
|
+
|
30
|
+
// 导入图标
|
31
|
+
import { ClipboardIcon, CheckIcon } from '../icons';
|
32
|
+
|
33
|
+
interface Props {
|
34
|
+
title?: string;
|
35
|
+
description?: string;
|
36
|
+
code: string;
|
37
|
+
}
|
38
|
+
|
39
|
+
const { title, description, code } = Astro.props;
|
40
|
+
---
|
41
|
+
|
42
|
+
<div class="code-example">
|
43
|
+
{title && <h3 class="code-example-title">{title}</h3>}
|
44
|
+
{description && <p class="code-example-description">{description}</p>}
|
45
|
+
|
46
|
+
<div class="code-example-tabs">
|
47
|
+
<button class="code-example-tab active" data-tab="preview">预览</button>
|
48
|
+
<button class="code-example-tab" data-tab="code">代码</button>
|
49
|
+
</div>
|
50
|
+
|
51
|
+
<div class="code-example-content">
|
52
|
+
<div class="code-example-panel active" data-panel="preview">
|
53
|
+
<div class="code-example-preview">
|
54
|
+
<slot />
|
55
|
+
</div>
|
56
|
+
</div>
|
57
|
+
|
58
|
+
<div class="code-example-panel" data-panel="code">
|
59
|
+
<div class="code-example-code">
|
60
|
+
<div class="code-example-header">
|
61
|
+
<button class="copy-button" aria-label="复制代码">
|
62
|
+
<span class="copy-icon"><ClipboardIcon /></span>
|
63
|
+
<span class="check-icon"><CheckIcon /></span>
|
64
|
+
<span class="copy-text">复制代码</span>
|
65
|
+
</button>
|
66
|
+
</div>
|
67
|
+
<pre><code class="language-astro">{code}</code></pre>
|
68
|
+
</div>
|
69
|
+
</div>
|
70
|
+
</div>
|
71
|
+
</div>
|
72
|
+
|
73
|
+
<style>
|
74
|
+
/* 颜色变量 - 支持亮色和暗黑模式 */
|
75
|
+
:root {
|
76
|
+
/* 亮色模式变量 */
|
77
|
+
--code-example-border: #e2e8f0;
|
78
|
+
--code-example-bg: #ffffff;
|
79
|
+
--code-example-text: #333333;
|
80
|
+
--code-example-title-border: #e2e8f0;
|
81
|
+
--code-example-description-color: #64748b;
|
82
|
+
--code-example-tabs-bg: #f8fafc;
|
83
|
+
--code-example-tab-color: #64748b;
|
84
|
+
--code-example-tab-hover-color: #0f172a;
|
85
|
+
--code-example-tab-active-color: #3b82f6;
|
86
|
+
--code-example-tab-active-border: #3b82f6;
|
87
|
+
--code-example-preview-bg: #ffffff;
|
88
|
+
--code-example-code-bg: #1e293b;
|
89
|
+
--code-example-code-text: #e2e8f0;
|
90
|
+
--code-example-header-bg: #334155;
|
91
|
+
--code-example-copy-button-color: #e2e8f0;
|
92
|
+
--code-example-copy-button-hover-bg: rgba(255, 255, 255, 0.1);
|
93
|
+
--code-example-copy-success-color: #4ade80;
|
94
|
+
}
|
95
|
+
|
96
|
+
@media (prefers-color-scheme: dark) {
|
97
|
+
:root {
|
98
|
+
/* 暗黑模式变量 */
|
99
|
+
--code-example-border: #2d3748;
|
100
|
+
--code-example-bg: #1a202c;
|
101
|
+
--code-example-text: #e2e8f0;
|
102
|
+
--code-example-title-border: #2d3748;
|
103
|
+
--code-example-description-color: #a0aec0;
|
104
|
+
--code-example-tabs-bg: #171e2e;
|
105
|
+
--code-example-tab-color: #a0aec0;
|
106
|
+
--code-example-tab-hover-color: #e2e8f0;
|
107
|
+
--code-example-tab-active-color: #60a5fa;
|
108
|
+
--code-example-tab-active-border: #60a5fa;
|
109
|
+
--code-example-preview-bg: #1a202c;
|
110
|
+
--code-example-code-bg: #0f172a;
|
111
|
+
--code-example-code-text: #e2e8f0;
|
112
|
+
--code-example-header-bg: #1e293b;
|
113
|
+
--code-example-copy-button-color: #e2e8f0;
|
114
|
+
--code-example-copy-button-hover-bg: rgba(255, 255, 255, 0.1);
|
115
|
+
--code-example-copy-success-color: #4ade80;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
.code-example {
|
120
|
+
margin-bottom: 2rem;
|
121
|
+
border: 1px solid var(--code-example-border);
|
122
|
+
border-radius: 0.5rem;
|
123
|
+
overflow: hidden;
|
124
|
+
background-color: var(--code-example-bg);
|
125
|
+
color: var(--code-example-text);
|
126
|
+
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
127
|
+
}
|
128
|
+
|
129
|
+
.code-example-title {
|
130
|
+
font-size: 1.25rem;
|
131
|
+
font-weight: bold;
|
132
|
+
margin: 0;
|
133
|
+
padding: 1rem;
|
134
|
+
border-bottom: 1px solid var(--code-example-title-border);
|
135
|
+
}
|
136
|
+
|
137
|
+
.code-example-description {
|
138
|
+
padding: 0 1rem;
|
139
|
+
color: var(--code-example-description-color);
|
140
|
+
margin-top: 0.5rem;
|
141
|
+
margin-bottom: 1rem;
|
142
|
+
}
|
143
|
+
|
144
|
+
.code-example-tabs {
|
145
|
+
display: flex;
|
146
|
+
border-bottom: 1px solid var(--code-example-title-border);
|
147
|
+
background-color: var(--code-example-tabs-bg);
|
148
|
+
}
|
149
|
+
|
150
|
+
.code-example-tab {
|
151
|
+
padding: 0.75rem 1.5rem;
|
152
|
+
background: transparent;
|
153
|
+
border: none;
|
154
|
+
border-bottom: 2px solid transparent;
|
155
|
+
cursor: pointer;
|
156
|
+
font-weight: 500;
|
157
|
+
color: var(--code-example-tab-color);
|
158
|
+
transition: all 0.2s ease;
|
159
|
+
}
|
160
|
+
|
161
|
+
.code-example-tab:hover {
|
162
|
+
color: var(--code-example-tab-hover-color);
|
163
|
+
}
|
164
|
+
|
165
|
+
.code-example-tab.active {
|
166
|
+
color: var(--code-example-tab-active-color);
|
167
|
+
border-bottom-color: var(--code-example-tab-active-border);
|
168
|
+
}
|
169
|
+
|
170
|
+
.code-example-content {
|
171
|
+
position: relative;
|
172
|
+
}
|
173
|
+
|
174
|
+
.code-example-panel {
|
175
|
+
display: none;
|
176
|
+
}
|
177
|
+
|
178
|
+
.code-example-panel.active {
|
179
|
+
display: block;
|
180
|
+
}
|
181
|
+
|
182
|
+
.code-example-preview {
|
183
|
+
padding: 1.5rem;
|
184
|
+
background-color: var(--code-example-preview-bg);
|
185
|
+
}
|
186
|
+
|
187
|
+
.code-example-code {
|
188
|
+
position: relative;
|
189
|
+
background-color: var(--code-example-code-bg);
|
190
|
+
color: var(--code-example-code-text);
|
191
|
+
overflow: auto;
|
192
|
+
}
|
193
|
+
|
194
|
+
.code-example-header {
|
195
|
+
display: flex;
|
196
|
+
justify-content: flex-end;
|
197
|
+
align-items: center;
|
198
|
+
padding: 0.5rem 1rem;
|
199
|
+
background-color: var(--code-example-header-bg);
|
200
|
+
}
|
201
|
+
|
202
|
+
.copy-button {
|
203
|
+
background: transparent;
|
204
|
+
border: none;
|
205
|
+
color: var(--code-example-copy-button-color);
|
206
|
+
cursor: pointer;
|
207
|
+
display: flex;
|
208
|
+
align-items: center;
|
209
|
+
gap: 0.5rem;
|
210
|
+
padding: 0.5rem 0.75rem;
|
211
|
+
border-radius: 0.25rem;
|
212
|
+
transition: background-color 0.2s;
|
213
|
+
font-size: 0.875rem;
|
214
|
+
}
|
215
|
+
|
216
|
+
.copy-button:hover {
|
217
|
+
background-color: var(--code-example-copy-button-hover-bg);
|
218
|
+
}
|
219
|
+
|
220
|
+
.copy-icon, .check-icon {
|
221
|
+
display: flex;
|
222
|
+
align-items: center;
|
223
|
+
justify-content: center;
|
224
|
+
width: 1rem;
|
225
|
+
height: 1rem;
|
226
|
+
}
|
227
|
+
|
228
|
+
.check-icon {
|
229
|
+
display: none;
|
230
|
+
color: var(--code-example-copy-success-color);
|
231
|
+
}
|
232
|
+
|
233
|
+
.copy-button.copied .copy-icon {
|
234
|
+
display: none;
|
235
|
+
}
|
236
|
+
|
237
|
+
.copy-button.copied .check-icon {
|
238
|
+
display: flex;
|
239
|
+
}
|
240
|
+
|
241
|
+
.copy-button.copied .copy-text {
|
242
|
+
color: var(--code-example-copy-success-color);
|
243
|
+
}
|
244
|
+
|
245
|
+
pre {
|
246
|
+
margin: 0;
|
247
|
+
padding: 1rem;
|
248
|
+
overflow-x: auto;
|
249
|
+
}
|
250
|
+
|
251
|
+
code {
|
252
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
253
|
+
white-space: pre;
|
254
|
+
font-size: 0.9rem;
|
255
|
+
line-height: 1.5;
|
256
|
+
}
|
257
|
+
</style>
|
258
|
+
|
259
|
+
<script>
|
260
|
+
function initializeCodeExample() {
|
261
|
+
// 标签切换功能
|
262
|
+
const tabs = document.querySelectorAll('.code-example-tab');
|
263
|
+
|
264
|
+
tabs.forEach(tab => {
|
265
|
+
tab.addEventListener('click', () => {
|
266
|
+
// 获取当前标签组
|
267
|
+
const tabGroup = tab.closest('.code-example-tabs');
|
268
|
+
if (!tabGroup) return;
|
269
|
+
|
270
|
+
const codeExample = tab.closest('.code-example');
|
271
|
+
if (!codeExample) return;
|
272
|
+
|
273
|
+
const contentContainer = codeExample.querySelector('.code-example-content');
|
274
|
+
if (!contentContainer) return;
|
275
|
+
|
276
|
+
// 获取目标面板
|
277
|
+
const targetTab = tab.getAttribute('data-tab');
|
278
|
+
if (!targetTab) return;
|
279
|
+
|
280
|
+
// 更新标签状态
|
281
|
+
tabGroup.querySelectorAll('.code-example-tab').forEach(t => {
|
282
|
+
t.classList.remove('active');
|
283
|
+
});
|
284
|
+
tab.classList.add('active');
|
285
|
+
|
286
|
+
// 更新面板状态
|
287
|
+
contentContainer.querySelectorAll('.code-example-panel').forEach(panel => {
|
288
|
+
panel.classList.remove('active');
|
289
|
+
});
|
290
|
+
|
291
|
+
const targetPanel = contentContainer.querySelector(`[data-panel="${targetTab}"]`);
|
292
|
+
if (targetPanel) {
|
293
|
+
targetPanel.classList.add('active');
|
294
|
+
}
|
295
|
+
});
|
296
|
+
});
|
297
|
+
|
298
|
+
// 复制代码功能
|
299
|
+
const copyButtons = document.querySelectorAll('.copy-button');
|
300
|
+
|
301
|
+
copyButtons.forEach(button => {
|
302
|
+
button.addEventListener('click', () => {
|
303
|
+
const codeBlock = button.closest('.code-example-code');
|
304
|
+
if (!codeBlock) return;
|
305
|
+
|
306
|
+
const codeElement = codeBlock.querySelector('code');
|
307
|
+
if (!codeElement) return;
|
308
|
+
|
309
|
+
const code = codeElement.textContent || '';
|
310
|
+
|
311
|
+
// 复制到剪贴板
|
312
|
+
navigator.clipboard.writeText(code).then(() => {
|
313
|
+
// 显示复制成功状态
|
314
|
+
button.classList.add('copied');
|
315
|
+
|
316
|
+
// 3秒后恢复原状
|
317
|
+
setTimeout(() => {
|
318
|
+
button.classList.remove('copied');
|
319
|
+
}, 3000);
|
320
|
+
});
|
321
|
+
});
|
322
|
+
});
|
323
|
+
}
|
324
|
+
|
325
|
+
// 初始化
|
326
|
+
initializeCodeExample();
|
327
|
+
|
328
|
+
// Astro 页面切换时重新初始化
|
329
|
+
document.addEventListener('astro:page-load', initializeCodeExample);
|
330
|
+
</script>
|
@@ -0,0 +1,119 @@
|
|
1
|
+
---
|
2
|
+
/**
|
3
|
+
* @component Hero
|
4
|
+
*
|
5
|
+
* @description
|
6
|
+
* Hero 组件是一个全屏的展示区域,通常用于网站的首页或重要页面的顶部。
|
7
|
+
* 它提供了一个引人注目的视觉区域,可以包含标题、描述、图片和行动按钮。
|
8
|
+
*
|
9
|
+
* @design
|
10
|
+
* 设计理念:
|
11
|
+
* 1. 视觉冲击力 - 全屏展示,吸引用户注意
|
12
|
+
* 2. 内容聚焦 - 清晰地传达核心信息
|
13
|
+
* 3. 引导行动 - 通过链接按钮引导用户进行下一步操作
|
14
|
+
* 4. 灵活布局 - 支持图片、标题、描述和自定义内容
|
15
|
+
*
|
16
|
+
* @usage
|
17
|
+
* 基本用法:
|
18
|
+
* ```astro
|
19
|
+
* <Hero
|
20
|
+
* title="欢迎使用我们的产品"
|
21
|
+
* description="这是一个简短的描述,介绍产品的主要特点和价值。"
|
22
|
+
* links={[
|
23
|
+
* { text: "开始使用", href: "/getting-started" },
|
24
|
+
* { text: "了解更多", href: "/about" }
|
25
|
+
* ]}
|
26
|
+
* />
|
27
|
+
* ```
|
28
|
+
*
|
29
|
+
* 带图片的用法:
|
30
|
+
* ```astro
|
31
|
+
* <Hero
|
32
|
+
* title="产品展示"
|
33
|
+
* description="查看我们的最新产品。"
|
34
|
+
* image={{ src: "/images/product.png", alt: "产品图片" }}
|
35
|
+
* links={[
|
36
|
+
* { text: "立即购买", href: "/buy" }
|
37
|
+
* ]}
|
38
|
+
* />
|
39
|
+
* ```
|
40
|
+
*
|
41
|
+
* 带自定义内容的用法:
|
42
|
+
* ```astro
|
43
|
+
* <Hero
|
44
|
+
* title="交互式演示"
|
45
|
+
* description="尝试我们的交互式演示。"
|
46
|
+
* links={[
|
47
|
+
* { text: "查看文档", href: "/docs" }
|
48
|
+
* ]}
|
49
|
+
* >
|
50
|
+
* <div slot="app">
|
51
|
+
* <InteractiveDemo />
|
52
|
+
* </div>
|
53
|
+
* </Hero>
|
54
|
+
* ```
|
55
|
+
*
|
56
|
+
* @props
|
57
|
+
* @prop {string} title - Hero 区域的主标题
|
58
|
+
* @prop {string} description - 标题下方的描述文本
|
59
|
+
* @prop {Object} [image] - 可选的图片配置
|
60
|
+
* @prop {string} image.src - 图片的源地址
|
61
|
+
* @prop {string} image.alt - 图片的替代文本
|
62
|
+
* @prop {Array<Link>} links - 链接按钮数组
|
63
|
+
* @prop {string} links[].text - 链接按钮的文本
|
64
|
+
* @prop {string} links[].href - 链接按钮的目标地址
|
65
|
+
*/
|
66
|
+
|
67
|
+
// 导入样式
|
68
|
+
import '../../app.css';
|
69
|
+
|
70
|
+
import Link from '../base/Link.astro';
|
71
|
+
|
72
|
+
interface Link {
|
73
|
+
text: string;
|
74
|
+
href: string;
|
75
|
+
}
|
76
|
+
|
77
|
+
interface Props {
|
78
|
+
title: string;
|
79
|
+
description: string;
|
80
|
+
image?: {
|
81
|
+
src: string;
|
82
|
+
alt: string;
|
83
|
+
};
|
84
|
+
links: Link[];
|
85
|
+
}
|
86
|
+
|
87
|
+
const { title, description, image, links = [] } = Astro.props;
|
88
|
+
---
|
89
|
+
|
90
|
+
<div class="hero-container">
|
91
|
+
<div class="hero-content">
|
92
|
+
{image && <img src={image.src} alt={image.alt} class="hero-image" />}
|
93
|
+
|
94
|
+
<h2 class="hero-title">{title}</h2>
|
95
|
+
<p class="hero-description">
|
96
|
+
{description}
|
97
|
+
</p>
|
98
|
+
|
99
|
+
<div class="hero-app">
|
100
|
+
<slot name="app" />
|
101
|
+
</div>
|
102
|
+
|
103
|
+
<div class="hero-links">
|
104
|
+
{
|
105
|
+
links.map((link: Link) => (
|
106
|
+
<Link
|
107
|
+
href={link.href}
|
108
|
+
external
|
109
|
+
variant="cta"
|
110
|
+
animation="hover-lift"
|
111
|
+
size="lg"
|
112
|
+
>
|
113
|
+
{link.text}
|
114
|
+
</Link>
|
115
|
+
))
|
116
|
+
}
|
117
|
+
</div>
|
118
|
+
</div>
|
119
|
+
</div>
|
@@ -0,0 +1,115 @@
|
|
1
|
+
---
|
2
|
+
/**
|
3
|
+
* @component Modal
|
4
|
+
*
|
5
|
+
* @description
|
6
|
+
* Modal 组件是一个模态对话框,用于在不离开当前页面的情况下显示内容、通知或请求用户输入。
|
7
|
+
* 它会覆盖在页面内容上方,并提供一个聚焦的交互环境。
|
8
|
+
*
|
9
|
+
* @design
|
10
|
+
* 设计理念:
|
11
|
+
* 1. 聚焦交互 - 通过遮罩层和动画效果引导用户注意力
|
12
|
+
* 2. 灵活布局 - 支持标题、内容和操作按钮的灵活组合
|
13
|
+
* 3. 可访问性 - 支持键盘导航和屏幕阅读器
|
14
|
+
* 4. 响应式设计 - 在不同屏幕尺寸下保持良好的用户体验
|
15
|
+
*
|
16
|
+
* @usage
|
17
|
+
* 基本用法:
|
18
|
+
* ```astro
|
19
|
+
* <Modal id="my-modal" title="提示">
|
20
|
+
* <p>这是一个模态对话框的内容。</p>
|
21
|
+
* <button slot="actions" data-modal-target="my-modal">关闭</button>
|
22
|
+
* </Modal>
|
23
|
+
*
|
24
|
+
* <!-- 触发按钮 -->
|
25
|
+
* <button data-modal-target="my-modal">打开模态框</button>
|
26
|
+
* ```
|
27
|
+
*
|
28
|
+
* 自定义操作按钮:
|
29
|
+
* ```astro
|
30
|
+
* <Modal id="confirm-modal" title="确认操作">
|
31
|
+
* <p>您确定要执行此操作吗?</p>
|
32
|
+
* <div slot="actions">
|
33
|
+
* <button class="btn btn-primary">确认</button>
|
34
|
+
* <button class="btn" data-modal-target="confirm-modal">取消</button>
|
35
|
+
* </div>
|
36
|
+
* </Modal>
|
37
|
+
* ```
|
38
|
+
*
|
39
|
+
* 不带标题的模态框:
|
40
|
+
* ```astro
|
41
|
+
* <Modal id="image-modal">
|
42
|
+
* <img src="/images/large-image.jpg" alt="大图预览" />
|
43
|
+
* </Modal>
|
44
|
+
* ```
|
45
|
+
*/
|
46
|
+
|
47
|
+
// 导入样式
|
48
|
+
import '../../app.css';
|
49
|
+
|
50
|
+
interface Props {
|
51
|
+
/**
|
52
|
+
* Modal 的唯一标识符
|
53
|
+
*/
|
54
|
+
id: string;
|
55
|
+
/**
|
56
|
+
* 模态框的标题
|
57
|
+
*/
|
58
|
+
title?: string;
|
59
|
+
/**
|
60
|
+
* 是否显示关闭按钮
|
61
|
+
* @default true
|
62
|
+
*/
|
63
|
+
showCloseButton?: boolean;
|
64
|
+
/**
|
65
|
+
* 自定义类名
|
66
|
+
*/
|
67
|
+
class?: string;
|
68
|
+
}
|
69
|
+
|
70
|
+
const {
|
71
|
+
id,
|
72
|
+
title,
|
73
|
+
showCloseButton = true,
|
74
|
+
class: className = '',
|
75
|
+
} = Astro.props;
|
76
|
+
---
|
77
|
+
|
78
|
+
<dialog id={id} class="modal">
|
79
|
+
<div class:list={["modal-box", className]}>
|
80
|
+
{showCloseButton && (
|
81
|
+
<form method="dialog">
|
82
|
+
<button class="modal-close-button">✕</button>
|
83
|
+
</form>
|
84
|
+
)}
|
85
|
+
|
86
|
+
{title && <h3 class="modal-title">{title}</h3>}
|
87
|
+
|
88
|
+
<div class="modal-content">
|
89
|
+
<slot />
|
90
|
+
</div>
|
91
|
+
|
92
|
+
<div class="modal-action">
|
93
|
+
<slot name="actions" />
|
94
|
+
</div>
|
95
|
+
</div>
|
96
|
+
|
97
|
+
<form method="dialog" class="modal-backdrop">
|
98
|
+
<button>关闭</button>
|
99
|
+
</form>
|
100
|
+
</dialog>
|
101
|
+
|
102
|
+
<script define:vars={{ id }}>
|
103
|
+
// 为了方便使用,我们提供一些辅助方法
|
104
|
+
document.addEventListener('DOMContentLoaded', () => {
|
105
|
+
const modal = document.getElementById(id);
|
106
|
+
if (!modal) return;
|
107
|
+
|
108
|
+
// 为所有触发这个模态框的按钮添加点击事件
|
109
|
+
document.querySelectorAll(`[data-modal-target="${id}"]`).forEach(trigger => {
|
110
|
+
trigger.addEventListener('click', () => {
|
111
|
+
modal.showModal();
|
112
|
+
});
|
113
|
+
});
|
114
|
+
});
|
115
|
+
</script>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# 展示组件 (Display Components)
|
2
|
+
|
3
|
+
这个目录包含了用于内容展示的组件,主要用于展示信息和内容的呈现。
|
4
|
+
|
5
|
+
## 设计原则
|
6
|
+
|
7
|
+
1. **视觉层次**:合理使用视觉层次来突出重要信息
|
8
|
+
2. **一致的美学**:保持组件风格的一致性
|
9
|
+
3. **灵活布局**:适应不同的内容长度和类型
|
10
|
+
|
11
|
+
## 包含的组件
|
12
|
+
|
13
|
+
- `Card.astro`: 卡片组件,用于信息分组展示
|
14
|
+
- `Banner.astro`: 横幅组件,用于重要信息展示
|
15
|
+
- `Hero.astro`: 英雄区组件,用于页面主要内容展示
|
16
|
+
- `Modal.astro`: 模态框组件,用于弹出式内容展示
|
17
|
+
- `CodeBlock.astro`: 代码块组件,用于代码展示
|
18
|
+
- `CodeExample.astro`: 代码示例组件,用于展示可运行的代码示例
|
19
|
+
|
20
|
+
## 使用指南
|
21
|
+
|
22
|
+
展示组件通常需要传入具体的内容和配置:
|
23
|
+
|
24
|
+
```astro
|
25
|
+
<Card title="标题">
|
26
|
+
这是卡片内容
|
27
|
+
</Card>
|
28
|
+
|
29
|
+
<Modal isOpen={true} onClose={handleClose}>
|
30
|
+
这是模态框内容
|
31
|
+
</Modal>
|
32
|
+
```
|
@@ -0,0 +1,6 @@
|
|
1
|
+
export { default as Card } from './Card.astro';
|
2
|
+
export { default as Banner } from './Banner.astro';
|
3
|
+
export { default as Hero } from './Hero.astro';
|
4
|
+
export { default as Modal } from './Modal.astro';
|
5
|
+
export { default as CodeBlock } from './CodeBlock.astro';
|
6
|
+
export { default as CodeExample } from './CodeExample.astro';
|
@@ -0,0 +1,35 @@
|
|
1
|
+
---
|
2
|
+
interface Props {
|
3
|
+
/**
|
4
|
+
* 图标的大小
|
5
|
+
* @default "24px"
|
6
|
+
*/
|
7
|
+
size?: string;
|
8
|
+
/**
|
9
|
+
* 图标的颜色
|
10
|
+
* @default "currentColor"
|
11
|
+
*/
|
12
|
+
color?: string;
|
13
|
+
/**
|
14
|
+
* 自定义类名
|
15
|
+
*/
|
16
|
+
class?: string;
|
17
|
+
}
|
18
|
+
|
19
|
+
const { size = '24px', color = 'currentColor', class: className = '' } = Astro.props;
|
20
|
+
---
|
21
|
+
|
22
|
+
<svg
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
24
|
+
width={size}
|
25
|
+
height={size}
|
26
|
+
viewBox="0 0 24 24"
|
27
|
+
fill="none"
|
28
|
+
stroke={color}
|
29
|
+
stroke-width="2"
|
30
|
+
stroke-linecap="round"
|
31
|
+
stroke-linejoin="round"
|
32
|
+
class={className}
|
33
|
+
>
|
34
|
+
<path d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
35
|
+
</svg>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
---
|
2
|
+
interface Props {
|
3
|
+
/**
|
4
|
+
* 图标的大小
|
5
|
+
* @default "24px"
|
6
|
+
*/
|
7
|
+
size?: string;
|
8
|
+
/**
|
9
|
+
* 图标的颜色
|
10
|
+
* @default "currentColor"
|
11
|
+
*/
|
12
|
+
color?: string;
|
13
|
+
/**
|
14
|
+
* 自定义类名
|
15
|
+
*/
|
16
|
+
class?: string;
|
17
|
+
}
|
18
|
+
|
19
|
+
const { size = '24px', color = 'currentColor', class: className = '' } = Astro.props;
|
20
|
+
---
|
21
|
+
|
22
|
+
<svg
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
24
|
+
width={size}
|
25
|
+
height={size}
|
26
|
+
viewBox="0 0 24 24"
|
27
|
+
fill="none"
|
28
|
+
stroke={color}
|
29
|
+
stroke-width="2"
|
30
|
+
stroke-linecap="round"
|
31
|
+
stroke-linejoin="round"
|
32
|
+
class={className}
|
33
|
+
>
|
34
|
+
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
|
35
|
+
<line x1="16" y1="2" x2="16" y2="6"></line>
|
36
|
+
<line x1="8" y1="2" x2="8" y2="6"></line>
|
37
|
+
<line x1="3" y1="10" x2="21" y2="10"></line>
|
38
|
+
</svg>
|