@coffic/cosy-ui 0.8.21 → 0.8.23

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.
Files changed (46) hide show
  1. package/dist/app.css +1 -1
  2. package/dist/index-astro.ts +2 -0
  3. package/dist/src/assets/iconData.ts +5 -1
  4. package/dist/src-astro/banner/Banner.astro +55 -3
  5. package/dist/src-astro/banner/index.ts +1 -52
  6. package/dist/src-astro/button/Button.astro +40 -1
  7. package/dist/src-astro/code-container/ButtonCodeToggle.astro +55 -0
  8. package/dist/src-astro/code-container/ButtonCopyCode.astro +74 -0
  9. package/dist/src-astro/code-container/CodeContainer.astro +14 -289
  10. package/dist/src-astro/code-container/CodePanel.astro +14 -0
  11. package/dist/src-astro/code-container/CodeToolbar.astro +100 -0
  12. package/dist/src-astro/code-container/Description.astro +17 -0
  13. package/dist/src-astro/code-container/Preview.astro +93 -0
  14. package/dist/src-astro/code-panel/CodePanel.astro +109 -0
  15. package/dist/src-astro/code-panel/index.ts +2 -0
  16. package/dist/src-astro/code-panel/types.ts +17 -0
  17. package/dist/src-astro/footer/Footer.astro +23 -20
  18. package/dist/src-astro/footer/FooterSection.astro +7 -9
  19. package/dist/src-astro/grid/index.ts +1 -9
  20. package/dist/src-astro/heading/index.ts +1 -9
  21. package/dist/src-astro/hero/Hero.astro +72 -8
  22. package/dist/src-astro/icons/CodeIcon.astro +22 -0
  23. package/dist/src-astro/icons/index.ts +2 -1
  24. package/dist/src-astro/install-tabs/ButtonCopyInstall.astro +102 -0
  25. package/dist/src-astro/install-tabs/InstallTabs.astro +174 -0
  26. package/dist/src-astro/install-tabs/index.ts +2 -0
  27. package/dist/src-astro/install-tabs/types.ts +8 -0
  28. package/dist/src-astro/language-switcher/LanguageSwitcher.astro +6 -2
  29. package/dist/src-astro/layout-app/AppLayout.astro +1 -10
  30. package/dist/src-astro/layout-basic/BaseLayout.astro +20 -4
  31. package/dist/src-astro/link/Link.astro +50 -3
  32. package/dist/src-astro/types/meta.ts +65 -53
  33. package/package.json +3 -2
  34. package/dist/src-astro/banner/BannerAllAnimations.astro +0 -10
  35. package/dist/src-astro/banner/BannerBasic.astro +0 -5
  36. package/dist/src-astro/banner/BannerCustomStyle.astro +0 -8
  37. package/dist/src-astro/banner/BannerDanger.astro +0 -5
  38. package/dist/src-astro/banner/BannerFadeIn.astro +0 -5
  39. package/dist/src-astro/banner/BannerInfo.astro +0 -5
  40. package/dist/src-astro/banner/BannerPrimary.astro +0 -5
  41. package/dist/src-astro/banner/BannerSecondary.astro +0 -5
  42. package/dist/src-astro/banner/BannerSlideUp.astro +0 -5
  43. package/dist/src-astro/banner/BannerSuccess.astro +0 -5
  44. package/dist/src-astro/banner/BannerWarning.astro +0 -5
  45. package/dist/src-astro/grid/GridBasic.astro +0 -21
  46. package/dist/src-astro/heading/HeadingBasic.astro +0 -10
