@coffic/cosy-ui 0.4.7 → 0.5.2

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.
@@ -30,12 +30,7 @@
30
30
  * ```astro
31
31
  * <Header
32
32
  * logo={import("../assets/logo.png")}
33
- * languages={[
34
- * { code: "zh-cn", name: "简体中文" },
35
- * { code: "en", name: "English" },
36
- * { code: "ja", name: "日本語" }
37
- * ]}
38
- * currentLocale="zh-cn"
33
+ * languages={["zh-cn", "en", "ja"]}
39
34
  * />
40
35
  * ```
41
36
  *
@@ -57,54 +52,20 @@
57
52
  import '../../app.css';
58
53
  import Link from '../base/Link.astro';
59
54
  import Image from '../base/Image.astro';
60
- import type { HeaderProps } from '../../index';
55
+ import { LanguageSwitcher, LinkUtil, type HeaderProps, type NavItem } from '../../index';
61
56
  import Logo from '../../assets/logo-rounded.png';
62
57
 
63
- interface Props extends HeaderProps {}
58
+ export interface Props extends HeaderProps {}
64
59
 
65
60
  const {
66
- basePath = '',
67
- currentLocale = 'zh-cn',
68
61
  height = 'md',
69
- languages = [
70
- { code: 'zh-cn', name: '中文' },
71
- { code: 'en', name: 'English' },
72
- ],
62
+ languages = ['zh-cn', 'en'],
73
63
  logo = Logo,
74
64
  logoHref = '/',
75
65
  navItems = [],
76
66
  sticky = true,
77
67
  } = Astro.props;
78
68
 
79
- type NavItem = { href: string; label: string; match: (path: string) => boolean };
80
-
81
- // 获取当前路径
82
- const currentPath = Astro.url.pathname;
83
-
84
- // 处理基础路径
85
- const basePathPattern = basePath ? new RegExp(`^${basePath}`) : null;
86
- const pathWithoutBase = basePathPattern ? currentPath.replace(basePathPattern, '') : currentPath;
87
-
88
- // 提取路径部分,排除语言代码
89
- const pathWithoutLocale = pathWithoutBase.replace(/^\/(zh-cn|en)/, '');
90
-
91
- // 生成语言切换链接
92
- function getLanguageUrl(langCode: string) {
93
- // 如果有基础路径,需要加上
94
- return `${basePath}/${langCode}${pathWithoutLocale}`;
95
- }
96
-
97
- // 获取初始高度(优先使用localStorage中的值)
98
- type HeightType = '3xs' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
99
-
100
- let initialHeight: HeightType;
101
- if (typeof window !== 'undefined') {
102
- const storedHeight = localStorage.getItem('cosy-header-height');
103
- initialHeight = (storedHeight as HeightType) || height;
104
- } else {
105
- initialHeight = height;
106
- }
107
-
108
69
  // 根据高度设置样式
109
70
  const headerHeightClasses = {
110
71
  '3xs': 'cosy:h-4',
@@ -116,7 +77,16 @@ const headerHeightClasses = {
116
77
  xl: 'cosy:h-20',
117
78
  };
118
79
 
119
- const headerHeightClass = headerHeightClasses[initialHeight];
80
+ const headerHeightClass = headerHeightClasses[height];
81
+ const linkHeightClasses = {
82
+ '3xs': 'cosy:py-0',
83
+ '2xs': 'cosy:py-0',
84
+ xs: 'cosy:py-0',
85
+ sm: 'cosy:py-1',
86
+ md: 'cosy:py-1',
87
+ lg: 'cosy:py-2',
88
+ xl: 'cosy:py-3',
89
+ };
120
90
 
121
91
  // 设置logo大小
122
92
  const logoSizeClasses = {
@@ -129,7 +99,13 @@ const logoSizeClasses = {
129
99
  xl: 'cosy:w-12 cosy:h-12',
130
100
  };
131
101
 
132
- const logoSizeClass = logoSizeClasses[initialHeight];
102
+ const logoSizeClass = logoSizeClasses[height];
103
+ const linkHeightClass = linkHeightClasses[height];
104
+ const currentPath = Astro.url.pathname;
105
+ const activeLink = LinkUtil.getActiveLink(
106
+ currentPath,
107
+ navItems.map((item: NavItem) => item.href)
108
+ );
133
109
  ---
134
110
 
135
111
  <header
@@ -140,42 +116,30 @@ const logoSizeClass = logoSizeClasses[initialHeight];
140
116
  ]}>
