@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
@@ -76,9 +76,7 @@ if (renderState.shouldRender && Astro.currentLocale) {
76
76
 
77
77
  {
78
78
  renderState.shouldRender && (
79
- <div
80
- transition:persist
81
- class={`cosy:dropdown cosy:dropdown-end ${className}`}>
79
+ <div class={`cosy:dropdown cosy:dropdown-end ${className}`}>
82
80
  <div tabindex="0" role="button" class:list={['cosy:btn cosy:btn-ghost']}>
83
81
  <span class="cosy:mr-1">{renderState.currentLanguageName}</span>
84
82
  <ChevronDownIcon size="16px" class="cosy:w-4 cosy:h-4" />
@@ -49,6 +49,12 @@
49
49
  * @param {Object} metaConfig - 元数据配置
50
50
  * @param {Object} rest - 其他属性
51
51
  *
52
+ * @slot default - 主内容区域
53
+ * @slot navbar-start - 导航栏开始位置的内容
54
+ * @slot navbar-center - 导航栏中间位置的内容
55
+ * @slot navbar-end - 导航栏结束位置的内容
56
+ * @slot modal-search - 搜索模态框内容,当提供此slot时会显示搜索按钮
57
+ *
52
58
  * @example
53
59
  * ```astro
54
60
  * ---
@@ -163,6 +169,72 @@
163
169
  * <p>这是文档的主要内容</p>
164
170
  * </AppLayout>
165
171
  * ```
172
+ *
173
+ * 自定义导航栏示例:
174
+ * ```astro
175
+ * <AppLayout
176
+ * metaConfig={{
177
+ * title: "文档标题",
178
+ * description: "文档描述"
179
+ * }}
180
+ * sidebarConfig={{
181
+ * sidebarItems: sidebarItems
182
+ * }}
183
+ * >
184
+ * <!-- 导航栏开始位置 -->
185
+ * <div slot="navbar-start">
186
+ * <h1 class="cosy:text-xl cosy:font-bold">我的应用</h1>
187
+ * </div>
188
+ *
189
+ * <!-- 导航栏中间位置 -->
190
+ * <div slot="navbar-center">
191
+ * <nav class="cosy:flex cosy:gap-4">
192
+ * <a href="/docs" class="cosy:link cosy:link-hover">文档</a>
193
+ * <a href="/components" class="cosy:link cosy:link-hover">组件</a>
194
+ * <a href="/examples" class="cosy:link cosy:link-hover">示例</a>
195
+ * </nav>
196
+ * </div>
197
+ *
198
+ * <!-- 导航栏结束位置 -->
199
+ * <div slot="navbar-end">
200
+ * <button class="cosy:btn cosy:btn-primary">登录</button>
201
+ * </div>
202
+ *
203
+ * <h1>文档内容</h1>
204
+ * <p>这是文档的主要内容</p>
205
+ * </AppLayout>
206
+ * ```
207
+ *
208
+ * 搜索功能示例:
209
+ * ```astro
210
+ * <AppLayout
211
+ * metaConfig={{
212
+ * title: "文档标题",
213
+ * description: "文档描述"
214
+ * }}
215
+ * sidebarConfig={{
216
+ * sidebarItems: sidebarItems
217
+ * }}
218
+ * >
219
+ * <h1>文档内容</h1>
220
+ * <p>这是文档的主要内容</p>
221
+ *
222
+ * <!-- 提供搜索模态框内容,会自动显示搜索按钮 -->
223
+ * <div slot="modal-search">
224
+ * <div class="cosy:space-y-4">
225
+ * <input
226
+ * type="text"
227
+ * placeholder="搜索文档..."
228
+ * class="cosy:input cosy:input-bordered cosy:w-full"
229
+ * />
230
+ * <div class="cosy:flex cosy:gap-2">
231
+ * <button class="cosy:btn cosy:btn-primary">搜索</button>
232
+ * <button class="cosy:btn cosy:btn-ghost">清除</button>
233
+ * </div>
234
+ * </div>
235
+ * </div>
236
+ * </AppLayout>
237
+ * ```
166
238
  */
167
239
 
168
240
  import '../../style.ts';
@@ -174,6 +246,9 @@ import {
174
246
  Container,
175
247
  Main,
176
248
  Sidebar,
249
+ Modal,
250
+ SearchIcon,
251
+ Button,
177
252
  } from '../../index-astro';
178
253
  import SkeletonLoader from './SkeletonLoader.astro';
179
254
 
@@ -194,6 +269,60 @@ const {
194
269
  loadingDelay = 100,
195
270
  ...rest
196
271
  }: Props = Astro.props;
272
+
273
+ // 动态计算Container最小高度
274
+ function getContainerMinHeightClass(headerHeight: string = 'md') {
275
+ const heightValueMap = {
276
+ '3xs': 'cosy:min-h-[calc(100vh-1rem)]',
277
+ '2xs': 'cosy:min-h-[calc(100vh-1.5rem)]',
278
+ xs: 'cosy:min-h-[calc(100vh-2rem)]',
279
+ sm: 'cosy:min-h-[calc(100vh-2.5rem)]',
280
+ md: 'cosy:min-h-[calc(100vh-3rem)]',
281
+ lg: 'cosy:min-h-[calc(100vh-4rem)]',
282
+ xl: 'cosy:min-h-[calc(100vh-5rem)]',
283
+ };
284
+ return (
285
+ heightValueMap[headerHeight as keyof typeof heightValueMap] ||
286
+ 'cosy:min-h-[calc(100vh-3rem)]'
287
+ );
288
+ }
289
+
290
+ const containerMinHeightClass = getContainerMinHeightClass(
291
+ headerConfig?.height
292
+ );
293
+
294
+ // 计算Sidebar的top值和高度值
295
+ function getSidebarTopClass(headerHeight: string = 'md') {
296
+ const topMap = {
297
+ '3xs': 'cosy:top-4',
298
+ '2xs': 'cosy:top-6',
299
+ xs: 'cosy:top-8',
300
+ sm: 'cosy:top-10',
301
+ md: 'cosy:top-12',
302
+ lg: 'cosy:top-16',
303
+ xl: 'cosy:top-20',
304
+ };
305
+ return topMap[headerHeight as keyof typeof topMap] || 'cosy:top-12';
306
+ }
307
+
308
+ function getSidebarHeightClass(headerHeight: string = 'md') {
309
+ const heightValueMap = {
310
+ '3xs': 'cosy:h-[calc(100vh-1rem)]',
311
+ '2xs': 'cosy:h-[calc(100vh-1.5rem)]',
312
+ xs: 'cosy:h-[calc(100vh-2rem)]',
313
+ sm: 'cosy:h-[calc(100vh-2.5rem)]',
314
+ md: 'cosy:h-[calc(100vh-3rem)]',
315
+ lg: 'cosy:h-[calc(100vh-4rem)]',
316
+ xl: 'cosy:h-[calc(100vh-5rem)]',
317
+ };
318
+ return (
319
+ heightValueMap[headerHeight as keyof typeof heightValueMap] ||
320
+ 'cosy:h-[calc(100vh-3rem)]'
321
+ );
322
+ }
323
+
324
+ const sidebarTopClass = getSidebarTopClass(headerConfig?.height);
325
+ const sidebarHeightClass = getSidebarHeightClass(headerConfig?.height);
197
326
  ---
198
327
 
199
328
  <BaseLayout {...metaConfig} debug={debug}>
@@ -207,23 +336,41 @@ const {
207
336
  <slot name="navbar-center" />
208
337
  </div>
209
338
  <div slot="navbar-end">
339
+ {Astro.slots.has('modal-search') && (
340
+ <Button data-modal-target="modalSearch" variant="ghost" size="sm">
341
+ <SearchIcon size="24px" />
342
+ </Button>
343
+ )}
210
344
  <slot name="navbar-end" />
211
345
  </div>
212
346
  </Header>
213
347
  )
214
348
  }
215
349
 
216
- <Container flex="row" gap="md" size="full" padding="none">
350
+ <Container
351
+ flex="row"
352
+ gap="none"
353
+ size="full"
354
+ padding="none"
355
+ class={containerMinHeightClass}>
217
356
  <!-- 侧边栏容器 -->
218
- {showSidebar && <Sidebar {...sidebarConfig} />}
357
+ {
358
+ showSidebar && (
359
+ <Sidebar
360
+ {...sidebarConfig}
361
+ topClass={sidebarTopClass}
362
+ heightClass={sidebarHeightClass}
363
+ />
364
+ )
365
+ }
219
366
 
220
367
  <!-- 主内容区域 -->
221
- <Main {...mainContentConfig}>
368
+ <Main {...mainContentConfig} class="cosy:flex-1 cosy:min-w-0">
222
369
  <SkeletonLoader
223
370
  showLoading={true}
224
371
  loadingSize="xl"
225
372
  loadingDelay={loadingDelay}
226
- skeletonClass="cosy:w-full cosy:h-screen cosy:flex cosy:items-center cosy:justify-center">
373
+ skeletonClass="cosy:w-full cosy:h-screen cosy:flex cosy:items-center cosy:justify-center">
227
374
  <slot />
228
375
  </SkeletonLoader>
229
376
  </Main>
@@ -238,6 +385,15 @@ const {
238
385
  )
239
386
  }
240
387
 
388
+ <!-- 搜索模态框 -->
389
+ {
390
+ Astro.slots.has('modal-search') && (
391
+ <Modal id="modalSearch" title="搜索">
392
+ <slot name="modal-search" />
393
+ </Modal>
394
+ )
395
+ }
396
+
241
397
  <script>
242
398
  // Handle sidebar toggle
243
399
  const sidebarToggle = document.getElementById('sidebar-toggle');
@@ -50,13 +50,10 @@
50
50
  */
51
51
 
52
52
  import '../../style.ts';
53
- import { type IMetaProps } from '../../index-astro';
53
+ import { type IMetaProps } from './meta';
54
54
  import { ClientRouter } from 'astro:transitions';
55
55
 
56
- export interface Props extends IMetaProps {
57
- /** 最小显示时间(毫秒),默认300ms,确保用户能看到加载状态 */
58
- loadingMinDisplayTime?: number;
59
- }
56
+ export interface Props extends IMetaProps {}
60
57
 
61
58
  const {
62
59
  title,
@@ -1,3 +1,5 @@
1
1
  import BaseLayout from './BaseLayout.astro';
2
2
 
3
3
  export { BaseLayout };
4
+
5
+ export type { IMetaProps } from './meta';
@@ -66,4 +66,8 @@ export interface IMetaProps {
66
66
  * @default 'default'
67
67
  */
68
68
  background?: 'default' | 'white' | 'gray' | 'dark' | 'gradient-blue' | 'gradient-pink' | 'gradient-green';
69
+
70
+
71
+ /** 最小显示时间(毫秒),默认300ms,确保用户能看到加载状态 */
72
+ loadingMinDisplayTime?: number;
69
73
  }
@@ -13,5 +13,5 @@ export {
13
13
  };
14
14
 
15
15
  // 导出类型和函数
16
- export type { NavItem, SidebarSize, UserMenuItem } from './types';
16
+ export type { SidebarSize, UserMenuItem } from './types';
17
17
  export { getIconFromHref, getNavItemIcon, getSidebarWidth } from './types';
@@ -0,0 +1,28 @@
1
+ ---
2
+ /**
3
+ * @component CloseButton
4
+ *
5
+ * @description
6
+ * 模态框的关闭按钮组件,用于关闭模态对话框。
7
+ * 使用 form method="dialog" 来关闭模态框。
8
+ *
9
+ * @usage
10
+ * ```astro
11
+ * <CloseButton />
12
+ * ```
13
+ */
14
+
15
+ import '../../style.ts';
16
+ import { Button } from '../../index-astro';
17
+ ---
18
+
19
+ <form method="dialog">
20
+ <Button
21
+ variant="accent"
22
+ size="sm"
23
+ shape="circle"
24
+ formmethod="dialog"
25
+ class="cosy:modal-close-button">
26
+
27
+ </Button>
28
+ </form>
@@ -45,7 +45,8 @@
45
45
  */
46
46
 
47
47
  import '../../style.ts';
48
- import { Button } from '../../index-astro';
48
+ import { Heading } from '../../index-astro';
49
+ import CloseButton from './CloseButton.astro';
49
50
 
50
51
  interface Props {
51
52
  /**
@@ -56,43 +57,24 @@ interface Props {
56
57
  * 模态框的标题
57
58
  */
58
59
  title?: string;
59
- /**
60
- * 是否显示关闭按钮
61
- * @default true
62
- */
63
- showCloseButton?: boolean;
64
60
  /**
65
61
  * 自定义类名
66
62
  */
67
63
  class?: string;
68
64
  }
69
65
 
70
- const {
71
- id,
72
- title,
73
- showCloseButton = true,
74
- class: className = '',
75
- } = Astro.props;
66
+ const { id, title = '', class: className = '' } = Astro.props;
76
67
  ---
77
68
 
78
69
  <dialog id={id} class="cosy:modal">
79
- <div class:list={['cosy:modal-box', className]}>
80
- {
81
- showCloseButton && (
82
- <form method="dialog">
83
- <Button
84
- variant="ghost"
85
- size="sm"
86
- shape="circle"
87
- formmethod="dialog"
88
- class="cosy:modal-close-button">
89
-
90
- </Button>
91
- </form>
92
- )
93
- }
94
-
95
- {title && <h3 class="cosy:modal-title">{title}</h3>}
70
+ <div class:list={['cosy:modal-box cosy:pt-0', className]}>
71
+ <div
72
+ class="cosy:flex cosy:justify-between cosy:items-center cosy:border-b-1 cosy:border-base-300 cosy:mb-4 not-prose">
73
+ <Heading level={4} class="cosy:modal-title cosy:m-0">
74
+ {title}
75
+ </Heading>
76
+ <CloseButton class="cosy:absolute" />
77
+ </div>
96
78
 
97
79
  <div class="cosy:modal-content">
98
80
  <slot />
@@ -102,25 +84,46 @@ const {
102
84
  <slot name="actions" />
103
85
  </div>
104
86
  </div>
105
-
106
- <form method="dialog" class="cosy:modal-backdrop">
107
- <button>关闭</button>
108
- </form>
109
87
  </dialog>
110
88
 
111
89
  <script is:inline define:vars={{ id }}>
112
- // 为了方便使用,我们提供一些辅助方法
113
- document.addEventListener('DOMContentLoaded', () => {
90
+ let handleClick;
91
+
92
+ function initializeModal() {
114
93
  const modal = document.getElementById(id);
115
- if (!modal) return;
94
+ if (!modal) {
95
+ return;
96
+ }
116
97
 
117
- // 为所有触发这个模态框的按钮添加点击事件
118
- document
119
- .querySelectorAll(`[data-modal-target="${id}"]`)
120
- .forEach((trigger) => {
121
- trigger.addEventListener('click', () => {
122
- modal.showModal();
123
- });
124
- });
98
+ // 移除之前的事件监听器(如果存在)
99
+ if (handleClick) {
100
+ document.removeEventListener('click', handleClick);
101
+ }
102
+
103
+ // 使用事件委托来处理动态加载的内容
104
+ handleClick = (event) => {
105
+ const target = event.target;
106
+ // 使用 closest() 查找最近的匹配元素,包括按钮内部的元素
107
+ const trigger = target.closest(`[data-modal-target="${id}"]`);
108
+ if (trigger) {
109
+ console.log('Modal: 触发模态框', id);
110
+ modal.showModal();
111
+ }
112
+ };
113
+
114
+ document.addEventListener('click', handleClick);
115
+ }
116
+
117
+ // Astro 页面切换时初始化
118
+ document.addEventListener('astro:page-load', () => {
119
+ initializeModal();
120
+ });
121
+
122
+ // 页面卸载时清理事件监听器
123
+ document.addEventListener('astro:before-preparation', () => {
124
+ if (handleClick) {
125
+ document.removeEventListener('click', handleClick);
126
+ handleClick = null;
127
+ }
125
128
  });
126
129
  </script>
@@ -0,0 +1,142 @@
1
+ ---
2
+ /**
3
+ * @component PlaceHolder
4
+ * @description 占位符组件,用于在布局中占用指定的空间
5
+ * @usage
6
+ * ```astro
7
+ * <PlaceHolder width="md" height="lg" padding="md" background="base-200">
8
+ * <p>内容</p>
9
+ * </PlaceHolder>
10
+ * ```
11
+ * @props
12
+ * - width: 宽度尺寸 ('none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | 'full')
13
+ * - height: 高度尺寸 ('none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | 'full')
14
+ * - padding: 内边距大小 ('none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl')
15
+ * - background: 背景色类名,如 'base-200', 'primary', 'secondary'
16
+ * - class: 自定义 CSS 类名
17
+ * @slots
18
+ * - default: 占位符内容
19
+ */
20
+ import '../../style.ts';
21
+ import type { PlaceHolderProps } from './types';
22
+
23
+ interface Props extends PlaceHolderProps {
24
+ width?:
25
+ | 'none'
26
+ | 'xs'
27
+ | 'sm'
28
+ | 'md'
29
+ | 'lg'
30
+ | 'xl'
31
+ | '2xl'
32
+ | '3xl'
33
+ | '4xl'
34
+ | '5xl'
35
+ | '6xl'
36
+ | 'full';
37
+ height?:
38
+ | 'none'
39
+ | 'xs'
40
+ | 'sm'
41
+ | 'md'
42
+ | 'lg'
43
+ | 'xl'
44
+ | '2xl'
45
+ | '3xl'
46
+ | '4xl'
47
+ | '5xl'
48
+ | '6xl'
49
+ | 'full';
50
+ padding?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
51
+ background?: string;
52
+ class?: string;
53
+ }
54
+
55
+ const {
56
+ width = 'md',
57
+ height = 'md',
58
+ padding = 'none',
59
+ background,
60
+ class: className = '',
61
+ } = Astro.props;
62
+
63
+ // 宽度样式映射
64
+ const widthClassMap = {
65
+ none: '',
66
+ xs: 'cosy:w-8',
67
+ sm: 'cosy:w-16',
68
+ md: 'cosy:w-24',
69
+ lg: 'cosy:w-32',
70
+ xl: 'cosy:w-40',
71
+ '2xl': 'cosy:w-48',
72
+ '3xl': 'cosy:w-56',
73
+ '4xl': 'cosy:w-64',
74
+ '5xl': 'cosy:w-72',
75
+ '6xl': 'cosy:w-80',
76
+ full: 'cosy:w-full',
77
+ } as const;
78
+
79
+ // 高度样式映射
80
+ const heightClassMap = {
81
+ none: '',
82
+ xs: 'cosy:h-8',
83
+ sm: 'cosy:h-16',
84
+ md: 'cosy:h-24',
85
+ lg: 'cosy:h-32',
86
+ xl: 'cosy:h-40',
87
+ '2xl': 'cosy:h-48',
88
+ '3xl': 'cosy:h-56',
89
+ '4xl': 'cosy:h-64',
90
+ '5xl': 'cosy:h-72',
91
+ '6xl': 'cosy:h-80',
92
+ full: 'cosy:h-full',
93
+ } as const;
94
+
95
+ // 内边距样式映射
96
+ const paddingClassMap = {
97
+ none: '',
98
+ xs: 'cosy:p-1',
99
+ sm: 'cosy:p-2',
100
+ md: 'cosy:p-4',
101
+ lg: 'cosy:p-6',
102
+ xl: 'cosy:p-8',
103
+ } as const;
104
+
105
+ // 背景色样式映射
106
+ const backgroundClassMap = {
107
+ 'base-100': 'cosy:bg-base-100',
108
+ 'base-200': 'cosy:bg-base-200',
109
+ 'base-300': 'cosy:bg-base-300',
110
+ primary: 'cosy:bg-primary',
111
+ secondary: 'cosy:bg-secondary',
112
+ accent: 'cosy:bg-accent',
113
+ info: 'cosy:bg-info',
114
+ success: 'cosy:bg-success',
115
+ warning: 'cosy:bg-warning',
116
+ error: 'cosy:bg-error',
117
+ } as const;
118
+
119
+ const widthClass = widthClassMap[width as keyof typeof widthClassMap] || '';
120
+ const heightClass = heightClassMap[height as keyof typeof heightClassMap] || '';
121
+ const paddingClass =
122
+ paddingClassMap[padding as keyof typeof paddingClassMap] || '';
123
+ const backgroundClass = background
124
+ ? backgroundClassMap[background as keyof typeof backgroundClassMap] || ''
125
+ : '';
126
+
127
+ const combinedClass =
128
+ `placeholder ${widthClass} ${heightClass} ${paddingClass} ${backgroundClass} ${className}`.trim();
129
+ ---
130
+
131
+ <div class={combinedClass}>
132
+ <slot />
133
+ </div>
134
+
135
+ <style>
136
+ .placeholder {
137
+ display: flex;
138
+ align-items: center;
139
+ justify-content: center;
140
+ border-radius: 0.5rem;
141
+ }
142
+ </style>
@@ -0,0 +1,2 @@
1
+ export { default as PlaceHolder } from './PlaceHolder.astro';
2
+ export type { PlaceHolderProps, PlaceHolderWidth, PlaceHolderHeight, PlaceHolderPadding } from './types';
@@ -0,0 +1,16 @@
1
+ export type PlaceHolderWidth = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | 'full';
2
+ export type PlaceHolderHeight = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | 'full';
3
+ export type PlaceHolderPadding = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
4
+
5
+ export interface PlaceHolderProps {
6
+ /** 占位符宽度 */
7
+ width?: PlaceHolderWidth;
8
+ /** 占位符高度 */
9
+ height?: PlaceHolderHeight;
10
+ /** 内边距大小 */
11
+ padding?: PlaceHolderPadding;
12
+ /** 背景色类名,如 'base-200', 'primary', 'secondary' */
13
+ background?: string;
14
+ /** 自定义 CSS 类名 */
15
+ class?: string;
16
+ }
@@ -81,6 +81,8 @@
81
81
  * description="无阴影的简洁风格"
82
82
  * />
83
83
  * ```
84
+ *
85
+
84
86
  */
85
87
 
86
88
  import {
@@ -321,7 +323,7 @@ const buttonsContainerClass =
321
323
 
322
324
  <div
323
325
  class:list={[
324
- 'cosy:card cosy:bg-base-100 cosy:transition-shadow cosy:duration-300',
326
+ 'cosy:card cosy:bg-base-200 cosy:transition-shadow cosy:duration-300',
325
327
  shadowStyles[shadow],
326
328
  currentSize.card,
327
329
  equalHeight && currentSize.cardHeight,
@@ -60,6 +60,22 @@
60
60
  * products={products}
61
61
  * />
62
62
  * ```
63
+ *
64
+ * 显示容器边框:
65
+ * ```astro
66
+ * <Products
67
+ * showBorder={true}
68
+ * products={products}
69
+ * />
70
+ * ```
71
+ *
72
+ * 设置上下外边距:
73
+ * ```astro
74
+ * <Products
75
+ * margin="lg"
76
+ * products={products}
77
+ * />
78
+ * ```
63
79
  */
64
80
 
65
81
  import { ProductCard } from '../../index-astro';
@@ -81,6 +97,9 @@ type ResponsiveColumns = {
81
97
  // 定义间距大小
82
98
  type GapSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
83
99
 
100
+ // 定义外边距大小
101
+ type MarginSize = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
102
+
84
103
  // 定义布局类型
85
104
  type LayoutType = 'grid' | 'list';
86
105
 
@@ -125,6 +144,21 @@ export interface Props {
125
144
  * 应用于所有ProductCard
126
145
  */
127
146
  descriptionLines?: number;
147
+ /**
148
+ * 是否显示容器边框
149
+ * 控制Products组件整体容器的边框显示
150
+ */
151
+ showBorder?: boolean;
152
+ /**
153
+ * 上下外边距
154
+ * - none: 无外边距
155
+ * - xs: 超小外边距
156
+ * - sm: 小外边距
157
+ * - md: 中等外边距(默认)
158
+ * - lg: 大外边距
159
+ * - xl: 超大外边距
160
+ */
161
+ margin?: MarginSize;
128
162
  /**
129
163
  * 自定义类名
130
164
  */
@@ -139,6 +173,8 @@ const {
139
173
  gap = 'md',
140
174
  equalHeight = true,
141
175
  descriptionLines,
176
+ showBorder = false,
177
+ margin = 'md',
142
178
  class: className = '',
143
179
  } = Astro.props;
144
180
 
@@ -151,6 +187,16 @@ const gapMap = {
151
187
  xl: 'cosy:gap-8',
152
188
  };
153
189
 
190
+ // 外边距映射
191
+ const marginMap = {
192
+ none: '',
193
+ xs: 'cosy:my-1',
194
+ sm: 'cosy:my-2',
195
+ md: 'cosy:my-4',
196
+ lg: 'cosy:my-6',
197
+ xl: 'cosy:my-8',
198
+ };
199
+
154
200
  // 获取响应式列数类名
155
201
  const getColumnsClasses = () => {
156
202
  if (typeof columns === 'number') {
@@ -181,7 +227,9 @@ const getLayoutClasses = () => {
181
227
  const containerClasses = [
182
228
  ...getLayoutClasses(),
183
229
  gapMap[gap],
230
+ marginMap[margin],
184
231
  'cosy:w-full',
232
+ showBorder && 'cosy:border cosy:border-base-300 cosy:p-4 cosy:rounded-lg',
185
233
  className,
186
234
  ];
187
235
  ---