@coffic/cosy-ui 0.5.2 → 0.5.6

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.
@@ -1,18 +1,18 @@
1
1
  ---
2
2
  /**
3
3
  * @component Grid
4
- *
4
+ *
5
5
  * @description
6
6
  * Grid 组件是一个灵活的网格布局组件,用于创建响应式的多列布局。
7
7
  * 它封装了 CSS Grid 的常用功能,提供简单易用的接口来控制网格的列数和间距。
8
- *
8
+ *
9
9
  * @design
10
10
  * 设计理念:
11
11
  * 1. 简单易用 - 通过简洁的 API 控制复杂的 Grid 布局
12
12
  * 2. 响应式优先 - 内置响应式断点,轻松创建适应不同屏幕尺寸的布局
13
13
  * 3. 灵活可配置 - 支持自定义列数和间距
14
14
  * 4. 语义化属性 - 使用直观的属性名称,降低学习成本
15
- *
15
+ *
16
16
  * @usage
17
17
  * 基本用法:
18
18
  * ```astro
@@ -22,7 +22,7 @@
22
22
  * <div>第三列</div>
23
23
  * </Grid>
24
24
  * ```
25
- *
25
+ *
26
26
  * 响应式网格:
27
27
  * ```astro
28
28
  * <Grid cols={{base: 1, md: 2, lg: 3}} gap="lg">
@@ -31,7 +31,7 @@
31
31
  * <div>显示不同的列数</div>
32
32
  * </Grid>
33
33
  * ```
34
- *
34
+ *
35
35
  * 自定义行列间距:
36
36
  * ```astro
37
37
  * <Grid cols={2} rowGap="lg" colGap="sm">
@@ -41,7 +41,7 @@
41
41
  * <div>第四项</div>
42
42
  * </Grid>
43
43
  * ```
44
- *
44
+ *
45
45
  * @props
46
46
  * @prop {number | Object} [cols=1] - 网格列数,可以是固定值或响应式对象
47
47
  * @prop {string} [gap="md"] - 网格间距,可选值:none, xs, sm, md, lg, xl
@@ -59,124 +59,132 @@ import type { HTMLAttributes } from 'astro/types';
59
59
  type GapSize = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
60
60
  type Breakpoint = 'base' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
61
61
 
62
- type ResponsiveValue<T> = T | {
63
- base?: T;
64
- sm?: T;
65
- md?: T;
66
- lg?: T;
67
- xl?: T;
68
- '2xl'?: T;
69
- };
62
+ type ResponsiveValue<T> =
63
+ | T
64
+ | {
65
+ base?: T;
66
+ sm?: T;
67
+ md?: T;
68
+ lg?: T;
69
+ xl?: T;
70
+ '2xl'?: T;
71
+ };
70
72
 
71
73
  interface Props extends HTMLAttributes<'div'> {
72
- /**
73
- * 网格列数,可以是固定值或响应式对象
74
- * @default 1
75
- */
76
- cols?: ResponsiveValue<number>;
77
-
78
- /**
79
- * 网格间距
80
- * @default "md"
81
- */
82
- gap?: GapSize;
83
-
84
- /**
85
- * 行间距,默认与gap相同
86
- */
87
- rowGap?: GapSize;
88
-
89
- /**
90
- * 列间距,默认与gap相同
91
- */
92
- colGap?: GapSize;
93
-
94
- /**
95
- * 自定义类名
96
- */
97
- class?: string;
98
-
99
- /**
100
- * 类名列表
101
- */
102
- 'class:list'?: any;
74
+ /**
75
+ * 网格列数,可以是固定值或响应式对象
76
+ * @default 1
77
+ */
78
+ cols?: ResponsiveValue<number>;
79
+
80
+ /**
81
+ * 网格间距
82
+ * @default "md"
83
+ */
84
+ gap?: GapSize;
85
+
86
+ /**
87
+ * 行间距,默认与gap相同
88
+ */
89
+ rowGap?: GapSize;
90
+
91
+ /**
92
+ * 列间距,默认与gap相同
93
+ */
94
+ colGap?: GapSize;
95
+
96
+ /**
97
+ * 自定义类名
98
+ */
99
+ class?: string;
100
+
101
+ /**
102
+ * 类名列表
103
+ */
104
+ 'class:list'?: any;
103
105
  }
