@coffic/cosy-ui 0.3.10-beta.1 → 0.3.15
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.
- package/dist/app.css +1 -1
- package/dist/components/base/Button.astro +61 -13
- package/dist/components/base/Image.astro +55 -16
- package/dist/components/base/Link.astro +14 -0
- package/dist/components/containers/Container.astro +35 -2
- package/dist/components/containers/Section.astro +23 -30
- package/dist/components/display/Modal.astro +14 -7
- package/dist/components/icons/MenuIcon.astro +5 -8
- package/dist/components/layouts/DocumentationLayout.astro +81 -25
- package/dist/components/layouts/Footer.astro +30 -76
- package/dist/components/layouts/Header.astro +17 -27
- package/dist/components/layouts/NavSection.astro +32 -0
- package/dist/components/layouts/Sidebar.astro +68 -68
- package/dist/components/layouts/SidebarNav.astro +122 -0
- package/dist/components/navigation/TableOfContents.astro +18 -50
- package/package.json +1 -1
- package/dist/components/containers/index.ts +0 -3
@@ -11,15 +11,16 @@
|
|
11
11
|
* <p>内容将被包裹在一个合适的区块中</p>
|
12
12
|
* </Section>
|
13
13
|
*
|
14
|
-
* <Section padding="lg" background="gray" centered={true}>
|
14
|
+
* <Section padding="lg" background="gray" centered={true} border={true}>
|
15
15
|
* <h2>自定义区块</h2>
|
16
|
-
* <p
|
16
|
+
* <p>大内边距,灰色背景,内容居中,带边框</p>
|
17
17
|
* </Section>
|
18
18
|
* ```
|
19
19
|
*/
|
20
20
|
|
21
21
|
import type { HTMLAttributes } from 'astro/types';
|
22
22
|
import Container from './Container.astro';
|
23
|
+
import "../../app.css"
|
23
24
|
|
24
25
|
interface Props extends HTMLAttributes<'section'> {
|
25
26
|
/**
|
@@ -51,6 +52,12 @@ interface Props extends HTMLAttributes<'section'> {
|
|
51
52
|
* @default false
|
52
53
|
*/
|
53
54
|
centered?: boolean;
|
55
|
+
|
56
|
+
/**
|
57
|
+
* 是否显示边框
|
58
|
+
* @default false
|
59
|
+
*/
|
60
|
+
border?: boolean;
|
54
61
|
|
55
62
|
/**
|
56
63
|
* 自定义类名
|
@@ -79,6 +86,7 @@ const {
|
|
79
86
|
container = true,
|
80
87
|
containerSize = 'md',
|
81
88
|
centered = false,
|
89
|
+
border = false,
|
82
90
|
class: className = '',
|
83
91
|
'class:list': classList,
|
84
92
|
id,
|
@@ -88,32 +96,33 @@ const {
|
|
88
96
|
|
89
97
|
// 内边距映射
|
90
98
|
const paddingClasses = {
|
91
|
-
'none': 'py-0',
|
92
|
-
'sm': 'py-6',
|
93
|
-
'md': 'py-12',
|
94
|
-
'lg': 'py-16',
|
95
|
-
'xl': 'py-24'
|
99
|
+
'none': 'cosy:py-0',
|
100
|
+
'sm': 'cosy:py-6',
|
101
|
+
'md': 'cosy:py-12',
|
102
|
+
'lg': 'cosy:py-16',
|
103
|
+
'xl': 'cosy:py-24'
|
96
104
|
};
|
97
105
|
|
98
106
|
// 背景颜色映射
|
99
107
|
const backgroundClasses = {
|
100
|
-
'transparent': 'bg-transparent',
|
101
|
-
'white': 'bg-
|
102
|
-
'gray': 'bg-
|
103
|
-
'primary': 'bg-
|
104
|
-
'secondary': 'bg-
|
105
|
-
'dark': 'bg-
|
108
|
+
'transparent': 'cosy:bg-transparent',
|
109
|
+
'white': 'cosy:bg-base-100',
|
110
|
+
'gray': 'cosy:bg-base-200',
|
111
|
+
'primary': 'cosy:bg-primary/10',
|
112
|
+
'secondary': 'cosy:bg-secondary/10',
|
113
|
+
'dark': 'cosy:bg-neutral cosy:text-neutral-content'
|
106
114
|
};
|
107
115
|
|
108
116
|
// 构建最终类名
|
109
117
|
const sectionClasses = [
|
110
118
|
paddingClasses[padding as keyof typeof paddingClasses],
|
111
119
|
backgroundClasses[background as keyof typeof backgroundClasses],
|
120
|
+
border ? 'cosy:border cosy:rounded-lg' : '',
|
112
121
|
className
|
113
122
|
].join(' ');
|
114
123
|
|
115
124
|
// 内容类名
|
116
|
-
const contentClasses = centered ? 'text-center' : '';
|
125
|
+
const contentClasses = centered ? 'cosy:text-center' : '';
|
117
126
|
---
|
118
127
|
|
119
128
|
<section id={id} class:list={[sectionClasses, classList]} style={style} {...rest}>
|
@@ -127,19 +136,3 @@ const contentClasses = centered ? 'text-center' : '';
|
|
127
136
|
</div>
|
128
137
|
)}
|
129
138
|
</section>
|
130
|
-
|
131
|
-
<style>
|
132
|
-
/* 背景颜色 */
|
133
|
-
.bg-transparent { background-color: transparent; }
|
134
|
-
.bg-white { background-color: #ffffff; }
|
135
|
-
.bg-gray-50 { background-color: #f9fafb; }
|
136
|
-
.bg-gray-100 { background-color: #f3f4f6; }
|
137
|
-
.bg-blue-50 { background-color: #eff6ff; }
|
138
|
-
.bg-gray-900 { background-color: #111827; }
|
139
|
-
|
140
|
-
/* 文字颜色 */
|
141
|
-
.text-white { color: #ffffff; }
|
142
|
-
|
143
|
-
/* 文本对齐 */
|
144
|
-
.text-center { text-align: center; }
|
145
|
-
</style>
|
@@ -46,6 +46,7 @@
|
|
46
46
|
|
47
47
|
// 导入样式
|
48
48
|
import '../../app.css';
|
49
|
+
import Button from '../base/Button.astro';
|
49
50
|
|
50
51
|
interface Props {
|
51
52
|
/**
|
@@ -75,26 +76,32 @@ const {
|
|
75
76
|
} = Astro.props;
|
76
77
|
---
|
77
78
|
|
78
|
-
<dialog id={id} class="modal">
|
79
|
-
<div class:list={["modal-box", className]}>
|
79
|
+
<dialog id={id} class="cosy:modal">
|
80
|
+
<div class:list={["cosy:modal-box", className]}>
|
80
81
|
{showCloseButton && (
|
81
82
|
<form method="dialog">
|
82
|
-
<
|
83
|
+
<Button
|
84
|
+
variant="ghost"
|
85
|
+
size="sm"
|
86
|
+
shape="circle"
|
87
|
+
formmethod="dialog"
|
88
|
+
class="cosy:modal-close-button"
|
89
|
+
>✕</Button>
|
83
90
|
</form>
|
84
91
|
)}
|
85
92
|
|
86
|
-
{title && <h3 class="modal-title">{title}</h3>}
|
93
|
+
{title && <h3 class="cosy:modal-title">{title}</h3>}
|
87
94
|
|
88
|
-
<div class="modal-content">
|
95
|
+
<div class="cosy:modal-content">
|
89
96
|
<slot />
|
90
97
|
</div>
|
91
98
|
|
92
|
-
<div class="modal-action">
|
99
|
+
<div class="cosy:modal-action">
|
93
100
|
<slot name="actions" />
|
94
101
|
</div>
|
95
102
|
</div>
|
96
103
|
|
97
|
-
<form method="dialog" class="modal-backdrop">
|
104
|
+
<form method="dialog" class="cosy:modal-backdrop">
|
98
105
|
<button>关闭</button>
|
99
106
|
</form>
|
100
107
|
</dialog>
|
@@ -1,4 +1,7 @@
|
|
1
1
|
---
|
2
|
+
/**
|
3
|
+
* 菜单图标组件
|
4
|
+
*/
|
2
5
|
interface Props {
|
3
6
|
/**
|
4
7
|
* 图标的大小
|
@@ -14,13 +17,9 @@ interface Props {
|
|
14
17
|
* 自定义类名
|
15
18
|
*/
|
16
19
|
class?: string;
|
17
|
-
/**
|
18
|
-
* 插槽名称
|
19
|
-
*/
|
20
|
-
slot?: string;
|
21
20
|
}
|
22
21
|
|
23
|
-
const { size = '24px', color = 'currentColor', class: className = ''
|
22
|
+
const { size = '24px', color = 'currentColor', class: className = '' } = Astro.props;
|
24
23
|
---
|
25
24
|
|
26
25
|
<svg
|
@@ -35,7 +34,5 @@ const { size = '24px', color = 'currentColor', class: className = '', slot } = A
|
|
35
34
|
stroke-linejoin="round"
|
36
35
|
class={className}
|
37
36
|
>
|
38
|
-
<
|
39
|
-
<line x1="3" y1="6" x2="21" y2="6" />
|
40
|
-
<line x1="3" y1="18" x2="21" y2="18" />
|
37
|
+
<path d="M4 6h16M4 12h16M4 18h16" />
|
41
38
|
</svg>
|
@@ -4,6 +4,38 @@
|
|
4
4
|
*
|
5
5
|
* 适用于文档页面的布局,包含侧边栏导航和目录
|
6
6
|
*
|
7
|
+
* 布局效果:
|
8
|
+
*
|
9
|
+
* 移动端:
|
10
|
+
* ```
|
11
|
+
* +------------------+
|
12
|
+
* | Header |
|
13
|
+
* +------------------+
|
14
|
+
* | Sidebar (1 line) |
|
15
|
+
* +------------------+
|
16
|
+
* | |
|
17
|
+
* | Main Content |
|
18
|
+
* | |
|
19
|
+
* | |
|
20
|
+
* +------------------+
|
21
|
+
* | Footer |
|
22
|
+
* +------------------+
|
23
|
+
* ```
|
24
|
+
*
|
25
|
+
* 桌面端:
|
26
|
+
* ```
|
27
|
+
* +------------------+
|
28
|
+
* | Header |
|
29
|
+
* +--------+---------+
|
30
|
+
* | | |
|
31
|
+
* |Sidebar | Content |
|
32
|
+
* | | |
|
33
|
+
* | | |
|
34
|
+
* +--------+---------+
|
35
|
+
* | Footer |
|
36
|
+
* +------------------+
|
37
|
+
* ```
|
38
|
+
*
|
7
39
|
* @example
|
8
40
|
* ```astro
|
9
41
|
* ---
|
@@ -317,6 +349,12 @@ export interface Props {
|
|
317
349
|
* 首页链接
|
318
350
|
*/
|
319
351
|
footerHomeLink?: string;
|
352
|
+
|
353
|
+
/**
|
354
|
+
* 是否默认展开侧边栏(移动端)
|
355
|
+
* @default false
|
356
|
+
*/
|
357
|
+
defaultSidebarOpen?: boolean;
|
320
358
|
}
|
321
359
|
|
322
360
|
const {
|
@@ -360,6 +398,7 @@ const {
|
|
360
398
|
footerFaqLink,
|
361
399
|
footerMediaLink,
|
362
400
|
footerTechStackLink,
|
401
|
+
defaultSidebarOpen = false,
|
363
402
|
...rest
|
364
403
|
} = Astro.props;
|
365
404
|
|
@@ -386,37 +425,38 @@ const validLang = getValidLanguage(currentLocale);
|
|
386
425
|
currentLocale={currentLocale}
|
387
426
|
sticky={true}
|
388
427
|
basePath={basePath}
|
428
|
+
showSidebarToggle={true}
|
429
|
+
defaultSidebarOpen={defaultSidebarOpen}
|
389
430
|
/>
|
390
431
|
)}
|
391
432
|
|
392
|
-
|
393
|
-
|
394
|
-
|
433
|
+
<div class="cosy:flex cosy:lg:flex-row cosy:flex-col cosy:flex-1">
|
434
|
+
<!-- 侧边栏容器 -->
|
435
|
+
<div class="cosy:top-16 cosy:z-10 cosy:sticky cosy:bg-base-100">
|
436
|
+
<Sidebar
|
437
|
+
sidebarItems={sidebarItems}
|
438
|
+
currentPath={currentPath}
|
439
|
+
debug={false}
|
440
|
+
class="cosy:lg:border-r cosy:border-b cosy:border-base-300 cosy:lg:border-b-0 cosy:lg:w-64 cosy:lg:shrink-0"
|
441
|
+
/>
|
395
442
|
</div>
|
396
|
-
)}
|
397
|
-
|
398
|
-
<div class="cosy:flex-1 cosy:flex">
|
399
|
-
<Sidebar sidebarItems={sidebarItems} currentPath={currentPath} />
|
400
443
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
<TableOfContents lang={currentLocale} />
|
414
|
-
</slot>
|
415
|
-
</div>
|
444
|
+
<!-- 主内容区域 -->
|
445
|
+
<div class="cosy:flex cosy:flex-col cosy:flex-1 cosy:items-center cosy:min-h-screen">
|
446
|
+
<Main class="cosy:lg:py-8 cosy:py-4 cosy:w-full">
|
447
|
+
<div class="cosy:mx-auto cosy:px-4 lg:cosy:px-8 cosy:container">
|
448
|
+
<div class="cosy:flex cosy:lg:flex-row cosy:flex-col cosy:justify-center cosy:gap-8">
|
449
|
+
<Article class="cosy:flex-1 xl:cosy:w-[calc(100%-16rem)]">
|
450
|
+
<slot />
|
451
|
+
</Article>
|
452
|
+
|
453
|
+
{showTableOfContents && (
|
454
|
+
<TableOfContents lang={currentLocale} />
|
455
|
+
)}
|
416
456
|
</div>
|
417
|
-
|
418
|
-
</
|
419
|
-
</
|
457
|
+
</div>
|
458
|
+
</Main>
|
459
|
+
</div>
|
420
460
|
</div>
|
421
461
|
|
422
462
|
{showFooter && (
|
@@ -447,4 +487,20 @@ const validLang = getValidLanguage(currentLocale);
|
|
447
487
|
techStackLink={footerTechStackLink}
|
448
488
|
/>
|
449
489
|
)}
|
490
|
+
|
491
|
+
<script>
|
492
|
+
// Handle sidebar toggle
|
493
|
+
const sidebarToggle = document.getElementById('sidebar-toggle');
|
494
|
+
const sidebar = document.getElementById('sidebar-mobile');
|
495
|
+
const sidebarOverlay = document.getElementById('sidebar-overlay');
|
496
|
+
|
497
|
+
function toggleSidebar() {
|
498
|
+
sidebar?.classList.toggle('cosy:hidden');
|
499
|
+
sidebarOverlay?.classList.toggle('cosy:hidden');
|
500
|
+
document.body.classList.toggle('cosy:overflow-hidden');
|
501
|
+
}
|
502
|
+
|
503
|
+
sidebarToggle?.addEventListener('click', toggleSidebar);
|
504
|
+
sidebarOverlay?.addEventListener('click', toggleSidebar);
|
505
|
+
</script>
|
450
506
|
</BaseLayout>
|
@@ -146,11 +146,11 @@
|
|
146
146
|
*/
|
147
147
|
|
148
148
|
import { processSocialLink } from '../../utils/social';
|
149
|
-
import Link from '../base/Link.astro';
|
150
149
|
import SocialIcon from '../icons/SocialIcon.astro';
|
151
150
|
import type { FooterProps } from '../../types/footer';
|
152
|
-
import { getCurrentLanguage
|
151
|
+
import { getCurrentLanguage } from '../../utils/language';
|
153
152
|
import { createTextGetter } from '../../utils/i18n';
|
153
|
+
import NavSection from './NavSection.astro';
|
154
154
|
|
155
155
|
// 导入样式
|
156
156
|
import '../../app.css';
|
@@ -194,7 +194,6 @@ const {
|
|
194
194
|
techStackLink,
|
195
195
|
debug = false,
|
196
196
|
lang: userLang,
|
197
|
-
enableLogging = false,
|
198
197
|
}: Props = Astro.props;
|
199
198
|
|
200
199
|
// 获取当前语言
|
@@ -202,22 +201,6 @@ const langInfo = getCurrentLanguage(userLang);
|
|
202
201
|
// 创建文本获取函数
|
203
202
|
const t = createTextGetter(langInfo, 'footer');
|
204
203
|
|
205
|
-
// 获取语言来源的描述
|
206
|
-
function getLanguageSourceDescription(source: LanguageSource): string {
|
207
|
-
switch (source) {
|
208
|
-
case LanguageSource.USER:
|
209
|
-
return '用户指定';
|
210
|
-
case LanguageSource.URL:
|
211
|
-
return 'URL参数';
|
212
|
-
case LanguageSource.BROWSER:
|
213
|
-
return '浏览器设置';
|
214
|
-
case LanguageSource.DEFAULT:
|
215
|
-
return '默认语言';
|
216
|
-
default:
|
217
|
-
return '未知来源';
|
218
|
-
}
|
219
|
-
}
|
220
|
-
|
221
204
|
const currentYear = new Date().getFullYear();
|
222
205
|
|
223
206
|
// 处理社交链接
|
@@ -238,28 +221,28 @@ const debugClasses = debug ? {
|
|
238
221
|
---
|
239
222
|
|
240
223
|
<footer class:list={["cosy:footer cosy:sm:footer-horizontal cosy:bg-base-200 cosy:text-base-content cosy:p-10", debugClasses.footer]}>
|
241
|
-
<div class:list={["cosy:flex cosy:flex-col cosy:gap-8 cosy:container cosy:mx-auto cosy:items-center cosy:w-full cosy:md:flex-row cosy:md:justify-between", debugClasses.section]}>
|
224
|
+
<div class:list={["cosy:flex cosy:flex-col cosy:md:h-56 cosy:gap-8 cosy:container cosy:mx-auto cosy:items-center cosy:w-full cosy:md:flex-row cosy:md:justify-between", debugClasses.section]}>
|
242
225
|
{/* 品牌区域 */}
|
243
|
-
<aside class:list={["cosy:max-w-xs", debugClasses.aside]}>
|
244
|
-
<a href={homeLink} class="cosy:flex cosy:items-center cosy:gap-2 cosy:mb-4">
|
226
|
+
<aside class:list={["cosy:max-w-xs cosy:text-center", debugClasses.aside]}>
|
227
|
+
<a href={homeLink} class="cosy:flex cosy:items-center cosy:gap-2 cosy:mb-4 cosy:no-underline">
|
245
228
|
{logo && (
|
246
229
|
<img
|
247
230
|
src={logo.src}
|
248
231
|
alt={logo.alt}
|
249
|
-
class="cosy:
|
232
|
+
class="cosy:w-12 cosy:h-12 cosy:mask cosy:mask-squircle"
|
250
233
|
width="48"
|
251
234
|
height="48"
|
252
235
|
/>
|
253
236
|
)}
|
254
237
|
<div>
|
255
|
-
<h2 class="cosy:
|
238
|
+
<h2 class="cosy:font-bold cosy:text-xl">{siteName}</h2>
|
256
239
|
<p class="cosy:text-base-content/70">{slogan}</p>
|
257
240
|
</div>
|
258
241
|
</a>
|
259
242
|
|
260
243
|
{/* 社交媒体链接 */}
|
261
244
|
{processedSocialLinks.length > 0 && (
|
262
|
-
<div class="cosy:flex cosy:gap-2 cosy:mt-4">
|
245
|
+
<div class="cosy:flex cosy:justify-center cosy:gap-2 cosy:mt-4">
|
263
246
|
{processedSocialLinks.map((link) => (
|
264
247
|
<a
|
265
248
|
href={link.url}
|
@@ -276,49 +259,39 @@ const debugClasses = debug ? {
|
|
276
259
|
</aside>
|
277
260
|
|
278
261
|
{/* 导航区域 */}
|
279
|
-
<div class:list={["cosy:flex cosy:flex-col cosy:gap-8 cosy:mx-auto cosy:max-w-xl cosy:text-center cosy:items-center cosy:w-full cosy:md:flex-row cosy:md:justify-between cosy:md:items-start", debugClasses.section]}>
|
262
|
+
<div class:list={["cosy:flex cosy:h-full cosy:flex-col cosy:justify-center cosy:gap-8 cosy:mx-auto cosy:max-w-xl cosy:text-center cosy:items-center cosy:w-full cosy:md:flex-row cosy:md:justify-between cosy:md:items-start", debugClasses.section]}>
|
280
263
|
{/* 产品导航 */}
|
281
264
|
{products.length > 0 && (
|
282
|
-
<
|
283
|
-
<h6 class="cosy:footer-title">{t('products')}</h6>
|
284
|
-
{products.map((product) => (
|
285
|
-
<Link href={product.href} external={product.external} size='sm' block animation='hover-lift'>
|
286
|
-
{product.name}
|
287
|
-
</Link>
|
288
|
-
))}
|
289
|
-
</nav>
|
265
|
+
<NavSection title={t('products')} links={products} />
|
290
266
|
)}
|
291
267
|
|
292
268
|
{/* 关于导航 */}
|
293
269
|
{(aboutLink || contactLink || teamLink || careersLink) && (
|
294
|
-
<
|
295
|
-
|
296
|
-
{
|
297
|
-
{
|
298
|
-
{
|
299
|
-
|
300
|
-
</nav>
|
270
|
+
<NavSection title={t('about')} links={[
|
271
|
+
{ name: t('aboutUs'), href: aboutLink },
|
272
|
+
{ name: t('team'), href: teamLink },
|
273
|
+
{ name: t('careers'), href: careersLink },
|
274
|
+
{ name: t('contactUs'), href: contactLink }
|
275
|
+
].filter(link => link.href)} />
|
301
276
|
)}
|
302
277
|
|
303
278
|
{/* 资源导航 */}
|
304
279
|
{(newsLink || historyLink || partnersLink || blogLink || faqLink || mediaLink || techStackLink) && (
|
305
|
-
<
|
306
|
-
|
307
|
-
{
|
308
|
-
{
|
309
|
-
{
|
310
|
-
{
|
311
|
-
|
312
|
-
</nav>
|
280
|
+
<NavSection title={t('resources')} links={[
|
281
|
+
{ name: t('news'), href: newsLink },
|
282
|
+
{ name: t('blog'), href: blogLink },
|
283
|
+
{ name: t('faq'), href: faqLink },
|
284
|
+
{ name: t('history'), href: historyLink },
|
285
|
+
{ name: t('techStack'), href: techStackLink }
|
286
|
+
].filter(link => link.href)} />
|
313
287
|
)}
|
314
288
|
|
315
289
|
{/* 法律导航 */}
|
316
290
|
{(termsLink || privacyLink) && (
|
317
|
-
<
|
318
|
-
|
319
|
-
{
|
320
|
-
|
321
|
-
</nav>
|
291
|
+
<NavSection title={t('legal')} links={[
|
292
|
+
{ name: t('terms'), href: termsLink },
|
293
|
+
{ name: t('privacy'), href: privacyLink }
|
294
|
+
].filter(link => link.href)} />
|
322
295
|
)}
|
323
296
|
</div>
|
324
297
|
</div>
|
@@ -334,32 +307,13 @@ const debugClasses = debug ? {
|
|
334
307
|
{/* 底部版权信息 */}
|
335
308
|
<div class:list={["cosy:footer cosy:footer-center cosy:p-4 cosy:bg-base-300 cosy:text-base-content", debugClasses.footer]}>
|
336
309
|
<aside class:list={["cosy:items-center cosy:grid-flow-col", debugClasses.aside]}>
|
337
|
-
<p class="cosy:
|
310
|
+
<p class="cosy:opacity-70 cosy:text-sm">
|
338
311
|
© {currentYear} {company} - {copyright || t('allRightsReserved')}
|
339
312
|
</p>
|
340
313
|
{icp && (
|
341
|
-
<p class="cosy:
|
314
|
+
<p class="cosy:opacity-70 cosy:ml-4 cosy:text-sm">
|
342
315
|
{icp}
|
343
316
|
</p>
|
344
317
|
)}
|
345
318
|
</aside>
|
346
|
-
</div>
|
347
|
-
|
348
|
-
<script define:vars={{ langInfo, enableLogging }}>
|
349
|
-
// 输出语言信息到控制台
|
350
|
-
if (enableLogging) {
|
351
|
-
console.log(`[Footer] 语言信息:`, {
|
352
|
-
语言代码: langInfo.code,
|
353
|
-
语言来源: langInfo.source,
|
354
|
-
来源描述: (() => {
|
355
|
-
switch (langInfo.source) {
|
356
|
-
case 'user': return '用户指定';
|
357
|
-
case 'url': return 'URL参数';
|
358
|
-
case 'browser': return '浏览器设置';
|
359
|
-
case 'default': return '默认语言';
|
360
|
-
default: return '未知来源';
|
361
|
-
}
|
362
|
-
})()
|
363
|
-
});
|
364
|
-
}
|
365
|
-
</script>
|
319
|
+
</div>
|
@@ -1,7 +1,5 @@
|
|
1
1
|
---
|
2
|
-
import SearchIcon from '../icons/SearchIcon.astro';
|
3
2
|
import Link from '../base/Link.astro';
|
4
|
-
import Button from '../base/Button.astro';
|
5
3
|
import Image from '../base/Image.astro';
|
6
4
|
import '../../app.css';
|
7
5
|
|
@@ -42,6 +40,16 @@ interface Props {
|
|
42
40
|
* @default ""
|
43
41
|
*/
|
44
42
|
basePath?: string;
|
43
|
+
/**
|
44
|
+
* 是否显示侧边栏切换按钮
|
45
|
+
* @default false
|
46
|
+
*/
|
47
|
+
showSidebarToggle?: boolean;
|
48
|
+
/**
|
49
|
+
* 侧边栏是否默认展开
|
50
|
+
* @default false
|
51
|
+
*/
|
52
|
+
defaultSidebarOpen?: boolean;
|
45
53
|
}
|
46
54
|
|
47
55
|
const {
|
@@ -54,7 +62,7 @@ const {
|
|
54
62
|
{ code: 'en', name: 'English' }
|
55
63
|
],
|
56
64
|
currentLocale = 'zh-cn',
|
57
|
-
basePath = ''
|
65
|
+
basePath = '',
|
58
66
|
} = Astro.props;
|
59
67
|
|
60
68
|
type NavItem = { href: string; label: string; match: (path: string) => boolean };
|
@@ -77,36 +85,18 @@ function getLanguageUrl(langCode: string) {
|
|
77
85
|
---
|
78
86
|
|
79
87
|
<header class:list={[
|
80
|
-
"cosy:navbar cosy:bg-accent/
|
88
|
+
"cosy:navbar cosy:bg-accent/70 cosy:backdrop-blur cosy:border-base-200 cosy:z-50 cosy:w-full",
|
81
89
|
{ "cosy:fixed cosy:top-0": sticky }
|
82
90
|
]}>
|
83
91
|
<div class="cosy:navbar-start">
|
84
|
-
<!-- 移动端菜单 -->
|
85
|
-
<div class="cosy:dropdown cosy:lg:hidden">
|
86
|
-
<div tabindex="0" role="button" class="cosy:btn cosy:btn-ghost cosy:btn-circle">
|
87
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="cosy:h-5 cosy:w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
88
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7" />
|
89
|
-
</svg>
|
90
|
-
</div>
|
91
|
-
<ul tabindex="0" class="cosy:menu cosy:menu-sm cosy:dropdown-content cosy:mt-3 cosy:z-[1] cosy:p-2 cosy:shadow cosy:bg-base-100 cosy:rounded-box cosy:w-52">
|
92
|
-
{navItems.map((item: NavItem) => (
|
93
|
-
<li>
|
94
|
-
<Link href={item.href}>
|
95
|
-
{item.label}
|
96
|
-
</Link>
|
97
|
-
</li>
|
98
|
-
))}
|
99
|
-
</ul>
|
100
|
-
</div>
|
101
|
-
|
102
92
|
<Link href={logoHref} class="cosy:btn cosy:btn-ghost">
|
103
93
|
<Image src={logo} alt="logo" class="cosy:w-10 cosy:h-10" />
|
104
94
|
</Link>
|
105
95
|
</div>
|
106
96
|
|
107
|
-
<!--
|
108
|
-
<div class="cosy:
|
109
|
-
<ul class="cosy:
|
97
|
+
<!-- 导航 -->
|
98
|
+
<div class="cosy:hidden cosy:lg:flex cosy:navbar-center">
|
99
|
+
<ul class="cosy:px-1 cosy:menu cosy:menu-horizontal">
|
110
100
|
{navItems.map((item: NavItem) => (
|
111
101
|
<li>
|
112
102
|
<Link href={item.href}>
|
@@ -122,11 +112,11 @@ function getLanguageUrl(langCode: string) {
|
|
122
112
|
<div class="cosy:dropdown cosy:dropdown-end">
|
123
113
|
<div tabindex="0" role="button" class="cosy:btn cosy:btn-ghost cosy:btn-sm">
|
124
114
|
<span class="cosy:mr-1">{currentLocale === 'zh-cn' ? '中文' : 'English'}</span>
|
125
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="cosy:
|
115
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="cosy:w-4 cosy:h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
126
116
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
127
117
|
</svg>
|
128
118
|
</div>
|
129
|
-
<ul tabindex="0" class="cosy:
|
119
|
+
<ul tabindex="0" class="cosy:z-[1] cosy:bg-base-100 cosy:shadow cosy:p-2 cosy:rounded-box cosy:w-32 cosy:dropdown-content cosy:menu">
|
130
120
|
{languages.map((lang) => (
|
131
121
|
<li class={currentLocale === lang.code ? "cosy:disabled" : ""}>
|
132
122
|
<a href={getLanguageUrl(lang.code)} class={currentLocale === lang.code ? "cosy:active" : ""}>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
/**
|
3
|
+
* @component NavSection
|
4
|
+
*
|
5
|
+
* @description
|
6
|
+
* NavSection 组件用于在页脚中创建一个导航部分。
|
7
|
+
*
|
8
|
+
* @props
|
9
|
+
* @prop {string} title - 导航部分的标题
|
10
|
+
* @prop {Array<Object>} links - 链接数组,每个对象包含name、href和可选的external属性
|
11
|
+
*
|
12
|
+
*/
|
13
|
+
|
14
|
+
import Link from '../base/Link.astro';
|
15
|
+
|
16
|
+
interface NavSectionProps {
|
17
|
+
title: string;
|
18
|
+
links: Array<{ name: string; href: string; external?: boolean }>;
|
19
|
+
}
|
20
|
+
|
21
|
+
const props = Astro.props as NavSectionProps;
|
22
|
+
const { title, links } = props;
|
23
|
+
---
|
24
|
+
|
25
|
+
<nav class="cosy:flex cosy:flex-col cosy:items-center cosy:gap-3 cosy:hover:bg-base-300 cosy:hover:shadow-lg cosy:p-4 cosy:rounded cosy:h-full! cosy:hover:scale-105 cosy:transition-transform cosy:duration-300">
|
26
|
+
<h6 class="cosy:footer-title">{title}</h6>
|
27
|
+
{links.map((link) => (
|
28
|
+
<Link href={link.href} external={link.external} size='sm' block animation='hover-lift' centerText>
|
29
|
+
{link.name}
|
30
|
+
</Link>
|
31
|
+
))}
|
32
|
+
</nav>
|