@coffic/cosy-ui 0.3.67 → 0.4.3

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.
@@ -54,82 +54,25 @@
54
54
  * height="lg"
55
55
  * />
56
56
  */
57
+ import '../../app.css';
57
58
  import Link from '../base/Link.astro';
58
59
  import Image from '../base/Image.astro';
59
- import '../../app.css';
60
+ import type { HeaderProps } from '@/types/header';
60
61
 
61
- // 自定义图片元数据接口
62
- interface ImageMetadata {
63
- src: string;
64
- width: number;
65
- height: number;
66
- format: string;
67
- }
68
-
69
- interface Props {
70
- logo: ImageMetadata;
71
- /**
72
- * Logo 链接地址
73
- * @default "/"
74
- */
75
- logoHref?: string;
76
- languages?: Array<{ code: string; name: string }>;
77
- currentLocale?: string;
78
- navItems?: Array<{
79
- href: string;
80
- label: string;
81
- match: (path: string) => boolean;
82
- }>;
83
- socialLinks?: Array<{
84
- name: string;
85
- url: string;
86
- icon: any;
87
- }>;
88
- /**
89
- * 是否固定在顶部
90
- * @default true
91
- */
92
- sticky?: boolean;
93
- /**
94
- * 基础路径,用于处理网站部署在二级目录的情况
95
- * @default ""
96
- */
97
- basePath?: string;
98
- /**
99
- * 是否显示侧边栏切换按钮
100
- * @default false
101
- */
102
- showSidebarToggle?: boolean;
103
- /**
104
- * 侧边栏是否默认展开
105
- * @default false
106
- */
107
- defaultSidebarOpen?: boolean;
108
- /**
109
- * 导航栏高度
110
- * @default "md"
111
- */
112
- height?: '3xs' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
113
- /**
114
- * 是否显示高度设置菜单
115
- * @default true
116
- */
117
- showHeightSetting?: boolean;
118
- }
62
+ interface Props extends HeaderProps {}
119
63
 
120
64
  const {
121
- logo,
122
- logoHref = '/',
123
- navItems = [],
124
- sticky = true,
65
+ basePath = '',
66
+ currentLocale = 'zh-cn',
67
+ height = 'md',
125
68
  languages = [
126
69
  { code: 'zh-cn', name: '中文' },
127
70
  { code: 'en', name: 'English' },
128
71
  ],
129
- currentLocale = 'zh-cn',
130
- basePath = '',
131
- height = 'md',
132
- showHeightSetting = true,
72
+ logo,
73
+ logoHref = '/',
74
+ navItems = [],
75
+ sticky = true,
133
76
  } = Astro.props;
134
77
 
135
78
  type NavItem = { href: string; label: string; match: (path: string) => boolean };
@@ -150,17 +93,6 @@ function getLanguageUrl(langCode: string) {
150
93
  return `${basePath}/${langCode}${pathWithoutLocale}`;
151
94
  }
152
95
 
153
- // 定义可用的高度选项
154
- const heightOptions = [
155
- { value: '3xs', label: '超超小' },
156
- { value: '2xs', label: '超小' },
157
- { value: 'xs', label: '小' },
158
- { value: 'sm', label: '较小' },
159
- { value: 'md', label: '中等' },
160
- { value: 'lg', label: '大' },
161
- { value: 'xl', label: '超大' },
162
- ];
163
-
164
96
  // 获取初始高度(优先使用localStorage中的值)
165
97
  type HeightType = '3xs' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
166
98
 
@@ -197,19 +129,6 @@ const logoSizeClasses = {
197
129
  };
198
130
 
199
131
  const logoSizeClass = logoSizeClasses[initialHeight];
200
-
201
- // 设置占位空间高度
202
- const spacerHeightClasses = {
203
- '3xs': 'cosy:h-4',
204
- '2xs': 'cosy:h-6',
205
- xs: 'cosy:h-8',
206
- sm: 'cosy:h-10',
207
- md: 'cosy:h-12',
208
- lg: 'cosy:h-16',
209
- xl: 'cosy:h-20',
210
- };
211
-
212
- const spacerHeightClass = spacerHeightClasses[initialHeight];
213
132
  ---
