@coffic/cosy-ui 0.8.28 → 0.8.29

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.
@@ -38,7 +38,6 @@ export * from './src-astro/products';
38
38
  export * from './src-astro/register';
39
39
  export * from './src-astro/section';
40
40
  export * from './src-astro/sidebar';
41
- export * from './src-astro/sidebar-nav';
42
41
  export * from './src-astro/speak';
43
42
  export * from './src-astro/stack';
44
43
  export * from './src-astro/team-member';
@@ -2,103 +2,104 @@ import { defineCollection, z } from 'astro:content';
2
2
  import { glob } from 'astro/loaders';
3
3
 
4
4
  export const makeArticleCollection = (base: string) => {
5
- return defineCollection({
6
- loader: glob({
7
- pattern: '**/*.{md,mdx}',
8
- base,
9
- }),
10
- schema: z.object({
11
- title: z.string().optional(),
12
- folder: z.boolean().optional(),
13
- order: z.number().optional(),
14
- description: z.string().optional(),
15
- }),
16
- });
5
+ return defineCollection({
6
+ loader: glob({
7
+ pattern: '**/*.{md,mdx}',
8
+ base,
9
+ }),
10
+ schema: z.object({
11
+ title: z.string().optional(),
12
+ folder: z.boolean().optional(),
13
+ order: z.number().optional(),
14
+ description: z.string().optional(),
15
+ }),
16
+ });
17
17
  };
18
18
 
19
19
  export const makeBlogCollection = (base: string) => {
20
- return defineCollection({
21
- loader: glob({
22
- pattern: '**/*.{md,mdx}',
23
- base,
24
- }),
25
- schema: z.object({
26
- title: z.string(),
27
- description: z.string().optional(),
28
- tags: z.array(z.string()).optional(),
29
- date: z.date().optional(),
30
- authors: z
31
- .array(
32
- z.object({
33
- name: z.string(),
34
- picture: z.string().optional(),
35
- url: z.string().optional(),
36
- })
37
- )
38
- .optional(),
39
- }),
40
- });
20
+ return defineCollection({
21
+ loader: glob({
22
+ pattern: '**/*.{md,mdx}',
23
+ base,
24
+ }),
25
+ schema: z.object({
26
+ title: z.string(),
27
+ description: z.string().optional(),
28
+ tags: z.array(z.string()).optional(),
29
+ date: z.date().optional(),
30
+ authors: z
31
+ .array(
32
+ z.object({
33
+ name: z.string(),
34
+ picture: z.string().optional(),
35
+ url: z.string().optional(),
36
+ })
37
+ )
38
+ .optional(),
39
+ }),
40
+ });
41
41
  };
42
42
 
43
43
  export const makeCourseCollection = (base: string) => {
44
- return defineCollection({
45
- loader: glob({
46
- pattern: '**/*.{md,mdx}',
47
- base,
48
- }),
49
- schema: z.object({
50
- title: z.string().optional(),
51
- description: z.string().optional(),
52
- folder: z.boolean().optional(),
53
- order: z.number().optional(),
54
- }),
55
- });
44
+ return defineCollection({
45
+ loader: glob({
46
+ pattern: '**/*.{md,mdx}',
47
+ base,
48
+ }),
49
+ schema: z.object({
50
+ title: z.string().optional(),
51
+ description: z.string().optional(),
52
+ folder: z.boolean().optional(),
53
+ order: z.number().optional(),
54
+ badge: z.string().optional(),
55
+ }),
56
+ });
56
57
  };
57
58
 
58
59
  export const makeExperimentCollection = (base: string) => {
59
- return defineCollection({
60
- loader: glob({
61
- pattern: '**/*.{md,mdx}',
62
- base,
63
- }),
64
- schema: z.object({
65
- title: z.string().optional(),
66
- description: z.string().optional(),
67
- pubDate: z.date().optional(),
68
- }),
69
- });
60
+ return defineCollection({
61
+ loader: glob({
62
+ pattern: '**/*.{md,mdx}',
63
+ base,
64
+ }),
65
+ schema: z.object({
66
+ title: z.string().optional(),
67
+ description: z.string().optional(),
68
+ pubDate: z.date().optional(),
69
+ }),
70
+ });
70
71
  };
71
72
 