104
106
 
105
107
  const {
106
- cols = 1,
107
- gap = 'md',
108
- rowGap,
109
- colGap,
110
- class: className = '',
111
- 'class:list': classList,
112
- ...rest
108
+ cols = 1,
109
+ gap = 'md',
110
+ rowGap,
111
+ colGap,
112
+ class: className = '',
113
+ 'class:list': classList,
114
+ ...rest
113
115
  } = Astro.props;
114
116
 
115
117
  // 处理响应式列数
116
118
  const getColsClasses = (cols: ResponsiveValue<number>) => {
117
- if (typeof cols === 'number') {
118
- return `grid-cols-${cols}`;
119
- }
120
-
121
- const breakpoints: Record<Breakpoint, string> = {
122
- base: '',
123
- sm: 'sm:',
124
- md: 'md:',
125
- lg: 'lg:',
126
- xl: 'xl:',
127
- '2xl': '2xl:'
128
- };
129
-
130
- return Object.entries(cols)
131
- .map(([breakpoint, value]) => {
132
- if (breakpoint === 'base') {
133
- return `grid-cols-${value}`;
134
- }
135
- return `${breakpoints[breakpoint as Breakpoint]}grid-cols-${value}`;
136
- })
137
- .join(' ');
119
+ if (typeof cols === 'number') {
120
+ return `cosy:grid-cols-${cols}`;
121
+ }
122
+
123
+ const breakpoints: Record<Breakpoint, string> = {
124
+ base: '',
125
+ sm: 'sm:',
126
+ md: 'md:',
127
+ lg: 'lg:',
128
+ xl: 'xl:',
129
+ '2xl': '2xl:',
130
+ };
131
+
132
+ return Object.entries(cols)
133
+ .map(([breakpoint, value]) => {
134
+ if (breakpoint === 'base') {
135
+ return `cosy:grid-cols-${value}`;
136
+ }
137
+ return `cosy:${breakpoints[breakpoint as Breakpoint]}grid-cols-${value}`;
138
+ })
139
+ .join(' ');
138
140
  };
139
141
 
140
142
  // 间距映射
141
143
  const gapClasses: Record<GapSize, string> = {
142
- none: 'gap-0',
143
- xs: 'gap-2',
144
- sm: 'gap-4',
145
- md: 'gap-6',
146
- lg: 'gap-8',
147
- xl: 'gap-12'
144
+ none: 'cosy:gap-0',
145
+ xs: 'cosy:gap-2',
146
+ sm: 'cosy:gap-4',
147
+ md: 'cosy:gap-6',
148
+ lg: 'cosy:gap-8',
149
+ xl: 'cosy:gap-12',
148
150
  };
149
151
 
150
152
  // 行间距映射
151
153
  const rowGapClasses: Record<GapSize, string> = {
152
- none: 'row-gap-0',
153
- xs: 'row-gap-2',
154
- sm: 'row-gap-4',
155
- md: 'row-gap-6',
156
- lg: 'row-gap-8',
157
- xl: 'row-gap-12'
154
+ none: 'cosy:row-gap-0',
155
+ xs: 'cosy:row-gap-2',
156
+ sm: 'cosy:row-gap-4',
157
+ md: 'cosy:row-gap-6',
158
+ lg: 'cosy:row-gap-8',
159
+ xl: 'cosy:row-gap-12',
158
160
  };
159
161
 
160
162
  // 列间距映射
161
163
  const colGapClasses: Record<GapSize, string> = {
162
- none: 'col-gap-0',
163
- xs: 'col-gap-2',
164
- sm: 'col-gap-4',
165
- md: 'col-gap-6',
166
- lg: 'col-gap-8',
167
- xl: 'col-gap-12'
164
+ none: 'cosy:col-gap-0',
165
+ xs: 'cosy:col-gap-2',
166
+ sm: 'cosy:col-gap-4',
167
+ md: 'cosy:col-gap-6',
168
+ lg: 'cosy:col-gap-8',
169
+ xl: 'cosy:col-gap-12',
168
170
  };