214
133
 
215
134
  <header
@@ -265,50 +184,6 @@ const spacerHeightClass = spacerHeightClasses[initialHeight];
265
184
  </div>
266
185
 
267
186
  <div class="cosy:navbar-end">
268
- {
269
- showHeightSetting && (
270
- <div class="cosy:mr-2 cosy:dropdown cosy:dropdown-end">
271
- <div
272
- tabindex="0"
273
- role="button"
274
- class:list={[
275
- 'cosy:btn cosy:btn-ghost',
276
- initialHeight === 'xs' || initialHeight === '2xs' || initialHeight === '3xs'
277
- ? 'cosy:btn-xs cosy:h-auto cosy:min-h-0 cosy:p-1'
278
- : initialHeight === 'sm'
279
- ? 'cosy:btn-sm'
280
- : 'cosy:btn-sm',
281
- ]}
282
- id="height-dropdown-btn">
283
- <span class="cosy:mr-1">高度</span>
284
- <svg
285
- xmlns="http://www.w3.org/2000/svg"
286
- class="cosy:w-4 cosy:h-4"
287
- fill="none"
288
- viewBox="0 0 24 24"
289
- stroke="currentColor">
290
- <path
291
- stroke-linecap="round"
292
- stroke-linejoin="round"
293
- stroke-width="2"
294
- d="M19 9l-7 7-7-7"
295
- />
296
- </svg>
297
- </div>
298
- <ul
299
- tabindex="0"
300
- class="cosy:z-[1] cosy:bg-base-100 cosy:shadow cosy:p-2 cosy:rounded-box cosy:w-40 cosy:dropdown-content cosy:menu"
301
- id="height-dropdown-content">
302
- {heightOptions.map((option) => (
303
- <li data-height={option.value} class="height-option" id={`height-${option.value}`}>
304
- <a class={initialHeight === option.value ? 'cosy:active' : ''}>{option.label}</a>
305
- </li>
306
- ))}
307
- </ul>
308
- </div>
309
- )
310
- }
311
-
312
187
  <!-- 语言切换按钮 -->
313
188
  <div class="cosy:dropdown cosy:dropdown-end">
314
189
  <div
@@ -351,160 +226,3 @@ const spacerHeightClass = spacerHeightClasses[initialHeight];
351
226
  </div>
352
227
  </div>
353
228
  </header>