@@ -0,0 +1,14 @@
1
+ ---
2
+ interface Props {
3
+ code: string;
4
+ }
5
+ const { code = '' } = Astro.props;
6
+ ---
7
+
8
+ <div class="cosy:hidden cosy:code-example-panel" data-panel="code">
9
+ <pre
10
+ class="cosy:overflow-x-auto"
11
+ style="margin:0">
12
+ <code class="cosy:language-astro">{code}</code>
13
+ </pre>
14
+ </div>
@@ -0,0 +1,100 @@
1
+ ---
2
+ import CodeToggleButton from './ButtonCodeToggle.astro';
3
+ import CopyCodeButton from './ButtonCopyCode.astro';
4
+
5
+ interface Props {
6
+ titles: string[];
7
+ activeTab: number;
8
+ isCodeView: boolean;
9
+ code: string;
10
+ }
11
+
12
+ const {
13
+ titles = [],
14
+ activeTab = 0,
15
+ isCodeView = false,
16
+ code = '',
17
+ } = Astro.props;
18
+ ---
19
+
20
+ <div
21
+ class="cosy:flex cosy:justify-between cosy:items-center cosy:bg-base-200 cosy:px-4 cosy:rounded-t">
22
+ <!-- 标签 -->
23
+ <div class="cosy:flex cosy:items-center cosy:gap-4">
24
+ <div role="tablist" class="cosy:tabs cosy:tabs-box">
25
+ {
26
+ titles.map((title: string, index: number) => (
27
+ <button
28
+ role="tab"
29
+ class={`cosy:tab ${index === activeTab ? 'cosy:tab-active' : ''}`}
30
+ data-tab={`tab-${index + 1}`}>
31
+ {title || `示例 ${index + 1}`}
32
+ </button>
33
+ ))
34
+ }
35
+ </div>
36
+ </div>
37
+ <!-- 工具按钮 -->
38
+ <div class="cosy:flex cosy:items-center cosy:gap-2">
39
+ <CodeToggleButton isCodeView={isCodeView} />
40
+ <CopyCodeButton code={code} />
41
+ </div>
42
+ </div>
43
+
44
+ <script>
45
+ function initializeTab() {
46
+ console.log('CodeContainer: 初始化标签切换按钮');
47
+
48
+ const exampleTabs = document.querySelectorAll(
49
+ '[role="tab"][data-tab^="tab-"]'
50
+ );
51
+ exampleTabs.forEach((tab) => {
52
+ tab.addEventListener('click', () => {
53
+ console.log('CodeContainer: 切换示例', tab.getAttribute('data-tab'));
54
+ const container = tab.closest('[data-role="code-container"]');
55
+ if (!container) return;
56
+
57
+ // 更新标签状态
58
+ container
59
+ .querySelectorAll('[role="tab"][data-tab^="tab-"]')
60
+ .forEach((t) => {
61
+ t.classList.remove('cosy:tab-active');
62
+ });
63
+ tab.classList.add('cosy:tab-active');
64
+
65
+ // 获取当前标签对应的内容 id
66
+ const targetId = tab.getAttribute('data-tab');
67
+ if (!targetId) return;
68
+
69
+ // 切换示例容器
70
+ container
71
+ .querySelectorAll('.cosy\\:example-container')
72
+ .forEach((example) => {
73
+ if (example.getAttribute('data-example') === targetId) {
74
+ example.classList.remove('cosy:hidden');
75
+ example.classList.add('cosy:block');
76
+ } else {
77
+ example.classList.add('cosy:hidden');
78
+ example.classList.remove('cosy:block');
79
+ }
80
+ });
81
+
82
+ // 更新对应内容的可见性
83
+ const allContent = container.querySelectorAll('[id^="tab-"]');
84
+ allContent.forEach((content) => {
85
+ if (content.id === targetId) {
86
+ content.classList.remove('cosy:hidden');
87
+ content.classList.add('cosy:block');
88
+ } else {
89
+ content.classList.add('cosy:hidden');
90
+ content.classList.remove('cosy:block');
91
+ }
92
+ });
93
+ });
94
+ });
95
+ }
96
+
97
+ document.addEventListener('astro:page-load', () => {
98
+ initializeTab();
99
+ });
100
+ </script>
@@ -0,0 +1,17 @@
1
+ ---
2
+ interface Props {
3
+ text: string;
4
+ }
5
+ const { text = '' } = Astro.props;
6
+ ---
7
+
8
+ {
9
+ text && (
10
+ <p
11
+ class="cosy:px-6 cosy:py-2 cosy:text-sm not-prose
12
+ cosy:bg-gradient-to-b cosy:from-blue-100/50 cosy:to-blue-100/90
13
+ cosy:dark:from-blue-900/20 cosy:dark:to-blue-900/20">
14
+ {text}
15
+ </p>
16
+ )
17
+ }
@@ -0,0 +1,93 @@
1
+ ---
2
+ // 预览组件,渲染slot内容
3
+ ---
4
+
5
+ <div class="cosy:code-example-panel cosy:block" data-panel="preview">
6
+ <slot />
7
+ </div>
8
+
9
+ <!-- 样式隔离和重置 -->
10
+ <style>
11
+ /* 预览区域样式重置,防止外部样式影响内部组件 */
12
+ [data-role='code-container'] .cosy\:reset-styles {
13
+ /* 重置所有可能影响布局的样式 */
14
+ all: initial;
15
+ font-family: inherit;
16
+ color: inherit;
17
+ line-height: 1.5;
18
+
19
+ /* 恢复必要的基础样式 */
20
+ display: block;
21
+ box-sizing: border-box;
22
+
23
+ /* 隔离样式作用域 */
24
+ isolation: isolate;
25
+ contain: layout style;
26
+ }
27
+
28
+ /* 重置内部所有元素的样式 */
29
+ [data-role='code-container'] .cosy\:reset-styles * {
30
+ all: unset;
31
+ display: revert;
32
+ box-sizing: border-box;
33
+ }
34
+
35
+ /* 恢复必要的文本样式 */
36
+ [data-role='code-container'] .cosy\:reset-styles {
37
+ font-family:
38
+ system-ui,
39
+ -apple-system,
40
+ BlinkMacSystemFont,
41
+ 'Segoe UI',
42
+ Roboto,
43
+ 'Helvetica Neue',
44
+ Arial,
45
+ sans-serif;
46
+ font-size: 14px;
47
+ line-height: 1.5;
48
+ color: #374151;
49
+ }
50
+
51
+ /* 恢复基本的HTML元素样式 */
52
+ [data-role='code-container'] .cosy\:reset-styles h1,
53
+ [data-role='code-container'] .cosy\:reset-styles h2,
54
+ [data-role='code-container'] .cosy\:reset-styles h3,
55
+ [data-role='code-container'] .cosy\:reset-styles h4,
56
+ [data-role='code-container'] .cosy\:reset-styles h5,
57
+ [data-role='code-container'] .cosy\:reset-styles h6 {
58
+ font-weight: bold;
59
+ margin-bottom: 0.5em;
60
+ }
61
+
62
+ [data-role='code-container'] .cosy\:reset-styles p {
63
+ margin-bottom: 1em;
64
+ }
65
+
66
+ [data-role='code-container'] .cosy\:reset-styles ul,
67
+ [data-role='code-container'] .cosy\:reset-styles ol {
68
+ padding-left: 1.5em;
69
+ margin-bottom: 1em;
70
+ }
71
+
72
+ [data-role='code-container'] .cosy\:reset-styles li {
73
+ margin-bottom: 0.25em;
74
+ }
75
+
76
+ /* 防止内部组件的样式泄漏到外部 */
77
+ [data-role='code-container'] .cosy\:code-preview-area {
78
+ position: relative;
79
+ z-index: 0;
80
+ }
81
+
82
+ /* 确保预览区域的样式隔离 */
83
+ [data-role='code-container'] .cosy\:code-preview-area::before {
84
+ content: '';
85
+ position: absolute;
86
+ top: -1px;
87
+ left: -1px;
88
+ right: -1px;
89
+ bottom: -1px;
90
+ pointer-events: none;
91
+ z-index: -1;
92
+ }
93
+ </style>
@@ -0,0 +1,109 @@
1
+ ---
2
+ /**
3
+ * @component CodePanel
4
+ *
5
+ * @description
6
+ * 代码展示面板组件,支持语法高亮、多主题切换和行号显示。
7
+ * 基于 Shiki 提供高质量的代码高亮效果,与 VS Code 保持一致的渲染效果。
8
+ * 支持服务端渲染,无需客户端 JavaScript 即可展示代码高亮。
9
+ *
10
+ * @features
11
+ * - 🎨 语法高亮:基于 Shiki,支持 180+ 编程语言
12
+ * - 🎭 多主题:支持 VS Code 主题(dark-plus、light-plus、github-dark 等)
13
+ * - 📏 行号显示:可选的行号显示功能
14
+ * - 🚀 性能优化:服务端渲染,避免客户端重复计算
15
+ * - 📱 响应式:自适应不同屏幕尺寸
16
+ * - 🎯 可访问性:语义化 HTML 结构,支持键盘导航
17
+ *
18
+ * @usage
19
+ * 基本用法:
20
+ * ```astro
21
+ * <CodePanel code="console.log('Hello, world!');" />
22
+ * ```
23
+ *
24
+ * 指定语言和主题:
25
+ * ```astro
26
+ * <CodePanel
27
+ * code="const name = 'TypeScript';"
28
+ * language="typescript"
29
+ * theme="github-dark"
30
+ * showLineNumbers={true}
31
+ * />
32
+ * ```
33
+ *
34
+ * 在切换面板中使用:
35
+ * ```astro
36
+ * <CodePanel
37
+ * code={sourceCode}
38
+ * language="astro"
39
+ * visible={false}
40
+ * />
41
+ * ```
42
+ *
43
+ * @props
44
+ * @param {string} code - 要显示的代码字符串
45
+ * @param {string} [language="typescript"] - 代码语言,用于语法高亮
46
+ * @param {string} [theme="dark-plus"] - 主题名称
47
+ * @param {boolean} [showLineNumbers=false] - 是否显示行号
48
+ * @param {boolean} [visible=true] - 是否显示在面板中
49
+ * @param {string} [class] - 自定义类名
50
+ *
51
+ * @slots
52
+ * 此组件不包含插槽,通过 props 传入代码内容
53
+ *
54
+ * @accessibility
55
+ * - 使用语义化的 HTML 结构
56
+ * - 代码区域具有适当的 aria 标签
57
+ * - 支持键盘导航和屏幕阅读器
58
+ * - 高对比度主题支持
59
+ */
60
+ import type { CodePanelProps } from './types';
61
+ import '../../style.ts';
62
+
63
+ interface Props extends CodePanelProps {}
64
+
65
+ const {
66
+ code = '',
67
+ language = 'typescript',
68
+ theme = 'dark-plus',
69
+ showLineNumbers = false,
70
+ visible = true,
71
+ class: className = '',
72
+ } = Astro.props;
73
+
74
+ // 优化 Shiki 加载 - 使用动态导入避免构建时创建多个实例
75
+ let highlightedCode = code;
76
+ try {
77
+ // 使用动态导入避免构建时的性能问题
78
+ const { createHighlighter } = await import('shiki');
79
+
80
+ const highlighter = await createHighlighter({
81
+ themes: [theme],
82
+ langs: [language],
83
+ });
84
+
85
+ highlightedCode = highlighter.codeToHtml(code, {
86
+ lang: language,
87
+ theme: theme,
88
+ transformers: [],
89
+ });
90
+
91
+ // 释放资源
92
+ highlighter.dispose?.();
93
+ } catch (error) {
94
+ console.warn(
95
+ 'CodePanel: Shiki highlighting failed, falling back to plain text:',
96
+ error
97
+ );
98
+ // 降级到普通代码块
99
+ highlightedCode = `<pre><code>${code}</code></pre>`;
100
+ }
101
+ ---
102
+
103
+ <div data-panel="code" role="region" aria-label="代码展示面板">
104
+ <!-- Shiki 渲染的代码 -->
105
+ <div
106
+ class="cosy:w-full not-prose cosy-shiki-container"
107
+ set:html={highlightedCode}
108
+ />
109
+ </div>
@@ -0,0 +1,2 @@
1
+ export { default as CodePanel } from './CodePanel.astro';
2
+ export type { CodePanelProps } from './types';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * CodePanel 组件的属性接口
3
+ */
4
+ export interface CodePanelProps {
5
+ /** 要显示的代码字符串 */
6
+ code: string;
7
+ /** 代码语言,用于语法高亮,默认 'typescript' */
8
+ language?: string;
9
+ /** 主题名称,默认 'dark-plus' */
10
+ theme?: 'dark-plus' | 'light-plus' | 'github-dark' | 'github-light' | 'nord' | 'dracula';
11
+ /** 是否显示行号,默认 false */
12
+ showLineNumbers?: boolean;
13
+ /** 是否显示在面板中(用于切换),默认 true */
14
+ visible?: boolean;
15
+ /** 自定义类名 */
16
+ class?: string;
17
+ }
@@ -172,6 +172,7 @@ import {
172
172
  LanguageUtil,
173
173
  type IFooterProps,
174
174
  createTextGetter,
175
+ Link,
175
176
  } from '../../index-astro';