169
171
 
170
172
  // 构建最终类名
171
173
  const gridClasses = [
172
- 'grid',
173
- getColsClasses(cols),
174
- rowGap ? rowGapClasses[rowGap as GapSize] : colGap ? gapClasses[gap as GapSize] : gapClasses[gap as GapSize],
175
- colGap ? colGapClasses[colGap as GapSize] : null,
176
- className
177
- ].filter(Boolean).join(' ');
174
+ 'cosy:grid',
175
+ getColsClasses(cols),
176
+ rowGap
177
+ ? rowGapClasses[rowGap as GapSize]
178
+ : colGap
179
+ ? gapClasses[gap as GapSize]
180
+ : gapClasses[gap as GapSize],
181
+ colGap ? colGapClasses[colGap as GapSize] : null,
182
+ className,
183
+ ]
184
+ .filter(Boolean)
185
+ .join(' ');
178
186
  ---
179
187
 
180
188
  <div class:list={[gridClasses, classList]} {...rest}>
181
- <slot />
189
+ <slot />
182
190
  </div>
@@ -26,19 +26,27 @@
26
26
  * />
27
27
  * ```
28
28
  *
29
- * 自定义语言选项:
29
+ * 自定义导航菜单位置:
30
30
  * ```astro
31
31
  * <Header
32
32
  * logo={import("../assets/logo.png")}
33
- * languages={["zh-cn", "en", "ja"]}
33
+ * navPosition="start"
34
+ * navItems={[
35
+ * { href: "/docs", label: "文档", match: (path) => path.startsWith("/docs") },
36
+ * { href: "/components", label: "组件", match: (path) => path.startsWith("/components") }
37
+ * ]}
34
38
  * />
35
39
  * ```
40
+ * navPosition 可选值:
41
+ * - start: 导航菜单在左侧
42
+ * - center: 导航菜单在中间(默认)
43
+ * - end: 导航菜单在右侧
36
44
  *
37
- * 带有基础路径:
45
+ * 自定义语言选项:
38
46
  * ```astro
39
47
  * <Header
40
48
  * logo={import("../assets/logo.png")}
41
- * basePath="/my-site"
49
+ * languages={["zh-cn", "en", "ja"]}
42
50
  * />