354
-
355
- {sticky && <div class={spacerHeightClass} id="header-spacer" />}
356
-
357
- <script define:vars={{ sticky, height, headerHeightClasses, spacerHeightClasses }}>
358
- // 等待DOM完全加载
359
- document.addEventListener('DOMContentLoaded', () => {
360
- // 获取存储的高度设置,如果没有则使用传入的默认高度
361
- const storedHeight = localStorage.getItem('cosy-header-height');
362
- let currentHeight = storedHeight || height;
363
-
364
- // 更新DOM元素的高度类
365
- function updateHeaderHeight(newHeight) {
366
- const header = document.querySelector('header');
367
- const spacer = document.getElementById('header-spacer');
368
-
369
- if (!header) return;
370
-
371
- // 先获取header当前的所有类名
372
- const headerClasses = [...header.classList];
373
-
374
- // 找出并移除当前的高度类
375
- Object.values(headerHeightClasses).forEach((cls) => {
376
- if (headerClasses.includes(cls)) {
377
- header.classList.remove(cls);
378
- }
379
- });
380
-
381
- // 添加新的高度类
382
- const newHeaderClass = headerHeightClasses[newHeight];
383
- header.classList.add(newHeaderClass);
384
-
385
- // 更新占位元素高度
386
- if (spacer) {
387
- const spacerClasses = [...spacer.classList];
388
-
389
- Object.values(spacerHeightClasses).forEach((cls) => {
390
- const className = cls.replace('cosy:', '');
391
- if (spacerClasses.includes(className)) {
392
- spacer.classList.remove(className);
393
- }
394
- });
395
-
396
- const newSpacerClass = spacerHeightClasses[newHeight].replace('cosy:', '');
397
- spacer.classList.add(newSpacerClass);
398
- }
399
-
400
- // 更新样式类,需要处理:list中的类
401
- // 1. 处理logo按钮
402
- const logoBtn = document.querySelector('.cosy\\:navbar-start .cosy\\:btn');
403
- if (logoBtn) {
404
- // 清理之前的按钮大小类
405
- ['cosy:btn-xs', 'cosy:btn-sm', 'cosy:h-auto', 'cosy:min-h-0', 'cosy:p-1'].forEach((cls) => {
406
- logoBtn.classList.remove(cls.replace('cosy:', ''));
407
- });
408
-
409
- // 根据新高度添加适当的类
410
- if (newHeight === 'xs' || newHeight === '2xs' || newHeight === '3xs') {
411
- ['cosy:btn-xs', 'cosy:h-auto', 'cosy:min-h-0', 'cosy:p-1'].forEach((cls) => {
412
- logoBtn.classList.add(cls.replace('cosy:', ''));
413
- });
414
- } else if (newHeight === 'sm') {
415
- logoBtn.classList.add('btn-sm');
416
- }
417
- }
418
-
419
- // 2. 处理导航菜单
420
- const navMenu = document.querySelector('.cosy\\:navbar-center .cosy\\:menu');
421
- if (navMenu) {
422
- navMenu.classList.remove('menu-xs', 'menu-sm');
423
-
424
- if (newHeight === 'xs' || newHeight === '2xs' || newHeight === '3xs') {
425
- navMenu.classList.add('menu-xs');
426
- } else if (newHeight === 'sm') {
427
- navMenu.classList.add('menu-sm');
428
- }
429
- }
430
-
431
- // 3. 处理菜单项
432
- const navLinks = document.querySelectorAll('.cosy\\:navbar-center .cosy\\:menu li a');
433
- navLinks.forEach((link) => {
434
- ['cosy:py-0', 'cosy:px-2', 'cosy:min-h-0', 'cosy:py-1', 'cosy:min-h-6'].forEach((cls) => {
435
- link.classList.remove(cls.replace('cosy:', ''));
436
- });
437
-
438
- if (newHeight === 'xs' || newHeight === '2xs' || newHeight === '3xs') {
439
- ['cosy:py-0', 'cosy:px-2', 'cosy:min-h-0'].forEach((cls) => {
440
- link.classList.add(cls.replace('cosy:', ''));
441
- });
442
- } else if (newHeight === 'sm') {
443
- ['cosy:py-1', 'cosy:min-h-6'].forEach((cls) => {
444
- link.classList.add(cls.replace('cosy:', ''));
445
- });
446
- }
447
- });
448
-
449
- // 4. 处理下拉按钮
450
- const dropdownBtns = document.querySelectorAll(
451
- '.cosy\\:navbar-end .cosy\\:dropdown .cosy\\:btn'
452
- );
453
- dropdownBtns.forEach((btn) => {
454
- ['cosy:btn-xs', 'cosy:btn-sm', 'cosy:h-auto', 'cosy:min-h-0', 'cosy:p-1'].forEach((cls) => {
455
- btn.classList.remove(cls.replace('cosy:', ''));
456
- });
457
-
458
- if (newHeight === 'xs' || newHeight === '2xs' || newHeight === '3xs') {
459
- ['cosy:btn-xs', 'cosy:h-auto', 'cosy:min-h-0', 'cosy:p-1'].forEach((cls) => {
460
- btn.classList.add(cls.replace('cosy:', ''));
461
- });
462
- } else if (newHeight === 'sm' || newHeight === 'md') {
463
- btn.classList.add('btn-sm');
464
- }
465
- });
466
-
467
- // 标记当前选中的选项
468
- document.querySelectorAll('.height-option a').forEach((item) => {
469
- item.classList.remove('active');
470
- });
471
-
472
- const activeItem = document.querySelector(`#height-${newHeight} a`);
473
- if (activeItem) {
474
- activeItem.classList.add('active');
475
- }
476
-
477
- // 保存设置到本地存储
478
- localStorage.setItem('cosy-header-height', newHeight);
479
- currentHeight = newHeight;
480
- }
481
-
482
- // 如果有存储的高度设置,应用它
483
- if (storedHeight) {
484
- updateHeaderHeight(storedHeight);
485
- }
486
-
487
- // 绑定点击事件到高度选项
488
- document.querySelectorAll('.height-option').forEach((item) => {
489
- item.addEventListener('click', function () {
490
- const newHeight = this.getAttribute('data-height');
491
- updateHeaderHeight(newHeight);
492
-
493
- // 关闭下拉菜单
494
- document.activeElement.blur();
495
- });
496
- });
497
-
498
- // 滚动时添加阴影
499
- if (sticky) {
500
- const header = document.querySelector('header');
501
- window.addEventListener('scroll', () => {
502
- if (window.pageYOffset > 0) {
503
- header?.classList.add('cosy:shadow-lg'.replace('cosy:', ''));
504
- } else {
505
- header?.classList.remove('cosy:shadow-lg'.replace('cosy:', ''));
506
- }
507
- });
508
- }
509
- });
510
- </script>
@@ -17,44 +17,60 @@
17
17
  * ];