176
177
  import FooterSection from './FooterSection.astro';
177
178
  import '../../style.ts';
@@ -242,9 +243,7 @@ const debugClasses = debug
242
243
  ]}>
243
244
  {/* 品牌区域 */}
244
245
  <aside class:list={['cosy:max-w-xs cosy:text-center', debugClasses.aside]}>
245
- <a
246
- href={homeLink}
247
- class="cosy:flex cosy:items-center cosy:gap-2 cosy:mb-4 cosy:no-underline">
246
+ <Link href={homeLink} align="center" noUnderline block class="cosy:mb-4">
248
247
  {
249
248
  logo && (
250
249
  <img
@@ -260,21 +259,25 @@ const debugClasses = debug
260
259
  <h2 class="cosy:font-bold cosy:text-xl">{siteName}</h2>
261
260
  <p class="cosy:text-base-content/70">{slogan}</p>
262
261
  </div>
263
- </a>
262
+ </Link>
264
263
 
265
264
  {/* 社交媒体链接 */}
266
265
  {
267
266
  processedSocialLinks.length > 0 && (
268
267
  <div class="cosy:flex cosy:justify-center cosy:gap-2 cosy:mt-4">
269
268
  {processedSocialLinks.map((link) => (
270
- <a
269
+ <Link
271
270
  href={link.url}
272
- class="cosy:btn cosy:btn-circle cosy:btn-ghost cosy:btn-sm"
273
- target="_blank"
271
+ btn
272
+ circle
273
+ ghost
274
+ size="sm"
275
+ color="primary"
276
+ external
274
277
  rel="noopener noreferrer"
275
278
  aria-label={link.name}>
276
279
  <SocialIcon platform={link.platform} />
277
- </a>
280
+ </Link>
278
281
  ))}
279
282
  </div>
280
283
  )
@@ -307,10 +310,10 @@ const debugClasses = debug
307
310
  <FooterSection
308
311
  title={t('about')}
309
312
  links={[
310
- { name: t('aboutUs'), href: aboutLink },
311
- { name: t('team'), href: teamLink },
312
- { name: t('careers'), href: careersLink },
313
- { name: t('contactUs'), href: contactLink },
313
+ { name: t('aboutUs'), href: aboutLink ?? '' },
314
+ { name: t('team'), href: teamLink ?? '' },
315
+ { name: t('careers'), href: careersLink ?? '' },
316
+ { name: t('contactUs'), href: contactLink ?? '' },
314
317
  ].filter((link) => link.href)}
315
318
  />
316
319
  )
@@ -328,11 +331,11 @@ const debugClasses = debug
328
331
  <FooterSection
329
332
  title={t('resources')}
330
333
  links={[
331
- { name: t('news'), href: newsLink },
332
- { name: t('blog'), href: blogLink },
333
- { name: t('faq'), href: faqLink },
334
- { name: t('history'), href: historyLink },
335
- { name: t('techStack'), href: techStackLink },
334
+ { name: t('news'), href: newsLink ?? '' },
335
+ { name: t('blog'), href: blogLink ?? '' },
336
+ { name: t('faq'), href: faqLink ?? '' },
337
+ { name: t('history'), href: historyLink ?? '' },
338
+ { name: t('techStack'), href: techStackLink ?? '' },
336
339
  ].filter((link) => link.href)}
337
340
  />
338
341
  )
@@ -344,8 +347,8 @@ const debugClasses = debug
344
347
  <FooterSection
345
348
  title={t('legal')}
346
349
  links={[
347
- { name: t('terms'), href: termsLink },
348
- { name: t('privacy'), href: privacyLink },
350
+ { name: t('terms'), href: termsLink ?? '' },
351
+ { name: t('privacy'), href: privacyLink ?? '' },
349
352
  ].filter((link) => link.href)}
350
353
  />
351
354
  )