43
51
  * ```
44
52
  *
@@ -55,7 +63,9 @@ import Image from '../base/Image.astro';
55
63
  import { LanguageSwitcher, LinkUtil, type HeaderProps, type NavItem } from '../../index';
56
64
  import Logo from '../../assets/logo-rounded.png';
57
65
 
58
- export interface Props extends HeaderProps {}
66
+ export interface Props extends HeaderProps {
67
+ debug?: boolean;
68
+ }
59
69
 
60
70
  const {
61
71
  height = 'md',
@@ -64,6 +74,11 @@ const {
64
74
  logoHref = '/',
65
75
  navItems = [],
66
76
  sticky = true,
77
+ debug = false,
78
+ rounded = 'none',
79
+ paddingHorizontal = 'none',
80
+ paddingVertical = 'none',
81
+ navPosition = 'center',
67
82
  } = Astro.props;
68
83
 
69
84
  // 根据高度设置样式
@@ -110,45 +125,144 @@ const activeLink = LinkUtil.getActiveLink(
110
125
 
111
126
  <header
112
127
  class:list={[
113
- 'cosy:navbar cosy:bg-accent/70 cosy:backdrop-blur cosy:border-base-200 cosy:z-50 cosy:w-full cosy:m-0 cosy:p-0 cosy:min-h-1',
114
- headerHeightClass,
115
- { 'cosy:fixed cosy:top-0': sticky },
128
+ 'cosy:w-full cosy:z-50',
129
+ {
130
+ 'cosy:fixed cosy:top-0': sticky,
131
+ 'cosy:border cosy:bg-amber-300 cosy:border-dashed cosy:border-green-500': debug,
132
+ },
133
+ {
134
+ 'cosy:px-2': paddingHorizontal === 'sm',
135
+ 'cosy:px-4': paddingHorizontal === 'md',
136
+ 'cosy:px-6': paddingHorizontal === 'lg',
137
+ 'cosy:px-8': paddingHorizontal === 'xl',
138
+ 'cosy:px-12': paddingHorizontal === '2xl',
139
+ 'cosy:px-16': paddingHorizontal === '3xl',
140
+ },
141
+ {
142
+ 'cosy:py-2': paddingVertical === 'sm',
143
+ 'cosy:py-4': paddingVertical === 'md',
144
+ 'cosy:py-6': paddingVertical === 'lg',
145
+ 'cosy:py-8': paddingVertical === 'xl',
146
+ 'cosy:py-12': paddingVertical === '2xl',
147
+ 'cosy:py-16': paddingVertical === '3xl',
148
+ },
116
149
  ]}>
117
- <div class="cosy:navbar-start">
118
- <Link
119
- animation="none"
120
- href={logoHref}
121
- class:list={['cosy:btn cosy:btn-ghost', linkHeightClass]}>
122
- <Image
123
- showPlaceholder={false}
124
- transition="none"
125
- lazy={false}
126
- src={logo}
127
- alt="logo"
128
- class={logoSizeClass}
129
- />
130
- </Link>
131
- </div>
132
-
133
- <!-- 导航 -->
134
- <div class="cosy:hidden cosy:lg:flex cosy:navbar-center">
135
- <ul class:list={['cosy:px-1 cosy:menu cosy:menu-horizontal', linkHeightClass]}>
150
+ <!-- 背景 -->
151
+ <div
152
+ class:list={[
153
+ 'cosy:bg-accent/70 cosy:flex cosy:flex-grow cosy:backdrop-blur not-prose cosy:border-base-200',
136
154
  {
137
- navItems.map((item: NavItem) => (
138
- <li>
155
+ 'cosy:rounded-none': rounded === 'none',
156
+ 'cosy:rounded-sm': rounded === 'sm',
157
+ 'cosy:rounded-md': rounded === 'md',
158
+ 'cosy:rounded-lg': rounded === 'lg',
159
+ 'cosy:rounded-xl': rounded === 'xl',
160
+ 'cosy:rounded-full': rounded === 'full',
161
+ },
162
+ headerHeightClass,
163
+ { 'cosy:border cosy:border-dashed cosy:border-red-500': debug },
164
+ ]}>
165
+ <!-- 左侧 -->
166
+ <div class="cosy:navbar-start cosy:pl-1">
167
+ {
168
+ navPosition === 'start' ? (
169
+ <div class="cosy:flex cosy:items-center cosy:gap-4">
139
170
  <Link
140
- variant={activeLink == item.href ? 'primary' : 'default'}
141
- href={item.href}
142
- class:list={[linkHeightClass]}>
143
- {item.label}
171
+ animation="none"
172
+ debug={debug}
173
+ href={logoHref}
174
+ class:list={['cosy:btn cosy:btn-ghost', linkHeightClass]}>
175
+ <Image
176
+ rounded="full"
177
+ showPlaceholder={false}
178
+ transition="none"
179
+ lazy={false}
180
+ src={logo}
181
+ alt="logo"
182
+ class={logoSizeClass}
183
+ />
144
184
  </Link>
145
- </li>
146
- ))
185
+ <ul
186
+ class:list={[
187
+ 'cosy:hidden cosy:lg:flex cosy:px-1 cosy:menu cosy:menu-horizontal',
188
+ linkHeightClass,
189
+ ]}>
190
+ {navItems.map((item: NavItem) => (
191
+ <li>
192
+ <Link
193
+ variant={activeLink == item.href ? 'primary' : 'default'}
194
+ href={item.href}
195
+ class:list={[linkHeightClass]}>
196
+ {item.label}
197
+ </Link>
198
+ </li>
199
+ ))}
200
+ </ul>
201
+ </div>
202
+ ) : (
203
+ <Link
204
+ animation="none"
205
+ debug={debug}
206
+ href={logoHref}
207
+ class:list={['cosy:btn cosy:btn-ghost', linkHeightClass]}>
208
+ <Image
209
+ rounded="full"
210
+ showPlaceholder={false}
211
+ transition="none"
212
+ lazy={false}
213
+ src={logo}
214
+ alt="logo"
215
+ class={logoSizeClass}
216
+ />
217
+ </Link>
218
+ )
147
219
  }
148
- </ul>
149
- </div>
220
+ </div>
150
221
 
151
- <div class="cosy:navbar-end">
152
- <LanguageSwitcher languages={languages} />
222
+ <!-- 中间 -->
223
+ {
224
+ navPosition === 'center' && (
225
+ <div class="cosy:hidden cosy:lg:flex cosy:navbar-center">
226
+ <ul class:list={['cosy:px-1 cosy:menu cosy:menu-horizontal', linkHeightClass]}>
227
+ {navItems.map((item: NavItem) => (
228
+ <li>
229
+ <Link
230
+ variant={activeLink == item.href ? 'primary' : 'default'}
231
+ href={item.href}
232
+ class:list={[linkHeightClass]}>
233
+ {item.label}
234
+ </Link>
235
+ </li>
236
+ ))}
237
+ </ul>
238
+ </div>
239
+ )
240
+ }
241
+
242
+ <!-- 右侧 -->
243
+ <div class="cosy:navbar-end cosy:pr-1">
244
+ {
245
+ navPosition === 'end' && (
246
+ <ul
247
+ class:list={[
248
+ 'cosy:hidden cosy:lg:flex cosy:px-1 cosy:menu cosy:menu-horizontal',
249
+ linkHeightClass,
250
+ ]}>
251
+ {navItems.map((item: NavItem) => (
252
+ <li>
253
+ <Link
254
+ variant={activeLink == item.href ? 'primary' : 'default'}
255
+ href={item.href}
256
+ class:list={[linkHeightClass]}>
257
+ {item.label}
258
+ </Link>
259
+ </li>
260
+ ))}
261
+ </ul>
262
+ )
263
+ }
264
+ <!-- 语言切换 -->
265
+ <LanguageSwitcher languages={languages} />
266
+ </div>
153
267
  </div>
154
268
  </header>
@@ -92,14 +92,14 @@ const currentSection = sidebarItems.find((section) =>
92
92
  </button>
93
93
  <span class="cosy:font-medium cosy:text-sm">{currentSection?.text || '导航'}</span>
94
94
  </div>
95
- </div>;
95
+ </div>
96
96
 
97
97
  {/* 移动端侧边栏弹出层 */}
98
98
  <Modal id="mobile-sidebar" class="cosy:mx-4 cosy:lg:w-80 cosy:w-[calc(100vw-2rem)] cosy:max-w-full">
99
99
  <div class="cosy:h-[calc(100vh-8rem)] cosy:overflow-y-auto">
100
100
  <SidebarNav sidebarItems={sidebarItems} currentPath={currentPath} debug={debug} />
101
101
  </div>
102
- </Modal>;
102
+ </Modal>
103
103
 
104
104
  {/* 桌面端侧边栏 */}
105
105
  <aside
@@ -116,4 +116,60 @@ const currentSection = sidebarItems.find((section) =>
116
116
  <div class="cosy:top-16 cosy:sticky cosy:pb-48 cosy:h-[calc(100vh-0rem)] cosy:overflow-y-auto">
117
117
  <SidebarNav sidebarItems={sidebarItems} currentPath={currentPath} debug={debug} />
118
118
  </div>
119
- </aside>; ---
119
+ </aside>
120
+
121
+ <script>
122
+ // 处理侧边栏滚动位置保存和恢复
123
+ document.addEventListener('astro:before-preparation', () => {
124
+ // 获取桌面侧边栏滚动容器
125
+ const desktopSidebarContent = document.querySelector(
126
+ 'aside[data-sidebar] .cosy\\:overflow-y-auto'
127
+ );
128
+
129
+ // 保存滚动位置到localStorage
130
+ if (desktopSidebarContent) {
131
+ localStorage.setItem('sidebarScrollPosition', desktopSidebarContent.scrollTop.toString());
132
+ }
133
+
134
+ // 获取移动端侧边栏滚动容器
135
+ const mobileSidebarContent = document.querySelector(
136
+ '.cosy\\:h-\\[calc\\(100vh-8rem\\)\\].cosy\\:overflow-y-auto'
137
+ );
138
+
139
+ // 保存移动端滚动位置
140
+ if (mobileSidebarContent) {
141
+ localStorage.setItem(
142
+ 'mobileSidebarScrollPosition',
143
+ mobileSidebarContent.scrollTop.toString()
144
+ );
145
+ }
146
+ });
147
+
148
+ document.addEventListener('astro:page-load', () => {
149
+ // 获取桌面侧边栏滚动容器
150
+ const desktopSidebarContent = document.querySelector(
151
+ 'aside[data-sidebar] .cosy\\:overflow-y-auto'
152
+ );
153
+
154
+ // 恢复滚动位置
155
+ if (desktopSidebarContent) {
156
+ const savedPosition = localStorage.getItem('sidebarScrollPosition');
157
+ if (savedPosition) {
158
+ desktopSidebarContent.scrollTop = parseInt(savedPosition, 10);
159
+ }
160
+ }
161
+
162
+ // 获取移动端侧边栏滚动容器
163
+ const mobileSidebarContent = document.querySelector(
164
+ '.cosy\\:h-\\[calc\\(100vh-8rem\\)\\].cosy\\:overflow-y-auto'
165
+ );
166
+
167
+ // 恢复移动端滚动位置
168
+ if (mobileSidebarContent) {
169
+ const savedMobilePosition = localStorage.getItem('mobileSidebarScrollPosition');
170
+ if (savedMobilePosition) {
171
+ mobileSidebarContent.scrollTop = parseInt(savedMobilePosition, 10);
172
+ }
173
+ }
174
+ });
175
+ </script>
@@ -106,12 +106,11 @@ const {
106
106
  maxDepth = 3,
107
107
  containerSelector = 'main',
108
108
  minHeadings = 2,
109
- lang: userLang,
110
109
  title,
111
110
  } = Astro.props;
112
111
 
113
112
  // 获取当前语言
114
- const langInfo = LanguageUtil.getCurrentLanguage(userLang);
113
+ const langInfo = LanguageUtil.getCurrentLanguage(Astro);
115
114
  // 创建文本获取函数
116
115
  const t = createTextGetter(langInfo, 'tableOfContents');
117
116
  // 获取标题文本,如果用户提供了标题则使用用户提供的标题
@@ -126,7 +125,8 @@ const tocId = `toc-${Math.random().toString(36).substring(2, 9)}`;
126
125
  <div
127
126
  class={`toc-container toc-scroll-container ${fixed ? 'cosy:w-64' : 'cosy:w-full cosy:max-w-xs'}`}
128
127
  id={`${tocId}-container`}
129
- style="display: none;">
128
+ style="display: none;"
129
+ >
130
130
  <div class="cosy:bg-base-100 cosy:shadow-inner cosy:card">
131
131
  <div class="cosy:p-4 cosy:card-body">
132
132
  <div class="cosy:mb-2 cosy:font-bold cosy:text-lg cosy:card-title">{titleText}</div>
@@ -1,12 +1,12 @@
1
- import { defineIntegration } from "astro-integration-kit";
1
+ import { defineIntegration } from 'astro-integration-kit';
2
2
 
3
3
  export const integration = defineIntegration({
4
- name: "astro-cosy",
4
+ name: 'cosy-ui',
5
5
  setup() {
6
6
  return {
7
7
  hooks: {
8
- "astro:config:setup": ({ logger }) => {
9
- logger.info("astro-cosy integration setup");
8
+ 'astro:config:setup': ({ logger }) => {
9
+ logger.info('cosy-ui integration setup');
10
10
  },
11
11
  },
12
12
  };
package/dist/style.ts CHANGED
@@ -1 +1,2 @@
1
- import './app.css';
1
+ // 为了让vite处理css文件,所以建立这个文件
2
+ import './app.css';