18
18
  * ---
19
19
  *
20
- * <Sidebar sidebarItems={sidebarItems} currentPath="/docs/getting-started" />
20
+ * <Sidebar sidebarItems={sidebarItems} />
21
21
  * ```
22
22
  */
23
23
 
24
+ import '../../app.css';
24
25
  import { isPathMatch } from '../../utils/path';
25
26
  import Modal from '../display/Modal.astro';
26
27
  import SidebarNav from './SidebarNav.astro';
27
28
  import MenuIcon from '../icons/MenuIcon.astro';
28
- import '../../app.css';
29
29
 
30
- import type { SidebarSection } from '../../types/layout';
30
+ import type { SidebarProps } from '../../types/sidebar';
31
31
 
32
- export interface Props {
33
- /**
34
- * 侧边栏项目
35
- */
36
- sidebarItems: SidebarSection[];
32
+ export interface Props extends SidebarProps{}
37
33
 
38
- /**
39
- * 当前路径
40
- */
41
- currentPath: string;
34
+ const {
35
+ sidebarItems,
36
+ class: className,
37
+ debug = false,
38
+ marginTop = 'md',
39
+ marginBottom = 'md',
40
+ } = Astro.props;
42
41
 
43
- /**
44
- * 桌面端类名
45
- */
46
- class?: string;
42
+ // 自动获取当前路径
43
+ const currentPath = Astro.url.pathname;
47
44
 
48
- /**
49
- * 是否开启调试模式,显示边框
50
- * @default false
51
- */
52
- debug?: boolean;
53
- }
45
+ const debugClass = debug ? 'cosy:border cosy:border-red-500' : '';
54
46
 
55
- const { sidebarItems, currentPath, class: className, debug = false } = Astro.props;
47
+ function getVerticalMarginTopClasses(marginTop: string) {
48
+ if (marginTop === 'none') return 'cosy:mt-0';
49
+ if (marginTop === 'xs') return 'cosy:mt-1';
50
+ if (marginTop === 'sm') return 'cosy:mt-2';
51
+ if (marginTop === 'md') return 'cosy:mt-4';
52
+ if (marginTop === 'lg') return 'cosy:mt-6';
53
+ if (marginTop === 'xl') return 'cosy:mt-8';
54
+ if (marginTop === '2xl') return 'cosy:mt-10';
55
+ if (marginTop === '3xl') return 'cosy:mt-12';
56
+ if (marginTop === '4xl') return 'cosy:mt-16';
57
+ if (marginTop === '5xl') return 'cosy:mt-20';
58
+ return '';
59
+ }
56
60
 
57
- const debugClass = debug ? 'cosy:border cosy:border-red-500' : '';
61
+ function getVerticalMarginBottomClasses(marginBottom: string) {
62
+ if (marginBottom === 'none') return 'cosy:mb-0';
63
+ if (marginBottom === 'xs') return 'cosy:mb-1';
64
+ if (marginBottom === 'sm') return 'cosy:mb-2';
65
+ if (marginBottom === 'md') return 'cosy:mb-4';
66
+ if (marginBottom === 'lg') return 'cosy:mb-6';
67
+ if (marginBottom === 'xl') return 'cosy:mb-8';
68
+ if (marginBottom === '2xl') return 'cosy:mb-10';
69
+ if (marginBottom === '3xl') return 'cosy:mb-12';
70
+ if (marginBottom === '4xl') return 'cosy:mb-16';
71
+ if (marginBottom === '5xl') return 'cosy:mb-20';
72
+ return '';
73
+ }
58
74
 
59
75
  // 获取当前活动的一级导航项
60
76
  const currentSection = sidebarItems.find((section) =>
@@ -75,22 +91,30 @@ const currentSection = sidebarItems.find((section) =>
75
91
  data-modal-target="mobile-sidebar">
76
92
  <MenuIcon class="cosy:w-5 cosy:h-5" />
77
93
  </button>
78
- <span class="cosy:font-medium cosy:text-sm">
79
- {currentSection?.title || '导航'}
80
- </span>
94
+ <span class="cosy:font-medium cosy:text-sm">{currentSection?.title || '导航'}</span>
81
95
  </div>
82
- </div>
96
+ </div>;
83
97
 
84
98
  {/* 移动端侧边栏弹出层 */}
85
99
  <Modal id="mobile-sidebar" class="cosy:mx-4 cosy:lg:w-80 cosy:w-[calc(100vw-2rem)] cosy:max-w-full">
86
100
  <div class="cosy:h-[calc(100vh-8rem)] cosy:overflow-y-auto">
87
101
  <SidebarNav sidebarItems={sidebarItems} currentPath={currentPath} debug={debug} />
88
102
  </div>
89
- </Modal>
103
+ </Modal>;
90
104
 
91
105
  {/* 桌面端侧边栏 */}
92
- <aside class:list={[className, debugClass, 'cosy:hidden cosy:lg:block']}>
106
+ <aside
107
+ data-sidebar
108
+ data-margin-top={marginTop}
109
+ data-margin-bottom={marginBottom}
110
+ class:list={[
111
+ className,
112
+ debugClass,
113
+ 'cosy:hidden cosy:lg:block',
114
+ getVerticalMarginTopClasses(marginTop),
115
+ getVerticalMarginBottomClasses(marginBottom),
116
+ ]}>
93
117
  <div class="cosy:top-16 cosy:sticky cosy:pb-48 cosy:h-[calc(100vh-0rem)] cosy:overflow-y-auto">
94
118
  <SidebarNav sidebarItems={sidebarItems} currentPath={currentPath} debug={debug} />
95
119
  </div>
96
- </aside>
120
+ </aside>; ---
@@ -7,17 +7,7 @@
7
7
 
8
8
  import { isPathMatch } from '../../utils/path';
9
9
  import '../../app.css';
10
-
11
- export interface SidebarItem {
12
- href: string;
13
- text: string;
14
- items?: SidebarItem[];
15
- }
16
-
17
- export interface SidebarSection {
18
- title: string;
19
- items: SidebarItem[];
20
- }
10
+ import type { SidebarSection, SidebarItem } from '../../types/sidebar';
21
11
 
22
12
  interface Props {
23
13
  /**
@@ -37,7 +37,7 @@
37
37
  * <p>这是一段文章内容...</p>
38
38
  * </Article>
39
39
  * ```