@@ -366,7 +369,7 @@ const debugClasses = debug
366
369
  {/* 底部版权信息 */}
367
370
  <div
368
371
  class:list={[
369
- 'cosy:footer cosy:footer-center cosy:p-4 cosy:bg-base-300 cosy:text-base-content',
372
+ 'cosy:footer cosy:footer-center cosy:p-4 cosy:bg-base-300',
370
373
  debugClasses.footer,
371
374
  ]}>
372
375
  <aside
@@ -6,10 +6,7 @@
6
6
  * FooterSection 组件用于在页脚中显示一组链接,通常用于导航、产品列表等。
7
7
  */
8
8
 
9
- interface Link {
10
- name: string;
11
- href?: string;
12
- }
9
+ import { Link, type IProduct } from '../../index-astro';
13
10
 
14
11
  interface Props {
15
12
  /**
@@ -20,7 +17,7 @@ interface Props {
20
17
  /**
21
18
  * 链接列表
22
19
  */
23
- links: Link[];
20
+ links: IProduct[];
24
21
  }
25
22
 
26
23
  const { title, links } = Astro.props;
@@ -33,12 +30,13 @@ const { title, links } = Astro.props;
33
30
  links.map((link) => (
34
31
  <li class="cosy:list-none">
35
32
  {link.href ? (
36
- <a
33
+ <Link
37
34
  href={link.href}
38
- class="cosy:link cosy:link-hover cosy:no-underline cosy:hover:no-underline"
39
- >
35
+ size="sm"
36
+ target={link.external ? '_blank' : '_self'}
37
+ variant="text">
40
38
  {link.name}
41
- </a>
39
+ </Link>
42
40
  ) : (
43
41
  <span class="cosy:opacity-50">{link.name}</span>
44
42
  )}
@@ -1,11 +1,3 @@
1
1
  import Grid from './Grid.astro';
2
- import GridBasic from './GridBasic.astro';
3
- import BasicSourceCode from './GridBasic.astro?raw';
4
- import { extractSimpleExample } from '../../src/utils/component';
5
2
 
6
- export { Grid, GridBasic };
7
-
8
- // 导出示例源代码
9
- export const GridExampleCodes = {
10
- Basic: extractSimpleExample(BasicSourceCode, 'Grid'),
11
- };
3
+ export { Grid };
@@ -1,11 +1,3 @@
1
1
  import Heading from './Heading.astro';
2
- import HeadingBasic from './HeadingBasic.astro';
3
- import BasicSourceCode from './HeadingBasic.astro?raw';
4
- import { extractSimpleExample } from '../../src/utils/component';
5
2
 
6
- export { Heading, HeadingBasic };
7
-
8
- // 导出示例源代码
9
- export const HeadingExampleCodes = {
10
- Basic: extractSimpleExample(BasicSourceCode, 'Heading'),
11
- };
3
+ export { Heading };
@@ -143,7 +143,7 @@
143
143
  * @prop {string} links[].text - 链接按钮的文本
144
144
  * @prop {string} links[].href - 链接按钮的目标地址
145
145
  * @prop {string} links[].variant - 链接按钮的变体,可选值:"primary", "secondary", "accent", "info", "success", "warning", "error"
146
- * @prop {string} [background="gradient"] - 背景样式,可选值:"gradient", "plain"
146
+ * @prop {string} [background="gradient"] - 背景样式,可选值:"gradient", "plain", "gradient-primary", "gradient-secondary", "gradient-accent", "gradient-success", "gradient-warning", "gradient-info", "gradient-sky", "gradient-sunset", "gradient-forest", "gradient-ocean", "gradient-mountain", "gradient-flower", "gradient-watermelon", "gradient-lemon", "gradient-grape", "gradient-blueberry", "gradient-mango", "gradient-kiwi", "gradient-pitaya", "gradient-banana"
147
147
  * @prop {string} [align="center"] - 内容对齐方式,可选值:"center", "left", "right"
148
148
  * @prop {string} [imagePosition="right"] - 图片位置,可选值:"right", "left", "top", "bottom"
149
149
  * @prop {string} [backgroundImage] - 背景图片的URL
@@ -176,7 +176,29 @@ interface Props {
176
176
  alt: string;
177
177
  };
178
178
  links: Link[];
179
- background?: 'gradient' | 'plain';
179
+ background?:
180
+ | 'gradient'
181
+ | 'plain'
182
+ | 'gradient-primary'
183
+ | 'gradient-secondary'
184
+ | 'gradient-accent'
185
+ | 'gradient-success'
186
+ | 'gradient-warning'
187
+ | 'gradient-info'
188
+ | 'gradient-sky'
189
+ | 'gradient-sunset'
190
+ | 'gradient-forest'
191
+ | 'gradient-ocean'
192
+ | 'gradient-mountain'
193
+ | 'gradient-flower'
194
+ | 'gradient-watermelon'
195
+ | 'gradient-lemon'
196
+ | 'gradient-grape'
197
+ | 'gradient-blueberry'
198
+ | 'gradient-mango'
199
+ | 'gradient-kiwi'
200
+ | 'gradient-pitaya'
201
+ | 'gradient-banana';
180
202
  align?: 'center' | 'left' | 'right';
181
203
  imagePosition?: 'right' | 'left' | 'top' | 'bottom';
182
204
  backgroundImage?: string;
@@ -200,6 +222,49 @@ const {
200
222
  // 确保不透明度在0-1之间
201
223
  const safeOpacity = Math.max(0, Math.min(1, overlayOpacity));
202
224
 
225
+ // 渐变色背景映射
226
+ const gradientBgClassMap = {
227
+ gradient: 'cosy:bg-gradient-to-br cosy:from-primary/10 cosy:to-secondary/20',
228
+ 'gradient-primary':
229
+ 'cosy:bg-gradient-to-br cosy:from-primary-400 cosy:to-primary-700',
230
+ 'gradient-secondary':
231
+ 'cosy:bg-gradient-to-br cosy:from-secondary-400 cosy:to-secondary-700',
232
+ 'gradient-accent':
233
+ 'cosy:bg-gradient-to-br cosy:from-accent-400 cosy:to-accent-700',
234
+ 'gradient-success':
235
+ 'cosy:bg-gradient-to-br cosy:from-success-400 cosy:to-success-700',
236
+ 'gradient-warning':
237
+ 'cosy:bg-gradient-to-br cosy:from-warning-400 cosy:to-warning-700',
238
+ 'gradient-info': 'cosy:bg-gradient-to-br cosy:from-info-400 cosy:to-info-700',
239
+ 'gradient-sky': 'cosy:bg-gradient-to-br cosy:from-sky-400 cosy:to-indigo-500',
240
+ 'gradient-sunset':
241
+ 'cosy:bg-gradient-to-br cosy:from-orange-400 cosy:via-pink-500 cosy:to-red-500',
242
+ 'gradient-forest':
243
+ 'cosy:bg-gradient-to-br cosy:from-green-700 cosy:to-lime-300',
244
+ 'gradient-ocean':
245
+ 'cosy:bg-gradient-to-br cosy:from-cyan-400 cosy:to-blue-700',
246
+ 'gradient-mountain':
247
+ 'cosy:bg-gradient-to-br cosy:from-gray-400 cosy:to-blue-900',
248
+ 'gradient-flower':
249
+ 'cosy:bg-gradient-to-br cosy:from-pink-300 cosy:via-purple-400 cosy:to-fuchsia-500',
250
+ 'gradient-watermelon':
251
+ 'cosy:bg-gradient-to-br cosy:from-green-300 cosy:via-pink-400 cosy:to-red-500',
252
+ 'gradient-lemon':
253
+ 'cosy:bg-gradient-to-br cosy:from-yellow-200 cosy:via-yellow-400 cosy:to-yellow-600',
254
+ 'gradient-grape':
255
+ 'cosy:bg-gradient-to-br cosy:from-purple-400 cosy:via-indigo-500 cosy:to-purple-700',
256
+ 'gradient-blueberry':
257
+ 'cosy:bg-gradient-to-br cosy:from-blue-400 cosy:via-blue-600 cosy:to-indigo-700',
258
+ 'gradient-mango':
259
+ 'cosy:bg-gradient-to-br cosy:from-yellow-300 cosy:via-orange-400 cosy:to-orange-600',
260
+ 'gradient-kiwi':
261
+ 'cosy:bg-gradient-to-br cosy:from-lime-200 cosy:via-green-400 cosy:to-green-700',
262
+ 'gradient-pitaya':
263
+ 'cosy:bg-gradient-to-br cosy:from-pink-200 cosy:via-fuchsia-400 cosy:to-lime-300',
264
+ 'gradient-banana':
265
+ 'cosy:bg-gradient-to-br cosy:from-yellow-100 cosy:via-yellow-300 cosy:to-yellow-500',
266
+ };
267
+
203
268
  // 确定容器类
204
269
  const containerClasses = [
205
270
  'cosy:hero',
@@ -207,8 +272,9 @@ const containerClasses = [
207
272
  'cosy:w-full',
208
273
  'cosy:relative',
209
274
  backgroundImage ? 'cosy:bg-cover cosy:bg-center' : '',
210
- !backgroundImage && background === 'gradient'
211
- ? 'cosy:bg-gradient-to-br cosy:from-primary/10 cosy:to-secondary/20'
275
+ !backgroundImage && background.startsWith('gradient')
276
+ ? gradientBgClassMap[background as keyof typeof gradientBgClassMap] ||
277
+ gradientBgClassMap['gradient']
212
278
  : '',
213
279
  !backgroundImage && background === 'plain' ? 'cosy:bg-base-100' : '',
214
280
  ].join(' ');
@@ -330,7 +396,7 @@ const contentOrder = {
330
396
 
331
397
  <div
332
398
  class={containerClasses}
333
- style={backgroundImage ? `background-image: url(${backgroundImage})` : ''}
399
+ style={backgroundImage ? `background-image: url(${backgroundImage})` : {}}
334
400
  ignore-heading>
335
401
  {
336
402
  backgroundImage && backgroundOverlay !== 'none' && (
@@ -354,9 +420,7 @@ const contentOrder = {
354
420
  (align === 'left' ? 'cosy:text-left cosy:items-start' : '') +
355
421
  (align === 'right' ? 'cosy:text-right cosy:items-end' : '')}>
356
422
  <h2 class={titleClasses}>{title}</h2>
357
- <p class={descriptionClasses}>
358
- {description}
359
- </p>
423
+ <p class={descriptionClasses}>{description}</p>
360
424
 
361
425
  {
362
426
  Astro.slots.has('app') && (
@@ -0,0 +1,22 @@
1
+ ---
2
+ // @component CodeIcon
3
+ // @description 代码相关的图标,用于表示代码块、开发等场景
4
+ import AstroIcon from './AstroIcon.astro';
5
+
6
+ interface Props {
7
+ /** 图标的大小 @default "24px" */
8
+ size?: string;
9
+ /** 图标的颜色 @default "currentColor" */
10
+ color?: string;
11
+ /** 自定义类名 */
12
+ class?: string;
13
+ }
14
+
15
+ const {
16
+ size = '24px',
17
+ color = 'currentColor',
18
+ class: className = '',
19
+ } = Astro.props;
20
+ ---
21
+
22
+ <AstroIcon name="code" size={size} stroke={color} class={className} />