@coffic/cosy-ui 0.9.20 → 0.9.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 (37) hide show
  1. package/dist/app.css +1 -1
  2. package/dist/index-astro.ts +1 -1
  3. package/dist/src-astro/alert/Alert.astro +28 -1
  4. package/dist/src-astro/confirm-dialog/ConfirmDialog.astro +29 -4
  5. package/dist/src-astro/container/Container.astro +40 -0
  6. package/dist/src-astro/container/index.ts +0 -15
  7. package/dist/src-astro/errors/404.astro +4 -8
  8. package/dist/src-astro/heading/Heading.astro +202 -83
  9. package/dist/src-astro/heading/HeadingAnchor.astro +33 -0
  10. package/dist/src-astro/language-switcher/LanguageSwitcher.astro +1 -3
  11. package/dist/src-astro/layout-app/AppLayout.astro +160 -4
  12. package/dist/src-astro/layout-basic/BaseLayout.astro +2 -5
  13. package/dist/src-astro/layout-basic/index.ts +2 -0
  14. package/dist/src-astro/{types → layout-basic}/meta.ts +4 -0
  15. package/dist/src-astro/layout-dashboard/index.ts +1 -1
  16. package/dist/src-astro/modal/CloseButton.astro +28 -0
  17. package/dist/src-astro/modal/Modal.astro +47 -44
  18. package/dist/src-astro/placeholder/PlaceHolder.astro +142 -0
  19. package/dist/src-astro/placeholder/index.ts +2 -0
  20. package/dist/src-astro/placeholder/types.ts +16 -0
  21. package/dist/src-astro/products/ProductCard.astro +3 -1
  22. package/dist/src-astro/products/Products.astro +48 -0
  23. package/dist/src-astro/sidebar/Sidebar.astro +19 -20
  24. package/dist/src-astro/sidebar/SidebarNav.astro +6 -9
  25. package/dist/src-astro/types/layout.ts +1 -1
  26. package/package.json +17 -17
  27. package/dist/src-astro/container/EContainerBasic.astro +0 -15
  28. package/dist/src-astro/container/EContainerBasicContainer.astro +0 -11
  29. package/dist/src-astro/container/EContainerFlexBetween.astro +0 -23
  30. package/dist/src-astro/container/EContainerFlexCenter.astro +0 -30
  31. package/dist/src-astro/container/EContainerFlexColumn.astro +0 -23
  32. package/dist/src-astro/container/EContainerFlexContainer.astro +0 -34
  33. package/dist/src-astro/container/EContainerFlexRow.astro +0 -23
  34. package/dist/src-astro/container/EContainerPadding.astro +0 -32
  35. package/dist/src-astro/container/EContainerPaddingContainer.astro +0 -11
  36. package/dist/src-astro/container/EContainerSizes.astro +0 -36
  37. package/dist/src-astro/container/EContainerSizesContainer.astro +0 -11
@@ -37,6 +37,7 @@ export * from './src-astro/modal';
37
37
  export * from './src-astro/module';
38
38
  export * from './src-astro/nav-item';
39
39
  export * from './src-astro/nav-section';
40
+ export * from './src-astro/placeholder';
40
41
  export * from './src-astro/products';
41
42
  export * from './src-astro/register';
42
43
  export * from './src-astro/section';
@@ -59,7 +60,6 @@ export * from './src-astro/types/header';
59
60
  export * from './src-astro/types/heading';
60
61
  export * from './src-astro/types/layout';
61
62
  export * from './src-astro/types/main';
62
- export * from './src-astro/types/meta';
63
63
  export * from './src-astro/types/nav';
64
64
  export * from './src-astro/types/product';
65
65
  export * from './src-astro/types/sidebar';
@@ -21,12 +21,18 @@
21
21
  * <Alert type="warning" showIcon={false}>不显示图标的警告</Alert>
22
22
  * ```
23
23
  *
24
+ * 设置垂直外边距:
25
+ * ```astro
26
+ * <Alert type="info" marginY="md">带垂直外边距的提示</Alert>
27
+ * ```
28
+ *
24
29
  * 组合使用:
25
30
  * ```astro
26
31
  * <Alert
27
32
  * type="error"
28
33
  * title="提交失败"
29
34
  * class="my-custom-class"
35
+ * marginY="lg"
30
36
  * >
31
37
  * 请检查表单并重新提交