40
- *
40
+ *
41
41
  * 设置文章宽度:
42
42
  * ```astro
43
43
  * <Article width="narrow">
@@ -105,42 +105,18 @@
105
105
 
106
106
  // 导入样式
107
107
  import '../../app.css';
108
+ import type { ArticleProps } from '@/types/article';
108
109
 
109
- export interface Props {
110
- /**
111
- * 文章的类名
112
- */
113
- class?: string;
114
-
115
- /**
116
- * 类名列表
117
- */
118
- 'class:list'?: any;
119
-
120
- /**
121
- * 内联样式
122
- */
123
- style?: string;
124
-
125
- /**
126
- * 文章宽度
127
- * @default "medium"
128
- */
129
- width?: "narrow" | "medium" | "wide" | "full";
130
- }
110
+ export interface Props extends ArticleProps {}
131
111
 
132
- const {
133
- class: className = '',
134
- width = "medium",
135
- style = ""
136
- } = Astro.props;
112
+ const { class: className = '', width = 'medium', style = '' } = Astro.props;
137
113
 
138
114
  // 根据宽度设置对应的 Tailwind 类名
139
115
  const widthClasses = {
140
116
  narrow: 'cosy:max-w-2xl',
141
117
  medium: 'cosy:max-w-4xl',
142
118
  wide: 'cosy:max-w-6xl',
143
- full: 'cosy:w-full'
119
+ full: 'cosy:w-full',
144
120
  }[width];
145
121
 
146
122
  // 基础样式类
@@ -150,8 +126,10 @@ const baseClasses = [
150
126
  'cosy:w-full',
151
127
  'cosy:mx-auto',
152
128
  'cosy:dark:prose-invert', // 暗黑模式支持,
129
+ 'cosy:m-0',
130
+ 'cosy:p-0',
153
131
  widthClasses,
154
- className
132
+ className,
155
133
  ];
156
134
  ---
157
135
 
package/dist/index.ts CHANGED
@@ -22,12 +22,13 @@ export { default as CodeExample } from './components/display/CodeExample.astro';
22
22
  export { default as TeamMembers } from './components/data-display/TeamMembers.astro';
23
23
  export { default as TeamMember } from './components/data-display/TeamMember.astro';
24
24
  export { default as ProductCard } from './components/data-display/ProductCard.astro';
25
+ export { default as Products } from './components/data-display/Products.astro';
25
26
  export { default as Blog } from './components/data-display/Blog.astro';
26
27
 
27
28
  // Layouts
28
29
  export { default as Footer } from './components/layouts/Footer.astro';
29
30
  export { default as Header } from './components/layouts/Header.astro';
30
- export { default as DocumentationLayout } from './components/layouts/DocumentationLayout.astro';
31
+ export { default as AppLayout } from './components/layouts/AppLayout.astro';
31
32
  export { default as DefaultLayout } from './components/layouts/DefaultLayout.astro';
32
33
  export { default as Stack } from './components/layouts/Stack.astro';
33
34
  export { default as Grid } from './components/layouts/Grid.astro';
@@ -74,7 +75,8 @@ export * from './utils/image';
74
75
  export * from './utils/i18n';
75
76
  export * from './utils/path';
76
77
  export * from './utils/url';
78
+ export * from './utils/language';
77
79
 
78
80
  // Types
79
- export type { SidebarSection } from './types/layout';
81
+ export type { SidebarSection } from './types/sidebar';
80
82
  export type { ImageProvider, ImageOptions } from './utils/image';
@@ -0,0 +1,22 @@
1
+ export interface ArticleProps {
2
+ /**
3
+ * 文章的类名
4
+ */
5
+ class?: string;
6
+
7
+ /**
8
+ * 类名列表
9
+ */
10
+ 'class:list'?: any;
11
+
12
+ /**
13
+ * 内联样式
14
+ */
15
+ style?: string;
16
+
17
+ /**
18
+ * 文章宽度
19
+ * @default "medium"
20
+ */
21
+ width?: 'narrow' | 'medium' | 'wide' | 'full';
22
+ }