141
117
  <div class="cosy:navbar-start">
142
118
  <Link
119
+ animation="none"
143
120
  href={logoHref}
144
- class:list={[
145
- 'cosy:btn cosy:btn-ghost',
146
- initialHeight === 'xs' || initialHeight === '2xs' || initialHeight === '3xs'
147
- ? 'cosy:btn-xs cosy:h-auto cosy:min-h-0 cosy:p-1'
148
- : initialHeight === 'sm'
149
- ? 'cosy:btn-sm'
150
- : '',
151
- ]}>
152
- <Image transition="none" src={logo} alt="logo" class={logoSizeClass} />
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
+ />
153
130
  </Link>
154
131
  </div>
155
132
 
156
133
  <!-- 导航 -->
157
134
  <div class="cosy:hidden cosy:lg:flex cosy:navbar-center">
158
- <ul
159
- class:list={[
160
- 'cosy:px-1 cosy:menu cosy:menu-horizontal',
161
- initialHeight === 'xs' || initialHeight === '2xs' || initialHeight === '3xs'
162
- ? 'cosy:menu-xs'
163
- : initialHeight === 'sm'
164
- ? 'cosy:menu-sm'
165
- : '',
166
- ]}>
135
+ <ul class:list={['cosy:px-1 cosy:menu cosy:menu-horizontal', linkHeightClass]}>
167
136
  {
168
137
  navItems.map((item: NavItem) => (
169
138
  <li>
170
139
  <Link
140
+ variant={activeLink == item.href ? 'primary' : 'default'}
171
141
  href={item.href}
172
- class:list={[
173
- initialHeight === 'xs' || initialHeight === '2xs' || initialHeight === '3xs'
174
- ? 'cosy:py-0 cosy:px-2 cosy:min-h-0'
175
- : initialHeight === 'sm'
176
- ? 'cosy:py-1 cosy:min-h-6'
177
- : '',
178
- ]}>
142
+ class:list={[linkHeightClass]}>
179
143
  {item.label}
180
144
  </Link>
181
145
  </li>
@@ -185,45 +149,6 @@ const logoSizeClass = logoSizeClasses[initialHeight];
185
149
  </div>
186
150
 
187
151
  <div class="cosy:navbar-end">
188
- <!-- 语言切换按钮 -->
189
- <div class="cosy:dropdown cosy:dropdown-end">
190
- <div
191
- tabindex="0"
192
- role="button"
193
- class:list={[
194
- 'cosy:btn cosy:btn-ghost',
195
- initialHeight === 'xs' || initialHeight === '2xs' || initialHeight === '3xs'
196
- ? 'cosy:btn-xs cosy:h-auto cosy:min-h-0 cosy:p-1'
197
- : initialHeight === 'sm'
198
- ? 'cosy:btn-sm'
199
- : 'cosy:btn-sm',
200
- ]}>
201
- <span class="cosy:mr-1">{currentLocale === 'zh-cn' ? '中文' : 'English'}</span>
202
- <svg
203
- xmlns="http://www.w3.org/2000/svg"
204
- class="cosy:w-4 cosy:h-4"
205
- fill="none"
206
- viewBox="0 0 24 24"
207
- stroke="currentColor">
208
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"
209
- ></path>
210
- </svg>
211
- </div>
212
- <ul
213
- tabindex="0"
214
- class="cosy:z-[1] cosy:bg-base-100 cosy:shadow cosy:p-2 cosy:rounded-box cosy:w-32 cosy:dropdown-content cosy:menu">
215
- {
216
- languages.map((lang) => (
217
- <li class={currentLocale === lang.code ? 'cosy:disabled' : ''}>
218
- <a
219
- href={getLanguageUrl(lang.code)}
220
- class={currentLocale === lang.code ? 'cosy:active' : ''}>
221
- {lang.name}
222
- </a>
223
- </li>
224
- ))
225
- }
226
- </ul>
227
- </div>
152
+ <LanguageSwitcher languages={languages} />
228
153
  </div>
229
154
  </header>
@@ -73,7 +73,7 @@ function getVerticalMarginBottomClasses(marginBottom: string) {
73
73
 
74
74
  // 获取当前活动的一级导航项
75
75
  const currentSection = sidebarItems.find((section) =>
76
- section.items.some((item) => isPathMatch(currentPath, item.href))
76
+ section.items?.some((item) => isPathMatch(currentPath, item.href))
77
77
  );
78
78
  ---
79
79
 
@@ -90,7 +90,7 @@ const currentSection = sidebarItems.find((section) =>
90
90
  data-modal-target="mobile-sidebar">
91
91
  <MenuIcon class="cosy:w-5 cosy:h-5" />
92
92
  </button>
93
- <span class="cosy:font-medium cosy:text-sm">{currentSection?.title || '导航'}</span>
93
+ <span class="cosy:font-medium cosy:text-sm">{currentSection?.text || '导航'}</span>
94
94
  </div>
95
95
  </div>;
96
96
 
@@ -7,13 +7,13 @@
7
7
 
8
8
  import { isPathMatch } from '../../utils/path';
9
9
  import '../../app.css';
10
- import type { SidebarSection, SidebarItem } from '../../types/sidebar';
10
+ import type { SidebarItem } from '../../types/sidebar';
11
11
 
12
12
  interface Props {
13
13
  /**
14
14
  * 侧边栏项目
15
15
  */
16
- sidebarItems: SidebarSection[];
16
+ sidebarItems: SidebarItem[];
17
17
 
18
18
  /**
19
19
  * 当前路径
@@ -39,13 +39,13 @@ const debugClass = debug ? 'cosy:border cosy:border-red-500' : '';
39
39
 
40
40
  <nav class:list={['cosy:p-4', debugClass, className]}>
41
41
  {
42
- sidebarItems.map((section: SidebarSection) => (
42
+ sidebarItems.map((section: SidebarItem) => (
43
43
  <div class:list={['cosy:mb-6', debugClass]}>
44
44
  <h3 class:list={['cosy:font-bold cosy:mb-2 cosy:text-base-content/70', debugClass]}>
45
- {section.title}
45
+ {section.text}
46
46
  </h3>
47
47
  <ul class:list={['cosy:menu cosy:bg-base-200 cosy:rounded-box cosy:w-56', debugClass]}>
48
- {section.items.map((item: SidebarItem) => {
48
+ {section.items?.map((item: SidebarItem) => {
49
49
  const isActive = isPathMatch(currentPath, item.href);
50
50
  return (
51
51
  <li class:list={[debugClass]}>
@@ -22,88 +22,42 @@
22
22
  * 自定义语言列表:
23
23
  * ```astro
24
24
  * <LanguageSwitcher
25
- * languages={[
26
- * { code: 'zh-cn', name: '简体中文' },
27
- * { code: 'en', name: 'English' },
28
- * { code: 'ja', name: '日本語' }
29
- * ]}
30
- * currentLocale="en"
25
+ * languages={['zh-cn', 'en']}
31
26
  * />
32
27
  * ```
33
28
  */
34
29
 
35
- import Button from '../base/Button.astro';
36
- import Link from '../base/Link.astro';
30
+ import ChevronDownIcon from '../icons/ChevronDownIcon.astro';
37
31
  import '../../app.css';
38
-
39
- interface Language {
40
- code: string;
41
- name: string;
42
- }
32
+ import { LanguageUtil } from '../../utils/language';
43
33
 
44
34
  interface Props {
45
- /**
46
- * 自定义类名
47
- */
48
- class?: string;
49
-
50
- /**
51
- * 语言列表
52
- * @default [{ code: 'zh-cn', name: '简体中文' }, { code: 'en', name: 'English' }]
53
- */
54
- languages?: Language[];
55
-
56
- /**
57
- * 当前语言
58
- * @default 'zh-cn'
59
- */
60
- currentLocale?: string;
35
+ languages: string[];
61
36
  }
62
37
 
63
- const {
64
- class: className,
65
- languages = [
66
- { code: 'zh-cn', name: '简体中文' },
67
- { code: 'en', name: 'English' },
68
- ],
69
- currentLocale = 'zh-cn',
70
- } = Astro.props;
38
+ const { languages = ['zh-cn', 'en'] } = Astro.props;
71
39
 
72
- const currentLanguageName =
73
- languages.find((lang: Language) => lang.code === currentLocale)?.name || '简体中文';
74
-
75
- // 为每个语言生成对应的URL
76
- function generateLanguageUrl(langCode: string): string {
77
- const currentPath = Astro.url.pathname;
78
- const pathParts = currentPath.split('/').filter(Boolean);
79
- const firstPathPart = pathParts[0];
80
- const supportedLanguages = languages.map((lang: Language) => lang.code);
81
- const isFirstPartLang = supportedLanguages.includes(firstPathPart);
82
-
83
- if (isFirstPartLang) {
84
- pathParts[0] = langCode;
85
- return '/' + pathParts.join('/');
86
- } else {
87
- return '/' + langCode + (currentPath === '/' ? '' : currentPath);
88
- }
89
- }
40
+ const currentLocale = Astro.currentLocale;
41
+ const currentLanguageName = LanguageUtil.getLanguageName(currentLocale);
90
42
  ---
91
43
 
92
- <div class:list={['cosy:dropdown cosy:dropdown-end', className]}>
93
- <Button variant="ghost" size="sm" class="cosy:p-1">
94
- {currentLanguageName}
95
- </Button>
44
+ <!-- 语言切换按钮 -->
45
+ <div class="cosy:dropdown cosy:dropdown-end">
46
+ <div tabindex="0" role="button" class:list={['cosy:btn cosy:btn-ghost']}>
47
+ <span class="cosy:mr-1">{currentLanguageName}</span>
48
+ <ChevronDownIcon size="16px" class="cosy:w-4 cosy:h-4" />
49
+ </div>
96
50
  <ul
97
- tabindex={0}
98
- class="cosy:bg-slate-900 cosy:dark:bg-slate-800 cosy:shadow-lg cosy:p-2 cosy:rounded-box cosy:w-40 cosy:dropdown-content cosy:menu">
51
+ tabindex="0"
52
+ class="cosy:z-[1] cosy:bg-base-100 cosy:shadow cosy:p-2 cosy:rounded-box cosy:w-32 cosy:dropdown-content cosy:menu">
99
53
  {
100
- languages.map((lang: Language) => (
101
- <li>
102
- <Link
103
- href={generateLanguageUrl(lang.code)}
104
- class:list={[{ 'cosy:active': lang.code === currentLocale }]}>
105
- {lang.name}
106
- </Link>
54
+ languages.map((lang) => (
55
+ <li class={currentLocale === lang ? 'cosy:disabled' : ''}>
56
+ <a
57
+ href={LanguageUtil.getRelativeLink(lang, Astro)}
58
+ class={currentLocale === lang ? 'cosy:active' : ''}>
59
+ {LanguageUtil.getLanguageName(lang)}
60
+ </a>
107
61
  </li>
108
62
  ))
109
63
  }
@@ -54,8 +54,8 @@
54
54
 
55
55
  // 导入样式
56
56
  import '../../app.css';
57
- import { getCurrentLanguage } from '../../utils/language';
58
57
  import { createTextGetter } from '../../utils/i18n';
58
+ import { LanguageUtil } from '../../utils/language';
59
59
 
60
60
  interface Props {
61
61
  /**
@@ -111,7 +111,7 @@ const {
111
111
  } = Astro.props;
112
112
 
113
113
  // 获取当前语言
114
- const langInfo = getCurrentLanguage(userLang);
114
+ const langInfo = LanguageUtil.getCurrentLanguage(userLang);
115
115
  // 创建文本获取函数
116
116
  const t = createTextGetter(langInfo, 'tableOfContents');
117
117
  // 获取标题文本,如果用户提供了标题则使用用户提供的标题
@@ -1,5 +1,5 @@
1
1
  import { getCollection, getEntry, type CollectionEntry, type DataEntryMap } from "astro:content";
2
- import { logger } from "@/utils/logger";
2
+ import { logger } from "../utils/logger";
3
3
 
4
4
  /**
5
5
  * BaseDB 是所有数据库类的基类,提供了通用的文档操作功能。
@@ -23,7 +23,7 @@ import { logger } from "@/utils/logger";
23
23
  * @template Entry - Collection 对应的条目类型
24
24
  * @template Doc - 文档类型,通常是自定义的文档类
25
25
  */
26
- export default abstract class BaseDB<
26
+ export abstract class BaseDB<
27
27
  Collection extends keyof DataEntryMap,
28
28
  Entry extends CollectionEntry<Collection>,
29
29
  Doc
@@ -1,24 +1,21 @@
1
- /**
2
- * 侧边栏项目接口
3
- */
4
- export interface SidebarItemProps {
5
- label: string;
6
- link?: string;
7
- items?: SidebarItem[];
8
- }
1
+ import { type SidebarItem } from '../types/sidebar';
9
2
 
10
3
  /**
11
4
  * 侧边栏项目类
12
5
  * 用于构建网站的侧边栏导航
13
6
  */
14
- export class SidebarItem {
15
- label: string;
16
- link: string;
7
+ export class SidebarItemEntity implements SidebarItem {
8
+ text: string;
9
+ href: string;
17
10
  items: SidebarItem[];
18
11
 
19
- constructor(props: SidebarItemProps) {
20
- this.label = props.label;
21
- this.link = props.link || '';
12
+ constructor(props: {
13
+ text: string;
14
+ link?: string;
15
+ items?: SidebarItem[];
16
+ }) {
17
+ this.text = props.text;
18
+ this.href = props.link || '';
22
19
  this.items = props.items || [];
23
20
  }
24
21
 
@@ -26,7 +23,7 @@ export class SidebarItem {
26
23
  * 添加子项目
27
24
  * @param item 要添加的子项目
28
25
  */
29
- addItem(item: SidebarItem): void {
26
+ addItem(item: SidebarItemEntity): void {
30
27
  this.items.push(item);
31
28
  }
32
29
 
@@ -34,8 +31,8 @@ export class SidebarItem {
34
31
  * 获取所有子项目
35
32
  * @returns 子项目数组
36
33
  */
37
- getItems(): SidebarItem[] {
38
- return this.items;
34
+ getItems(): SidebarItemEntity[] {
35
+ return this.items.map(item => new SidebarItemEntity(item));
39
36
  }
40
37
 
41
38
  /**
@@ -43,7 +40,7 @@ export class SidebarItem {
43
40
  * @returns 项目标签
44
41
  */
45
42
  getLabel(): string {
46
- return this.label;
43
+ return this.text;
47
44
  }
48
45
 
49
46
  /**
@@ -51,14 +48,14 @@ export class SidebarItem {
51
48
  * @returns 项目链接
52
49
  */
53
50
  getLink(): string {
54
- return this.link;
51
+ return this.href;
55
52
  }
56
53
 
57
54
  /**
58
55
  * 获取包括自身在内的所有项目
59
56
  * @returns 包括自身在内的所有项目
60
57
  */
61
- getItemsIncludingSelf(): SidebarItem[] {
58
+ getItemsIncludingSelf(): SidebarItemEntity[] {
62
59
  return [this, ...this.getItems()];
63
60
  }
64
61
 
@@ -87,10 +84,10 @@ export interface SidebarProvider {
87
84
  /**
88
85
  * 转换为侧边栏项目
89
86
  */
90
- toSidebarItem(): Promise<SidebarItem>;
87
+ toSidebarItem(): Promise<SidebarItemEntity>;
91
88
 
92
89
  /**
93
90
  * 获取顶级侧边栏项目
94
91
  */
95
- getTopSidebarItem?(): Promise<SidebarItem>;
96
- }
92
+ getTopSidebarItem?(): Promise<SidebarItemEntity>;
93
+ }
package/dist/index.ts CHANGED
@@ -42,6 +42,9 @@ export { default as Article } from './components/typography/Article.astro';
42
42
  export { default as Text } from './components/typography/Text.astro';
43
43
  export { default as Heading } from './components/typography/Heading.astro';
44
44
 
45
+ // Errors Page
46
+ export { default as ErrorPage404 } from './components/errors/404.astro';
47
+
45
48
  // Icons
46
49
  export { default as SocialIcon } from './components/icons/SocialIcon.astro';
47
50
  export { default as TwitterIcon } from './components/icons/TwitterIcon.astro';
@@ -1,11 +1,11 @@
1
1
  import { render, type RenderResult, type CollectionEntry, type DataEntryMap } from "astro:content";
2
- import { SidebarItem, type SidebarProvider } from "../entities/SidebarItem";
2
+ import { SidebarItemEntity, type SidebarProvider } from "../entities/SidebarItem";
3
3
  import { logger } from "../utils/logger";
4
4
 
5
5
  /**
6
6
  * 文档基类,提供所有文档类型共享的基本功能
7
7
  */
8
- export default abstract class BaseDoc<Collection extends keyof DataEntryMap, T extends CollectionEntry<Collection>> implements SidebarProvider {
8
+ export abstract class BaseDoc<Collection extends keyof DataEntryMap, T extends CollectionEntry<Collection>> implements SidebarProvider {
9
9
  protected entry: T;
10
10
 
11
11
  constructor(entry: T) {
@@ -72,9 +72,9 @@ export default abstract class BaseDoc<Collection extends keyof DataEntryMap, T e
72
72
  * 转换为侧边栏项目
73
73
  * 基本实现,只包含当前文档
74
74
  */
75
- async toSidebarItem(): Promise<SidebarItem> {
76
- return new SidebarItem({
77
- label: this.getTitle(),
75
+ async toSidebarItem(): Promise<SidebarItemEntity> {
76
+ return new SidebarItemEntity({
77
+ text: this.getTitle(),
78
78
  link: this.getLink(),
79
79
  });
80
80
  }
@@ -125,7 +125,7 @@ export abstract class HierarchicalDoc<Collection extends keyof DataEntryMap, T e
125
125
  * 转换为侧边栏项目
126
126
  * 如果文档有子文档,会包含子文档的侧边栏项目
127
127
  */
128
- override async toSidebarItem(): Promise<SidebarItem> {
128
+ override async toSidebarItem(): Promise<SidebarItemEntity> {
129
129
  const debug = false;
130
130
 
131
131
  const children = await this.getChildren();
@@ -137,8 +137,8 @@ export abstract class HierarchicalDoc<Collection extends keyof DataEntryMap, T e
137
137
  console.log(childItems);
138
138
  }
139
139
 
140
- return new SidebarItem({
141
- label: this.getTitle(),
140
+ return new SidebarItemEntity({
141
+ text: this.getTitle(),
142
142
  items: childItems,
143
143
  link: this.getLink(),
144
144
  });
@@ -149,14 +149,14 @@ export abstract class HierarchicalDoc<Collection extends keyof DataEntryMap, T e
149
149
  * 如果有顶级文档,返回顶级文档的侧边栏项目
150
150
  * 否则返回当前文档的侧边栏项目
151
151
  */
152
- async getTopSidebarItem(): Promise<SidebarItem> {
152
+ async getTopSidebarItem(): Promise<SidebarItemEntity> {
153
153
  const topDoc = await this.getTopDoc();
154
154
  if (topDoc) {
155
155
  return await topDoc.toSidebarItem();
156
156
  }
157
157
 
158
- return new SidebarItem({
159
- label: this.getTitle(),
158
+ return new SidebarItemEntity({
159
+ text: this.getTitle(),
160
160
  items: [],
161
161
  link: this.getLink(),
162
162
  });
@@ -25,7 +25,7 @@ export interface HeaderProps {
25
25
  /**
26
26
  * 语言选项列表
27
27
  */
28
- languages?: Array<{ code: string; name: string }>;
28
+ languages?: string[];
29
29
 
30
30
  /**
31
31
  * Logo图片元数据
@@ -41,11 +41,7 @@ export interface HeaderProps {
41
41
  /**
42
42
  * 导航菜单项
43
43
  */
44
- navItems?: Array<{
45
- href: string;
46
- label: string;
47
- match: (path: string) => boolean;
48
- }>;
44
+ navItems?: NavItem[];
49
45
 
50
46
  /**
51
47
  * 是否显示侧边栏切换按钮
@@ -68,3 +64,5 @@ export interface HeaderProps {
68
64
  */
69
65
  sticky?: boolean;
70
66
  }
67
+
68
+ export type NavItem = { href: string; label: string; };
@@ -1,19 +1,17 @@
1
+ /**
2
+ * 侧边栏项目
3
+ */
1
4
  export interface SidebarItem {
2
5
  href: string;
3
6
  text: string;
4
7
  items?: SidebarItem[];
5
8
  }
6
9
 
7
- export interface SidebarSection {
8
- title: string;
9
- items: SidebarItem[];
10
- }
11
-
12
10
  export interface SidebarProps {
13
11
  /**
14
12
  * 侧边栏项目
15
13
  */
16
- sidebarItems: SidebarSection[];
14
+ sidebarItems: SidebarItem[];
17
15
 
18
16
  /**
19
17
  * 桌面端类名