32
38
  * </Alert>
@@ -48,7 +54,7 @@
48
54
  * @prop {string} [class] - 自定义 CSS 类名
49
55
  * @prop {boolean} [closable=true] - 是否可关闭
50
56
  * @prop {boolean} [showIcon=true] - 是否显示图标
51
- * @prop {number} [bgOpacity=1] - 背景色透明度,取值范围 0~1,1 为不透明
57
+ * @prop {('xs'|'sm'|'md'|'lg'|'xl')} [marginY] - 垂直方向外边距大小
52
58
  *
53
59
  * @slots
54
60
  * @slot default - 提示内容
@@ -72,6 +78,7 @@ export interface AlertProps {
72
78
  closable?: boolean;
73
79
  showIcon?: boolean;
74
80
  variant?: 'solid' | 'outline' | 'dash' | 'soft';
81
+ marginY?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
75
82
  }
76
83
 
77
84
  const {
@@ -82,13 +89,33 @@ const {
82
89
  closable = true,
83
90
  showIcon = true,
84
91
  variant = 'solid',
92
+ marginY,
85
93
  } = Astro.props as AlertProps;
86
94
 
95
+ // 根据 marginY 值设置对应的 CSS 类
96
+ const getMarginYClass = (marginY?: string) => {
97
+ switch (marginY) {
98
+ case 'xs':
99
+ return 'cosy:my-1';
100
+ case 'sm':
101
+ return 'cosy:my-2';
102
+ case 'md':
103
+ return 'cosy:my-4';
104
+ case 'lg':
105
+ return 'cosy:my-8';
106
+ case 'xl':
107
+ return 'cosy:my-12';
108
+ default:
109
+ return '';
110
+ }
111
+ };
112
+
87
113
  // 组合样式
88
114
  const alertClass = [
89
115
  `cosy:alert-${type}`,
90
116
  variant !== 'solid' ? `cosy:alert-${variant}` : '',
91
117
  'cosy:alert-horizontal',
118
+ getMarginYClass(marginY),
92
119
  ]
93
120
  .filter(Boolean)
94
121
  .join(' ');
@@ -92,11 +92,27 @@ const style = getConfirmDialogStyle();
92
92
 
93
93
  <script is:inline define:vars={{ id }}>
94
94
  // 为了方便使用,我们提供一些辅助方法
95
- document.addEventListener('DOMContentLoaded', () => {
95
+ function initializeConfirmDialog() {
96
96
  const dialog = document.getElementById(id);
97
- if (!dialog) return;
97
+ if (!dialog) {
98
+ console.log('ConfirmDialog: dialog is null', id);
99
+ return;
100
+ }
101
+
102
+ console.log('ConfirmDialog: 初始化确认对话框', id);
103
+
104
+ // 使用事件委托来处理动态加载的内容
105
+ document.addEventListener('click', (event) => {
106
+ const target = event.target;
107
+ // 使用 closest() 查找最近的匹配元素,包括按钮内部的元素
108
+ const trigger = target.closest(`[data-confirm-dialog-target="${id}"]`);
109
+ if (trigger) {
110
+ console.log('ConfirmDialog: 触发确认对话框', id);
111
+ dialog.showModal();
112
+ }
113
+ });
98
114
 
99
- // 为所有触发这个确认框的按钮添加点击事件
115
+ // 为已存在的按钮添加点击事件(向后兼容)
100
116
  document
101
117
  .querySelectorAll(`[data-confirm-dialog-target="${id}"]`)
102
118
  .forEach((trigger) => {
@@ -115,5 +131,14 @@ const style = getConfirmDialogStyle();
115
131
  document.dispatchEvent(event);
116
132
  };
117
133
  }
118
- });
134
+ }
135
+
136
+ // 初始加载时初始化
137
+ document.addEventListener('DOMContentLoaded', initializeConfirmDialog);
138
+
139
+ // Astro 页面切换时重新初始化
140
+ document.addEventListener('astro:page-load', initializeConfirmDialog);
141
+
142
+ // 确保脚本加载后立即初始化
143
+ initializeConfirmDialog();
119
144
  </script>
@@ -49,6 +49,13 @@
49
49
  * </Container>
50
50
  * ```
51
51
  *
52
+ * 设置外边距:
53
+ * ```astro
54
+ * <Container margin="lg">
55
+ * <p>带有大外边距的容器</p>
56
+ * </Container>
57
+ * ```
58
+ *
52
59
  * Flex布局容器(按行排列):
53
60
  * ```astro
54
61
  * <Container flex="row" gap="md">
@@ -82,6 +89,23 @@ interface Props extends HTMLAttributes<'div'> {
82
89
  */
83
90
  padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
84
91
 
92
+ /**
93
+ * 外边距大小
94
+ * @default "none"
95
+ */
96
+ margin?:
97
+ | 'none'
98
+ | 'xs'
99
+ | 'sm'
100
+ | 'md'
101
+ | 'lg'
102
+ | 'xl'
103
+ | '2xl'
104
+ | '3xl'
105
+ | '4xl'
106
+ | '5xl'
107
+ | '6xl';
108
+
85
109
  /**
86
110
  * 是否居中显示
87
111
  * @default true
@@ -129,6 +153,7 @@ interface Props extends HTMLAttributes<'div'> {
129
153
  const {
130
154
  size = 'md',
131
155
  padding = 'md',
156
+ margin = 'none',
132
157
  centered = true,
133
158
  border = false,
134
159
  flex,
@@ -158,6 +183,20 @@ const paddingClasses = {
158
183
  xl: 'cosy:p-8',
159
184
  } as const;
160
185
 
186
+ const marginClasses = {
187
+ none: '',
188
+ xs: 'cosy:my-1',
189
+ sm: 'cosy:my-2',
190
+ md: 'cosy:my-4',
191
+ lg: 'cosy:my-6',
192
+ xl: 'cosy:my-8',
193
+ '2xl': 'cosy:my-12',
194
+ '3xl': 'cosy:my-16',
195
+ '4xl': 'cosy:my-20',
196
+ '5xl': 'cosy:my-24',
197
+ '6xl': 'cosy:my-32',
198
+ } as const;
199
+
161
200
  const flexClasses = {
162
201
  row: 'cosy:flex cosy:flex-row',
163
202
  col: 'cosy:flex cosy:flex-col',
@@ -197,6 +236,7 @@ const containerClasses = [
197
236
  centered ? 'cosy:mx-auto' : '',
198
237
  sizeClasses[size],
199
238
  paddingClasses[padding],
239
+ marginClasses[margin],
200
240
  border ? 'cosy:border cosy:rounded-lg' : '',
201
241
  flex ? flexClasses[flex] : '',
202
242
  flex ? gapClasses[gap] : '',
@@ -1,16 +1 @@
1
- import Container from './Container.astro';
2
- import ContainerBasicContainer from './EContainerBasicContainer.astro';
3
- import ContainerSizesContainer from './EContainerSizesContainer.astro';
4
- import ContainerPaddingContainer from './EContainerPaddingContainer.astro';
5
- import ContainerFlexContainer from './EContainerFlexContainer.astro';
6
-
7
1
  export { default as Container } from './Container.astro';
8
- export const ContainerPackage = {
9
- Container,
10
- ContainerContainers: {
11
- Basic: ContainerBasicContainer,
12
- Sizes: ContainerSizesContainer,
13
- Padding: ContainerPaddingContainer,
14
- Flex: ContainerFlexContainer,
15
- },
16
- };
@@ -37,6 +37,7 @@
37
37
 
38
38
  import '../../style.ts';
39
39
  import { LinkUtil } from '../../src/utils/link.ts';
40
+ import Button from '../button/Button.astro';
40
41
 
41
42
  const baseUrl = LinkUtil.getBaseUrl();
42
43
  const path = Astro.url.pathname;
@@ -105,15 +106,10 @@ const { debugKVs = {} } = Astro.props as Error404Props;
105
106
 
106
107
  <!-- 操作按钮 -->
107
108
  <div class="cosy:space-y-3">
108
- <a href={baseUrl} class="btn btn-primary cosy:w-full cosy:no-underline">
109
- 返回首页
110
- </a>
111
- <button
112
- onclick="history.back()"
113
- class="btn btn-outline cosy:w-full"
114
- type="button">
109
+ <Button href={baseUrl} variant="primary" block> 返回首页 </Button>
110
+ <Button onclick="history.back()" variant="outline" block>
115
111
  返回上一页
116
- </button>
112
+ </Button>
117
113
  </div>
118
114
 
119
115
  <!-- 帮助提示 -->
@@ -4,6 +4,8 @@
4
4
  *
5
5
  * @description
6
6
  * Heading 组件用于创建各级标题,提供一致的排版样式和灵活的定制选项。
7
+ * 支持链接功能,当传入 href 属性时,标题会变成可点击的链接。
8
+ * 组件保持语义化结构:即使作为链接使用时,仍然渲染正确的 h1-h6 标签。
7
9
  *
8
10
  * @design
9
11
  * 设计理念:
@@ -11,12 +13,14 @@
11
13
  * 2. 一致性 - 确保整个应用中标题样式的一致性
12
14
  * 3. 可定制性 - 支持多种配置选项,适应不同场景需求
13
15
  * 4. 无障碍性 - 遵循语义化HTML标准,确保屏幕阅读器可以正确解析内容结构
16
+ * 5. 链接支持 - 标题可以作为链接使用,提供更好的导航体验
14
17
  *
15
18
  * 视觉特点:
16
19
  * - 字体大小和粗细随级别变化
17
20
  * - 可选的下划线或底部边框
18
21
  * - 可定制的颜色和间距
19
22
  * - 响应式设计,在不同屏幕尺寸下保持良好的可读性
23
+ * - 链接状态下的悬停效果
20
24
  *
21
25
  * @usage
22
26
  * 基本用法:
@@ -26,6 +30,12 @@
26
30
  * <Heading level={3}>这是一个三级标题</Heading>
27
31
  * ```
28
32
  *
33
+ * 链接标题:
34
+ * ```astro
35
+ * <Heading level={2} href="/about">关于我们</Heading>
36
+ * <Heading level={3} href="https://example.com" external>外部链接标题</Heading>
37
+ * ```
38
+ *
29
39
  * 自定义样式:
30
40
  * ```astro
31
41
  * <Heading level={2} color="primary" underline>带下划线的二级标题</Heading>
@@ -41,13 +51,32 @@
41
51
  * <Heading level={1} class="cosy:mb-8">自定义底部间距的标题</Heading>
42
52
  * ```
43
53
  *
54
+ * 外边距控制:
55
+ * ```astro
56
+ * <Heading level={2} margin="none">无外边距的标题</Heading>
57
+ * <Heading level={2} margin="sm">小外边距的标题</Heading>
58
+ * <Heading level={2} margin="lg">大外边距的标题</Heading>
59
+ * <Heading level={2} margin="xl">超大外边距的标题</Heading>
60
+ * ```
61
+ *
62
+ * 背景色支持:
63
+ * ```astro
64
+ * <Heading level={3} background="base-300" padding="sm">带背景色的标题</Heading>
65
+ * <Heading level={3} background="primary" color="white">主要背景色标题</Heading>
66
+ * ```
67
+ *
44
68
  * @props
45
69
  * @prop {1|2|3|4|5|6} [level=2] - 标题级别,对应 h1-h6 标签
46
70
  * @prop {string} [id] - 标题的 ID,用于锚点链接
71
+ * @prop {string} [href] - 链接地址,传入后标题会变成可点击的链接
72
+ * @prop {boolean} [external=false] - 是否为外部链接,影响链接的打开方式
47
73
  * @prop {boolean} [anchor=false] - 是否显示锚点链接图标
48
74
  * @prop {boolean} [underline=false] - 是否显示下划线
49
75
  * @prop {string} [align='left'] - 文本对齐方式:'left', 'center', 'right'
50
76
  * @prop {'default'|'primary'|'secondary'|'accent'|'muted'} [color='default'] - 标题颜色
77
+ * @prop {'none'|'sm'|'md'|'lg'|'xl'} [margin='md'] - 上下外边距大小
78
+ * @prop {string} [background] - 背景色类名,如 'base-300', 'primary', 'secondary'
79
+ * @prop {'none'|'sm'|'md'|'lg'|'xl'} [padding='none'] - 内边距大小(仅在设置背景色时生效)
51
80
  * @prop {string} [class] - 自定义 CSS 类名
52
81
  *
53
82
  * @slots
@@ -57,32 +86,45 @@
57
86
  * - 使用语义化的 h1-h6 标签
58
87
  * - 锚点链接带有描述性 aria-label
59
88
  * - 遵循标题层次结构的最佳实践
89
+ * - 链接标题保持良好的可访问性
60
90
  *
61
91
  * @dependencies
62
- * 依赖于以下图标组件:
92
+ * 依赖于以下组件:
63
93
  * - LinkIcon (用于锚点链接)
94
+ * - Link (用于锚点链接)
64
95
  */
65
96
 
66
- import { LinkIcon } from '../../index-astro';
97
+ import HeadingAnchor from './HeadingAnchor.astro';
98
+ import Link from '../link/Link.astro';
67
99
  import '../../style.ts';
68
100
 
69
101
  interface Props {
70
102
  level?: 1 | 2 | 3 | 4 | 5 | 6;
71
103
  id?: string;
104
+ href?: string;
105
+ external?: boolean;
72
106
  anchor?: boolean;
73
107
  underline?: boolean;
74
108
  align?: 'left' | 'center' | 'right';
75
109
  color?: 'default' | 'primary' | 'secondary' | 'accent' | 'muted';
110
+ margin?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
111
+ background?: string;
112
+ padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
76
113
  class?: string;
77
114
  }
78
115
 
79
116
  const {
80
117
  level = 2,
81
118
  id,
119
+ href,
120
+ external = false,
82
121
  anchor = false,
83
122
  underline = false,
84
123
  align = 'left',
85
124
  color = 'default',
125
+ margin = 'md',
126
+ background,
127
+ padding = 'none',
86
128
  class: className = '',
87
129
  } = Astro.props;
88
130
 
@@ -97,7 +139,7 @@ const headingClass = {
97
139
  }[(level ?? 2) as 1 | 2 | 3 | 4 | 5 | 6];
98
140
 
99
141
  const colorClass = {
100
- default: 'cosy:text-gray-900 cosy:dark:text-gray-100',
142
+ default: '',
101
143
  primary: 'cosy:text-primary-600 cosy:dark:text-primary-400',
102
144
  secondary: 'cosy:text-secondary-600 cosy:dark:text-secondary-400',
103
145
  accent: 'cosy:text-accent-600 cosy:dark:text-accent-400',
@@ -121,109 +163,186 @@ const underlineClass = underline
121
163
  ? 'cosy:border-b cosy:pb-2 cosy:border-gray-200 cosy:dark:border-gray-700'
122
164
  : '';
123
165
 
166
+ // 外边距样式
167
+ const marginClass = {
168
+ none: '',
169
+ sm: 'cosy:my-2',
170
+ md: 'cosy:my-4',
171
+ lg: 'cosy:my-6',
172
+ xl: 'cosy:my-8',
173
+ }[(margin ?? 'md') as 'none' | 'sm' | 'md' | 'lg' | 'xl'];
174
+
175
+ // 背景色样式映射
176
+ const backgroundClassMap = {
177
+ 'base-100': 'cosy:bg-base-100 cosy:dark:bg-base-100',
178
+ 'base-200': 'cosy:bg-base-200 cosy:dark:bg-base-200',
179
+ 'base-300': 'cosy:bg-base-300 cosy:dark:bg-base-300',
180
+ primary: 'cosy:bg-primary cosy:dark:bg-primary',
181
+ secondary: 'cosy:bg-secondary cosy:dark:bg-secondary',
182
+ accent: 'cosy:bg-accent cosy:dark:bg-accent',
183
+ info: 'cosy:bg-info cosy:dark:bg-info',
184
+ success: 'cosy:bg-success cosy:dark:bg-success',
185
+ warning: 'cosy:bg-warning cosy:dark:bg-warning',
186
+ error: 'cosy:bg-error cosy:dark:bg-error',
187
+ } as const;
188
+
189
+ const backgroundClass = background
190
+ ? backgroundClassMap[background as keyof typeof backgroundClassMap] || ''
191
+ : '';
192
+
193
+ // 内边距样式映射
194
+ const paddingClassMap = {
195
+ none: '',
196
+ sm: 'cosy:py-2',
197
+ md: 'cosy:py-4',
198
+ lg: 'cosy:py-6',
199
+ xl: 'cosy:py-8',
200
+ } as const;
201
+
202
+ const paddingClass =
203
+ paddingClassMap[padding as keyof typeof paddingClassMap] || '';
204
+
124
205
  // 组合所有类名
125
- const combinedClass = `heading ${headingClass} ${colorClass} ${alignClass} ${underlineClass} ${className}`;
206
+ const combinedClass = `heading cosy:w-full ${headingClass} ${colorClass} ${alignClass} ${underlineClass} ${marginClass} ${backgroundClass} ${paddingClass} ${className}`;
207
+
208
+ // 如果有链接,添加链接相关的样式
209
+ const linkClass = href ? 'cosy:hover:opacity-80 cosy:transition-opacity' : '';
126
210
  ---
127
211
 
128
212
  {
129
- level === 1 && (
130
- <h1 id={id} class={combinedClass}>
131
- <slot />
132
- {anchor && id && (
133
- <a
134
- href={`#${id}`}
135
- class="cosy:hover:opacity-100 cosy:opacity-0 cosy:ml-2 cosy:transition-opacity heading-anchor"
136
- aria-label={`链接到 ${id} 部分`}>
137
- <LinkIcon class="cosy:inline-block cosy:w-4 cosy:h-4" />
138
- </a>
139
- )}
140
- </h1>
141
- )
213
+ level === 1 &&
214
+ (href ? (
215
+ <Link
216
+ href={href}
217
+ external={external}
218
+ class={`${linkClass}`}
219
+ noUnderline
220
+ fullWidth>
221
+ <h1 id={id} class={combinedClass}>
222
+ <slot />
223
+ <HeadingAnchor id={id} show={anchor} />
224
+ </h1>
225
+ </Link>
226
+ ) : (
227
+ <h1 id={id} class={combinedClass}>
228
+ <slot />
229
+ <HeadingAnchor id={id} show={anchor} />
230
+ </h1>
231
+ ))
142
232
  }
143
233
 
144
234
  {
145
- level === 2 && (
146
- <h2 id={id} class={combinedClass}>
147
- <slot />
148
- {anchor && id && (
149
- <a
150
- href={`#${id}`}
151
- class="cosy:hover:opacity-100 cosy:opacity-0 cosy:ml-2 cosy:transition-opacity heading-anchor"
152
- aria-label={`链接到 ${id} 部分`}>
153
- <LinkIcon class="cosy:inline-block cosy:w-4 cosy:h-4" />
154
- </a>
155
- )}
156
- </h2>
157
- )
235
+ level === 2 &&
236
+ (href ? (
237
+ <Link
238
+ href={href}
239
+ external={external}
240
+ class={`${linkClass}`}
241
+ noUnderline
242
+ fullWidth>
243
+ <h2 id={id} class={combinedClass}>
244
+ <slot />
245
+ <HeadingAnchor id={id} show={anchor} />
246
+ </h2>
247
+ </Link>
248
+ ) : (
249
+ <h2 id={id} class={combinedClass}>
250
+ <slot />
251
+ <HeadingAnchor id={id} show={anchor} />
252
+ </h2>
253
+ ))
158
254
  }
159
255
 
160
256
  {
161
- level === 3 && (
162
- <h3 id={id} class={combinedClass}>
163
- <slot />
164
- {anchor && id && (
165
- <a
166
- href={`#${id}`}
167
- class="cosy:hover:opacity-100 cosy:opacity-0 cosy:ml-2 cosy:transition-opacity heading-anchor"
168
- aria-label={`链接到 ${id} 部分`}>
169
- <LinkIcon class="cosy:inline-block cosy:w-4 cosy:h-4" />
170
- </a>
171
- )}
172
- </h3>
173
- )
257
+ level === 3 &&
258
+ (href ? (
259
+ <Link
260
+ href={href}
261
+ external={external}
262
+ class={`${linkClass}`}
263
+ noUnderline
264
+ fullWidth>
265
+ <h3 id={id} class={combinedClass}>
266
+ <slot />
267
+ <HeadingAnchor id={id} show={anchor} />
268
+ </h3>
269
+ </Link>
270
+ ) : (
271
+ <h3 id={id} class={combinedClass}>
272
+ <slot />
273
+ <HeadingAnchor id={id} show={anchor} />
274
+ </h3>
275
+ ))
174
276
  }
175
277
 
176
278
  {
177
- level === 4 && (
178
- <h4 id={id} class={combinedClass}>
179
- <slot />
180
- {anchor && id && (
181
- <a
182
- href={`#${id}`}
183
- class="cosy:hover:opacity-100 cosy:opacity-0 cosy:ml-2 cosy:transition-opacity heading-anchor"
184
- aria-label={`链接到 ${id} 部分`}>
185
- <LinkIcon class="cosy:inline-block cosy:w-4 cosy:h-4" />
186
- </a>
187
- )}
188
- </h4>
189
- )
279
+ level === 4 &&
280
+ (href ? (
281
+ <Link
282
+ href={href}
283
+ external={external}
284
+ class={`${linkClass}`}
285
+ noUnderline
286
+ fullWidth>
287
+ <h4 id={id} class={combinedClass}>
288
+ <slot />
289
+ <HeadingAnchor id={id} show={anchor} />
290
+ </h4>
291
+ </Link>
292
+ ) : (
293
+ <h4 id={id} class={combinedClass}>
294
+ <slot />
295
+ <HeadingAnchor id={id} show={anchor} />
296
+ </h4>
297
+ ))
190
298
  }
191
299
 
192
300
  {
193
- level === 5 && (
194
- <h5 id={id} class={combinedClass}>
195
- <slot />
196
- {anchor && id && (
197
- <a
198
- href={`#${id}`}
199
- class="cosy:hover:opacity-100 cosy:opacity-0 cosy:ml-2 cosy:transition-opacity heading-anchor"
200
- aria-label={`链接到 ${id} 部分`}>
201
- <LinkIcon class="cosy:inline-block cosy:w-4 cosy:h-4" />
202
- </a>
203
- )}
204
- </h5>
205
- )
301
+ level === 5 &&
302
+ (href ? (
303
+ <Link
304
+ href={href}
305
+ external={external}
306
+ class={`${linkClass}`}
307
+ noUnderline
308
+ fullWidth>
309
+ <h5 id={id} class={combinedClass}>
310
+ <slot />
311
+ <HeadingAnchor id={id} show={anchor} />
312
+ </h5>
313
+ </Link>
314
+ ) : (
315
+ <h5 id={id} class={combinedClass}>
316
+ <slot />
317
+ <HeadingAnchor id={id} show={anchor} />
318
+ </h5>
319
+ ))
206
320
  }
207
321
 
208
322
  {
209
- level === 6 && (
210
- <h6 id={id} class={combinedClass}>
211
- <slot />
212
- {anchor && id && (
213
- <a
214
- href={`#${id}`}
215
- class="cosy:hover:opacity-100 cosy:opacity-0 cosy:ml-2 cosy:transition-opacity heading-anchor"
216
- aria-label={`链接到 ${id} 部分`}>
217
- <LinkIcon class="cosy:inline-block cosy:w-4 cosy:h-4" />
218
- </a>
219
- )}
220
- </h6>
221
- )
323
+ level === 6 &&
324
+ (href ? (
325
+ <Link
326
+ href={href}
327
+ external={external}
328
+ class={`${linkClass}`}
329
+ noUnderline
330
+ fullWidth>
331
+ <h6 id={id} class={combinedClass}>
332
+ <slot />
333
+ <HeadingAnchor id={id} show={anchor} />
334
+ </h6>
335
+ </Link>
336
+ ) : (
337
+ <h6 id={id} class={combinedClass}>
338
+ <slot />
339
+ <HeadingAnchor id={id} show={anchor} />
340
+ </h6>
341
+ ))
222
342
  }
223
343
 
224
344
  <style>
225
345
  .heading {
226
- margin-bottom: 0.5em;
227
346
  line-height: 1.2;
228
347
  scroll-margin-top: 100px;
229
348
  }
@@ -0,0 +1,33 @@
1
+ ---
2
+ /**
3
+ * @component HeadingAnchor
4
+ *
5
+ * @description
6
+ * HeadingAnchor 组件用于在标题中显示锚点链接图标。
7
+ * 这是一个内部组件,专门为 Heading 组件设计。
8
+ *
9
+ * @props
10
+ * @prop {string} id - 锚点的 ID
11
+ * @prop {boolean} [show=false] - 是否显示锚点链接
12
+ */
13
+
14
+ import { LinkIcon, Link } from '../../index-astro';
15
+
16
+ interface Props {
17
+ id?: string;
18
+ show?: boolean;
19
+ }
20
+
21
+ const { id, show = false } = Astro.props;
22
+ ---
23
+
24
+ {
25
+ show && id && (
26
+ <Link
27
+ href={`#${id}`}
28
+ class="cosy:ml-2 heading-anchor"
29
+ aria-label={`链接到 ${id} 部分`}>
30
+ <LinkIcon size="16px" class="cosy:inline-block" />
31
+ </Link>
32
+ )
33
+ }