72
73
  export const makeLessonCollection = (base: string) => {
73
- return defineCollection({
74
- loader: glob({
75
- pattern: '**/*.{md,mdx}',
76
- base,
77
- }),
78
- schema: z.object({
79
- title: z.string().optional(),
80
- description: z.string().optional(),
81
- authors: z
82
- .array(
83
- z.object({
84
- name: z.string(),
85
- picture: z.string().optional(),
86
- })
87
- )
88
- .optional(),
89
- }),
90
- });
74
+ return defineCollection({
75
+ loader: glob({
76
+ pattern: '**/*.{md,mdx}',
77
+ base,
78
+ }),
79
+ schema: z.object({
80
+ title: z.string().optional(),
81
+ description: z.string().optional(),
82
+ authors: z
83
+ .array(
84
+ z.object({
85
+ name: z.string(),
86
+ picture: z.string().optional(),
87
+ })
88
+ )
89
+ .optional(),
90
+ }),
91
+ });
91
92
  };
92
93
 
93
94
  export const makeMetaCollection = (base: string) => {
94
- return defineCollection({
95
- loader: glob({
96
- pattern: '**/*.{md,mdx}',
97
- base,
98
- }),
99
- schema: z.object({
100
- title: z.string().optional(),
101
- description: z.string().optional(),
102
- }),
103
- });
95
+ return defineCollection({
96
+ loader: glob({
97
+ pattern: '**/*.{md,mdx}',
98
+ base,
99
+ }),
100
+ schema: z.object({
101
+ title: z.string().optional(),
102
+ description: z.string().optional(),
103
+ }),
104
+ });
104
105
  };
@@ -7,95 +7,96 @@ import { COLLECTION_COURSE } from '../database/CourseDB';
7
7
  import { BaseDoc } from './BaseDoc';
8
8
 
9
9
  export default class CourseDoc extends BaseDoc<
10
- typeof COLLECTION_COURSE,
11
- CourseEntry
10
+ typeof COLLECTION_COURSE,
11
+ CourseEntry
12
12
  > {
13
- constructor(entry: CourseEntry) {
14
- super(entry);
15
- }
13
+ constructor(entry: CourseEntry) {
14
+ super(entry);
15
+ }
16
16
 
17
- static fromEntry(entry: CourseEntry) {
18
- return new CourseDoc(entry);
19
- }
17
+ static fromEntry(entry: CourseEntry) {
18
+ return new CourseDoc(entry);
19
+ }
20
20
 
21
- getLink(): string {
22
- return LinkUtil.getCourseLink(this.entry.id);
23
- }
21
+ getLink(): string {
22
+ return LinkUtil.getCourseLink(this.entry.id);
23
+ }
24
24
 
25
- getOrder(): number {
26
- return this.entry.data.order ?? 0;
27
- }
25
+ getOrder(): number {
26
+ return this.entry.data.order ?? 0;
27
+ }
28
28
 
29
- isFolder(): boolean {
30
- return this.entry.data.folder ?? false;
31
- }
29
+ isFolder(): boolean {
30
+ return this.entry.data.folder ?? false;
31
+ }
32
32
 
33
- async getTopDoc(): Promise<CourseDoc | null> {
34
- const id = this.getTopDocId();
35
- const doc = await courseDB.find(id);
36
- return doc;
37
- }
33
+ async getTopDoc(): Promise<CourseDoc | null> {
34
+ const id = this.getTopDocId();
35
+ const doc = await courseDB.find(id);
36
+ return doc;
37
+ }
38
38
 
39
- async getAncestor(level: number): Promise<CourseDoc | null> {
40
- const debug = false;
41
- if (debug) {
42
- cosyLogger.info(`获取 ${this.entry.id} 的祖先文档,level: ${level}`);
39
+ async getAncestor(level: number): Promise<CourseDoc | null> {
40
+ const debug = false;
41
+ if (debug) {
42
+ cosyLogger.info(`获取 ${this.entry.id} 的祖先文档,level: ${level}`);
43
+ }
44
+
45
+ if (level >= this.getLevel()) {
46
+ if (debug) {
47
+ cosyLogger.info(`祖先文档为自身`);
48
+ }
49
+ return this;
50
+ }
51
+
52
+ const id = this.getAncestorId(level);
53
+ const doc = await courseDB.find(id);
54
+ return doc;
43
55
  }
44
56
 
45
- if (level >= this.getLevel()) {
46
- if (debug) {
47
- cosyLogger.info(`祖先文档为自身`);
48
- }
49
- return this;
57
+ /**
58
+ * 获取子文档
59
+ * @returns 子文档列表
60
+ */
61
+ async getChildren(): Promise<CourseDoc[]> {
62
+ const debug = false;
63
+ const children = (await courseDB.getChildren(this.entry.id)).sort(
64
+ (a, b) => a.getOrder() - b.getOrder()
65
+ );
66
+ if (debug && children.length > 0) {
67
+ cosyLogger.array(
68
+ `${this.entry.id} 的子文档(${children.length})`,
69
+ children.map((child) => `#${child.getOrder()} ${child.entry.id}`)
70
+ );
71
+ }
72
+ return children;
50
73
  }
51
74
 
52
- const id = this.getAncestorId(level);
53
- const doc = await courseDB.find(id);
54
- return doc;
55
- }
75
+ override async toSidebarItem(): Promise<SidebarItemEntity> {
76
+ const debug = false;
77
+ const children = await this.getChildren();
78
+ let childItems = await Promise.all(
79
+ children.map((child) => child.toSidebarItem())
80
+ );
56
81
 
57
- /**
58
- * 获取子文档
59
- * @returns 子文档列表
60
- */
61
- async getChildren(): Promise<CourseDoc[]> {
62
- const debug = false;
63
- const children = (await courseDB.getChildren(this.entry.id)).sort(
64
- (a, b) => a.getOrder() - b.getOrder()
65
- );
66
- if (debug && children.length > 0) {
67
- cosyLogger.array(
68
- `${this.entry.id} 的子文档(${children.length})`,
69
- children.map((child) => `#${child.getOrder()} ${child.entry.id}`)
70
- );
71
- }
72
- return children;
73
- }
82
+ if (this.isBook()) {
83
+ childItems = [...childItems];
84
+ }
74
85
 
75
- override async toSidebarItem(): Promise<SidebarItemEntity> {
76
- const debug = false;
77
- const children = await this.getChildren();
78
- let childItems = await Promise.all(
79
- children.map((child) => child.toSidebarItem())
80
- );
86
+ if (debug) {
87
+ cosyLogger.info(`${this.entry.id} 的侧边栏项目`);
88
+ console.log(childItems);
89
+ }
81
90
 
82
- if (this.isBook()) {
83
- childItems = [...childItems];
91
+ return new SidebarItemEntity({
92
+ text: this.getTitle(),
93
+ items: childItems,
94
+ link: this.getLink(),
95
+ badge: this.entry.data.badge,
96
+ });
84
97
  }
85
98
 
86
- if (debug) {
87
- cosyLogger.info(`${this.entry.id} 的侧边栏项目`);
88
- console.log(childItems);
99
+ isBook(): boolean {
100
+ return this.entry.id.split('/').length === 2;
89
101
  }
90
-
91
- return new SidebarItemEntity({
92
- text: this.getTitle(),
93
- items: childItems,
94
- link: this.getLink(),
95
- });
96
- }
97
-
98
- isBook(): boolean {
99
- return this.entry.id.split('/').length === 2;
100
- }
101
102
  }
@@ -5,71 +5,73 @@ import { type ISidebarItem } from '../types/sidebar';
5
5
  * 用于构建网站的侧边栏导航
6
6
  */
7
7
  export class SidebarItemEntity implements ISidebarItem {
8
- text: string;
9
- href: string;
10
- items: ISidebarItem[];
8
+ text: string;
9
+ href: string;
10
+ items: ISidebarItem[];
11
+ badge?: string | number;
11
12
 
12
- constructor(props: { text: string; link?: string; items?: ISidebarItem[] }) {
13
- this.text = props.text;
14
- this.href = props.link || '';
15
- this.items = props.items || [];
16
- }
13
+ constructor(props: { text: string; link?: string; items?: ISidebarItem[]; badge?: string | number }) {
14
+ this.text = props.text;
15
+ this.href = props.link || '';
16
+ this.items = props.items || [];
17
+ this.badge = props.badge;
18
+ }
17
19
 
18
- /**
19
- * 添加子项目
20
- * @param item 要添加的子项目
21
- */
22
- addItem(item: SidebarItemEntity): void {
23
- this.items.push(item);
24
- }
20
+ /**
21
+ * 添加子项目
22
+ * @param item 要添加的子项目
23
+ */
24
+ addItem(item: SidebarItemEntity): void {
25
+ this.items.push(item);
26
+ }
25
27
 
26
- /**
27
- * 获取所有子项目
28
- * @returns 子项目数组
29
- */
30
- getItems(): SidebarItemEntity[] {
31
- return this.items.map((item) => new SidebarItemEntity(item));
32
- }
28
+ /**
29
+ * 获取所有子项目
30
+ * @returns 子项目数组
31
+ */
32
+ getItems(): SidebarItemEntity[] {
33
+ return this.items.map((item) => new SidebarItemEntity(item));
34
+ }
33
35
 
34
- /**
35
- * 获取项目标签
36
- * @returns 项目标签
37
- */
38
- getLabel(): string {
39
- return this.text;
40
- }
36
+ /**
37
+ * 获取项目标签
38
+ * @returns 项目标签
39
+ */
40
+ getLabel(): string {
41
+ return this.text;
42
+ }
41
43
 
42
- /**
43
- * 获取项目链接
44
- * @returns 项目链接
45
- */
46
- getLink(): string {
47
- return this.href;
48
- }
44
+ /**
45
+ * 获取项目链接
46
+ * @returns 项目链接
47
+ */
48
+ getLink(): string {
49
+ return this.href;
50
+ }
49
51
 
50
- /**
51
- * 获取包括自身在内的所有项目
52
- * @returns 包括自身在内的所有项目
53
- */
54
- getItemsIncludingSelf(): SidebarItemEntity[] {
55
- return [this, ...this.getItems()];
56
- }
52
+ /**
53
+ * 获取包括自身在内的所有项目
54
+ * @returns 包括自身在内的所有项目
55
+ */
56
+ getItemsIncludingSelf(): SidebarItemEntity[] {
57
+ return [this, ...this.getItems()];
58
+ }
57
59
 
58
- /**
59
- * 判断是否是分组(有子项目)
60
- * @returns 是否是分组
61
- */
62
- isGroup(): boolean {
63
- return this.items.length > 0;
64
- }
60
+ /**
61
+ * 判断是否是分组(有子项目)
62
+ * @returns 是否是分组
63
+ */
64
+ isGroup(): boolean {
65
+ return this.items.length > 0;
66
+ }
65
67
 
66
- /**
67
- * 判断是否不是分组
68
- * @returns 是否不是分组
69
- */
70
- isNotGroup(): boolean {
71
- return !this.isGroup();
72
- }
68
+ /**
69
+ * 判断是否不是分组
70
+ * @returns 是否不是分组
71
+ */
72
+ isNotGroup(): boolean {
73
+ return !this.isGroup();
74
+ }
73
75
  }
74
76
 
75
77
  /**
@@ -77,13 +79,13 @@ export class SidebarItemEntity implements ISidebarItem {
77
79
  * 实现此接口的类可以提供侧边栏项目
78
80
  */
79
81
  export interface SidebarProvider {
80
- /**
81
- * 转换为侧边栏项目
82
- */
83
- toSidebarItem(): Promise<SidebarItemEntity>;
82
+ /**
83
+ * 转换为侧边栏项目
84
+ */
85
+ toSidebarItem(): Promise<SidebarItemEntity>;
84
86
 
85
- /**
86
- * 获取顶级侧边栏项目
87
- */
88
- getTopSidebarItem?(): Promise<SidebarItemEntity>;
87
+ /**
88
+ * 获取顶级侧边栏项目
89
+ */
90
+ getTopSidebarItem?(): Promise<SidebarItemEntity>;
89
91
  }
@@ -176,6 +176,7 @@ import {
176
176
  } from '../../index-astro';
177
177
  import FooterSection from './FooterSection.astro';
178
178
  import '../../style.ts';
179
+ import FooterCopyright from './FooterCopyright.astro';
179
180
 
180
181
  const {
181
182
  siteName,
@@ -367,17 +368,11 @@ const debugClasses = debug
367
368
  }
368
369
 
369
370
  {/* 底部版权信息 */}
370
- <div
371
- class:list={[
372
- 'cosy:footer cosy:footer-center cosy:p-4 cosy:bg-base-300',
373
- debugClasses.footer,
374
- ]}>
375
- <aside
376
- class:list={['cosy:items-center cosy:grid-flow-col', debugClasses.aside]}>
377
- <p class="cosy:opacity-70 cosy:text-sm">
378
- © {currentYear}
379
- {company} - {copyright || t('allRightsReserved')}
380
- </p>
381
- {icp && <p class="cosy:opacity-70 cosy:ml-4 cosy:text-sm">{icp}</p>}
382
- </aside>
383
- </div>
371
+ <FooterCopyright
372
+ company={company}
373
+ copyright={copyright}
374
+ icp={icp}
375
+ currentYear={currentYear}
376
+ t={t}
377
+ debugClasses={debugClasses}
378
+ />
@@ -0,0 +1,29 @@
1
+ ---
2
+ /**
3
+ * @component FooterCopyright
4
+ * @description 页脚底部版权信息组件。
5
+ * @props
6
+ * @prop {string} company - 公司名称
7
+ * @prop {string} copyright - 版权信息
8
+ * @prop {string} icp - ICP备案号(可选)
9
+ * @prop {number} currentYear - 当前年份
10
+ * @prop {Function} t - 文本获取函数
11
+ * @prop {object} debugClasses - 调试样式类
12
+ */
13
+ const { company, copyright, icp, currentYear, t, debugClasses } = Astro.props;
14
+ ---
15
+
16
+ <div
17
+ class:list={[
18
+ 'cosy:footer cosy:footer-center cosy:p-4 cosy:bg-base-300',
19
+ debugClasses?.footer,
20
+ ]}>
21
+ <aside
22
+ class:list={['cosy:items-center cosy:grid-flow-col', debugClasses?.aside]}>
23
+ <p class="cosy:opacity-70 cosy:text-sm">
24
+ © {currentYear}
25
+ {company} - {copyright || (t && t('allRightsReserved'))}
26
+ </p>
27
+ {icp && <p class="cosy:opacity-70 cosy:ml-4 cosy:text-sm">{icp}</p>}
28
+ </aside>
29
+ </div>
@@ -33,6 +33,9 @@ const { title, links } = Astro.props;
33
33
  <Link
34
34
  href={link.href}
35
35
  size="sm"
36
+ ghost
37
+ btn
38
+ color="primary"
36
39
  target={link.external ? '_blank' : '_self'}
37
40
  variant="text">
38
41
  {link.name}
@@ -260,6 +260,12 @@ export interface Props {
260
260
  * @default false
261
261
  */
262
262
  debug?: boolean;
263
+
264
+ /**
265
+ * 主内容区 padding 尺寸
266
+ * @default 'md'
267
+ */
268
+ mainPadding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
263
269
  }
264
270
 
265
271
  const {
@@ -273,18 +279,27 @@ const {
273
279
  sidebarCollapsed = false,
274
280
  sidebarSize = 'md',
275
281
  sidebarTheme = 'default',
276
- mainBackgroundTheme = 'transparent',
282
+ mainBackgroundTheme = 'base-100',
277
283
  enableToast = true,
278
284
  enableConfirmDialog = true,
279
285
  head,
280
286
  class: className,
281
287
  'class:list': classList,
282
288
  debug = false,
289
+ mainPadding = 'md',
283
290
  ...rest
284
291
  } = Astro.props;
285
292
 
286
293
  const currentPath = Astro.url.pathname;
287
294
  const mainBackgroundStyles = getMainBackgroundTheme(mainBackgroundTheme);
295
+
296
+ const mainPaddingMap = {
297
+ none: '',
298
+ sm: 'cosy:p-2',
299
+ md: 'cosy:p-4',
300
+ lg: 'cosy:p-8',
301
+ xl: 'cosy:p-12',
302
+ };
288
303
  ---
289
304
 
290
305
  <BaseLayout
@@ -328,7 +343,11 @@ const mainBackgroundStyles = getMainBackgroundTheme(mainBackgroundTheme);
328
343
 
329
344
  <!-- 页面内容 -->
330
345
  <main
331
- class:list={['cosy:flex-1 cosy:p-4 cosy:lg:p-6', mainBackgroundStyles]}>
346
+ class:list={[
347
+ 'cosy:flex-1',
348
+ mainPaddingMap[mainPadding],
349
+ mainBackgroundStyles,
350
+ ]}>
332
351
  <slot />
333
352
  </main>
334
353
  </div>
@@ -159,8 +159,8 @@ export const mainBackgroundThemeMap: Record<MainBackgroundTheme, string> = {
159
159
  * @param theme 主内容区域背景主题
160
160
  * @returns 对应的样式类名
161
161
  */
162
- export function getMainBackgroundTheme(theme: MainBackgroundTheme = 'transparent'): string {
162
+ export function getMainBackgroundTheme(theme: MainBackgroundTheme = 'base-100'): string {
163
163
  return mainBackgroundThemeMap[theme];
164
164
  }
165
165
 
166
- export { getIconFromHref, getNavItemIcon, getUserMenuItemIcon } from './tools';
166
+ export { getIconFromHref, getNavItemIcon, getUserMenuItemIcon } from './tools';