@coffic/cosy-ui 0.9.6 → 0.9.7
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/index-astro.ts +0 -4
- package/package.json +1 -5
- package/dist/index-collection.ts +0 -1
- package/dist/src-astro/collection/entities/BaseDoc.ts +0 -28
- package/dist/src-astro/collection/entities/BlogDoc.ts +0 -221
- package/dist/src-astro/collection/entities/CourseDoc.ts +0 -254
- package/dist/src-astro/collection/entities/ExperimentDoc.ts +0 -169
- package/dist/src-astro/collection/entities/Feature.ts +0 -53
- package/dist/src-astro/collection/entities/LessonDoc.ts +0 -203
- package/dist/src-astro/collection/entities/MetaDoc.ts +0 -115
- package/dist/src-astro/collection/entities/SidebarItem.ts +0 -91
- package/dist/src-astro/collection/entities/Tag.ts +0 -42
- package/dist/src-astro/collection/index.ts +0 -11
- package/dist/src-astro/collection/repos/BaseRepo.ts +0 -276
- package/dist/src-astro/collection/repos/BlogRepo.ts +0 -226
- package/dist/src-astro/collection/repos/CourseRepo.ts +0 -137
- package/dist/src-astro/collection/repos/ExperimentRepo.ts +0 -121
- package/dist/src-astro/collection/repos/LessonRepo.ts +0 -128
- package/dist/src-astro/collection/repos/MetaRepo.ts +0 -89
@@ -1,53 +0,0 @@
|
|
1
|
-
class Feature {
|
2
|
-
private translations: Map<string, string>;
|
3
|
-
public emoji: string = '';
|
4
|
-
public link: string = '';
|
5
|
-
public presetIcon: string = '';
|
6
|
-
|
7
|
-
private constructor() {
|
8
|
-
this.translations = new Map();
|
9
|
-
this.translations.set('zh-cn', '');
|
10
|
-
this.translations.set('en', '');
|
11
|
-
}
|
12
|
-
|
13
|
-
public static createWithIcon(emoji: string): Feature {
|
14
|
-
const feature = new Feature();
|
15
|
-
feature.emoji = emoji;
|
16
|
-
return feature;
|
17
|
-
}
|
18
|
-
|
19
|
-
public static createWithPresetIcon(presetIcon: string): Feature {
|
20
|
-
const feature = new Feature();
|
21
|
-
feature.presetIcon = presetIcon;
|
22
|
-
return feature;
|
23
|
-
}
|
24
|
-
|
25
|
-
public setTitle(title: string, lang: string): Feature {
|
26
|
-
this.translations.set(lang, title);
|
27
|
-
return this;
|
28
|
-
}
|
29
|
-
|
30
|
-
public setLink(link: string): Feature {
|
31
|
-
this.link = link;
|
32
|
-
return this;
|
33
|
-
}
|
34
|
-
|
35
|
-
public setPresetIcon(presetIcon: string): Feature {
|
36
|
-
this.presetIcon = presetIcon;
|
37
|
-
return this;
|
38
|
-
}
|
39
|
-
|
40
|
-
public setZh(title: string): Feature {
|
41
|
-
return this.setTitle(title, 'zh-cn');
|
42
|
-
}
|
43
|
-
|
44
|
-
public setEn(title: string): Feature {
|
45
|
-
return this.setTitle(title, 'en');
|
46
|
-
}
|
47
|
-
|
48
|
-
public getTitle(lang: string): string {
|
49
|
-
return this.translations.get(lang) || '';
|
50
|
-
}
|
51
|
-
}
|
52
|
-
|
53
|
-
export default Feature;
|
@@ -1,203 +0,0 @@
|
|
1
|
-
import type { LessonEntry } from '../repos/LessonRepo';
|
2
|
-
import { lessonRepo } from '../repos/LessonRepo';
|
3
|
-
import { cosyLogger } from '../../cosy';
|
4
|
-
import { SidebarItemEntity, type SidebarProvider } from './SidebarItem';
|
5
|
-
import { LinkUtil } from '../../../src/utils/link';
|
6
|
-
import { render } from 'astro:content';
|
7
|
-
import type { IHeadingType } from '../../types/heading';
|
8
|
-
import { BaseDoc } from './BaseDoc';
|
9
|
-
|
10
|
-
/**
|
11
|
-
* 课程文档类,配合 LessonRepo 使用
|
12
|
-
*
|
13
|
-
* 目录结构:
|
14
|
-
* ```
|
15
|
-
* lessons/
|
16
|
-
* ├── build_your_own_web_toolbox/ # 课程目录
|
17
|
-
* │ ├── images/ # 课程图片资源
|
18
|
-
* │ ├── components/ # 课程组件
|
19
|
-
* │ ├── en/ # 英文版本
|
20
|
-
* │ │ ├── index.mdx # 课程首页
|
21
|
-
* │ │ ├── 1.mdx # 第一章
|
22
|
-
* │ │ └── 2.mdx # 第二章
|
23
|
-
* │ └── zh-cn/ # 中文版本
|
24
|
-
* │ ├── index.mdx # 课程首页
|
25
|
-
* │ ├── 1.mdx # 第一章
|
26
|
-
* │ └── 2.mdx # 第二章
|
27
|
-
* └── learn_astro/ # 另一个课程
|
28
|
-
* ├── en/
|
29
|
-
* │ ├── index.mdx
|
30
|
-
* │ ├── 1.mdx
|
31
|
-
* │ └── 2.mdx
|
32
|
-
* └── zh-cn/
|
33
|
-
* ├── index.mdx
|
34
|
-
* ├── 1.mdx
|
35
|
-
* └── 2.mdx
|
36
|
-
* ```
|
37
|
-
*
|
38
|
-
* 说明:
|
39
|
-
* - 每个课程(如 build_your_own_web_toolbox)是一个独立的目录
|
40
|
-
* - 课程目录可以包含多语言版本(en, zh-cn 等)
|
41
|
-
* - 每个语言版本包含完整的课程内容
|
42
|
-
* - 课程目录可以作为 git 子模块独立管理
|
43
|
-
*/
|
44
|
-
export default class LessonDoc extends BaseDoc implements SidebarProvider {
|
45
|
-
entry: LessonEntry;
|
46
|
-
|
47
|
-
constructor(entry: LessonEntry) {
|
48
|
-
super();
|
49
|
-
this.entry = entry;
|
50
|
-
}
|
51
|
-
|
52
|
-
isBook(): boolean {
|
53
|
-
return this.entry.id.split('/').length === 2;
|
54
|
-
}
|
55
|
-
|
56
|
-
getAncestorIds(): string[] {
|
57
|
-
const parts = this.entry.id.split('/');
|
58
|
-
return parts
|
59
|
-
.slice(0, -1)
|
60
|
-
.map((_part: string, index: number) => parts.slice(0, index + 1).join('/'));
|
61
|
-
}
|
62
|
-
|
63
|
-
getAncestorId(level: number): string {
|
64
|
-
const ancestorIds = this.getAncestorIds();
|
65
|
-
|
66
|
-
if (level < 1) {
|
67
|
-
cosyLogger.error('Level must be greater than 0');
|
68
|
-
throw new Error('Level must be greater than 0');
|
69
|
-
}
|
70
|
-
|
71
|
-
if (level >= this.getLevel()) {
|
72
|
-
cosyLogger.debug('当前文档的ID:' + this.entry.id);
|
73
|
-
cosyLogger.debug('当前文档的Level:' + this.getLevel());
|
74
|
-
cosyLogger.debug('正在获取祖先ID,level:' + level);
|
75
|
-
|
76
|
-
throw new Error('Level must be less than the document level');
|
77
|
-
}
|
78
|
-
|
79
|
-
if (ancestorIds.length < level) {
|
80
|
-
cosyLogger.debug('当前文档的ID\n' + this.entry.id);
|
81
|
-
cosyLogger.array('当前文档的祖先IDs', ancestorIds);
|
82
|
-
cosyLogger.debug('正在获取祖先ID,level:\n' + level);
|
83
|
-
|
84
|
-
throw new Error('Level must be greater than 0');
|
85
|
-
}
|
86
|
-
|
87
|
-
return ancestorIds[level - 1];
|
88
|
-
}
|
89
|
-
|
90
|
-
getParentId(): string | null {
|
91
|
-
return this.getAncestorId(this.getLevel() - 1);
|
92
|
-
}
|
93
|
-
|
94
|
-
getTopDocId(): string {
|
95
|
-
const level = this.getLevel();
|
96
|
-
if (level <= 2) {
|
97
|
-
return this.entry.id;
|
98
|
-
}
|
99
|
-
return this.getAncestorId(2);
|
100
|
-
}
|
101
|
-
|
102
|
-
getLang(): string {
|
103
|
-
const debug = false;
|
104
|
-
const parts = this.entry.id.split('/');
|
105
|
-
const lang = parts[1];
|
106
|
-
if (debug) {
|
107
|
-
cosyLogger.info(`获取 ${this.entry.id} 的语言: ${lang}`);
|
108
|
-
}
|
109
|
-
return lang;
|
110
|
-
}
|
111
|
-
|
112
|
-
getSlug(): string {
|
113
|
-
return this.getId().split('/').slice(1).join('/');
|
114
|
-
}
|
115
|
-
|
116
|
-
getDescription(): string {
|
117
|
-
return this.entry.data.description as string;
|
118
|
-
}
|
119
|
-
|
120
|
-
async getBookId(): Promise<string> {
|
121
|
-
return this.getTopDocId();
|
122
|
-
}
|
123
|
-
|
124
|
-
async getBook(): Promise<LessonDoc | null> {
|
125
|
-
const bookId = await this.getBookId();
|
126
|
-
return await lessonRepo.find(bookId);
|
127
|
-
}
|
128
|
-
|
129
|
-
getLink(): string {
|
130
|
-
const debug = false;
|
131
|
-
const lang = this.getLang();
|
132
|
-
const link = LinkUtil.getLessonLink(lang, this.getId());
|
133
|
-
if (debug) {
|
134
|
-
cosyLogger.info(`获取 ${this.entry.id} 的链接: ${link}`);
|
135
|
-
}
|
136
|
-
return link;
|
137
|
-
}
|
138
|
-
|
139
|
-
getHTML(): string {
|
140
|
-
const debug = false;
|
141
|
-
if (debug) {
|
142
|
-
cosyLogger.info(`获取 ${this.entry.id} 的 HTML`);
|
143
|
-
}
|
144
|
-
return this.entry.rendered?.html || '';
|
145
|
-
}
|
146
|
-
|
147
|
-
getHeadings(): IHeadingType[] {
|
148
|
-
const debug = false;
|
149
|
-
if (debug) {
|
150
|
-
cosyLogger.info(`获取 ${this.entry.id} 的 headings`);
|
151
|
-
}
|
152
|
-
return (this.entry.rendered?.metadata?.headings as IHeadingType[]) || [];
|
153
|
-
}
|
154
|
-
|
155
|
-
async getTopDoc(): Promise<LessonDoc | null> {
|
156
|
-
const bookId = await this.getBookId();
|
157
|
-
return await lessonRepo.find(bookId);
|
158
|
-
}
|
159
|
-
|
160
|
-
async getChildren(): Promise<LessonDoc[]> {
|
161
|
-
return await lessonRepo.getChildren(this.entry.id);
|
162
|
-
}
|
163
|
-
|
164
|
-
async getDescendants(): Promise<LessonDoc[]> {
|
165
|
-
return await lessonRepo.getDescendantDocs(this.entry.id);
|
166
|
-
}
|
167
|
-
|
168
|
-
async render(): Promise<any> {
|
169
|
-
return await render(this.entry);
|
170
|
-
}
|
171
|
-
|
172
|
-
async toSidebarItem(): Promise<SidebarItemEntity> {
|
173
|
-
const debug = false;
|
174
|
-
const children = await this.getChildren();
|
175
|
-
let childItems = await Promise.all(
|
176
|
-
children.map((child) => child.toSidebarItem())
|
177
|
-
);
|
178
|
-
if (this.isBook()) {
|
179
|
-
childItems = [...childItems];
|
180
|
-
}
|
181
|
-
if (debug) {
|
182
|
-
cosyLogger.info(`${this.entry.id} 的侧边栏项目`);
|
183
|
-
console.log(childItems);
|
184
|
-
}
|
185
|
-
return new SidebarItemEntity({
|
186
|
-
text: this.getTitle(),
|
187
|
-
items: childItems,
|
188
|
-
link: this.getLink(),
|
189
|
-
});
|
190
|
-
}
|
191
|
-
|
192
|
-
async getTopSidebarItem(): Promise<SidebarItemEntity> {
|
193
|
-
const topDoc = await this.getTopDoc();
|
194
|
-
if (topDoc) {
|
195
|
-
return await topDoc.toSidebarItem();
|
196
|
-
}
|
197
|
-
return new SidebarItemEntity({
|
198
|
-
text: this.getTitle(),
|
199
|
-
items: [],
|
200
|
-
link: this.getLink(),
|
201
|
-
});
|
202
|
-
}
|
203
|
-
}
|
@@ -1,115 +0,0 @@
|
|
1
|
-
import type { MetaEntry } from '../repos/MetaRepo';
|
2
|
-
import { LinkUtil } from '../../../src/utils/link';
|
3
|
-
import { metaRepo } from '../repos/MetaRepo';
|
4
|
-
import { SidebarItemEntity, type SidebarProvider } from './SidebarItem';
|
5
|
-
import { cosyLogger } from '../../cosy';
|
6
|
-
import { BaseDoc } from './BaseDoc';
|
7
|
-
|
8
|
-
export default class MetaDoc extends BaseDoc implements SidebarProvider {
|
9
|
-
entry: MetaEntry;
|
10
|
-
collectionName = 'meta' as const;
|
11
|
-
|
12
|
-
constructor(entry: MetaEntry) {
|
13
|
-
super();
|
14
|
-
this.entry = entry;
|
15
|
-
}
|
16
|
-
|
17
|
-
getAncestorIds(): string[] {
|
18
|
-
const parts = this.entry.id.split('/');
|
19
|
-
return parts
|
20
|
-
.slice(0, -1)
|
21
|
-
.map((_part: string, index: number) => parts.slice(0, index + 1).join('/'));
|
22
|
-
}
|
23
|
-
|
24
|
-
getAncestorId(level: number): string {
|
25
|
-
const ancestorIds = this.getAncestorIds();
|
26
|
-
|
27
|
-
if (level < 1) {
|
28
|
-
cosyLogger.error('Level must be greater than 0');
|
29
|
-
throw new Error('Level must be greater than 0');
|
30
|
-
}
|
31
|
-
|
32
|
-
if (level >= this.getLevel()) {
|
33
|
-
cosyLogger.debug('当前文档的ID:' + this.entry.id);
|
34
|
-
cosyLogger.debug('当前文档的Level:' + this.getLevel());
|
35
|
-
cosyLogger.debug('正在获取祖先ID,level:' + level);
|
36
|
-
|
37
|
-
throw new Error('Level must be less than the document level');
|
38
|
-
}
|
39
|
-
|
40
|
-
if (ancestorIds.length < level) {
|
41
|
-
cosyLogger.debug('当前文档的ID\n' + this.entry.id);
|
42
|
-
cosyLogger.array('当前文档的祖先IDs', ancestorIds);
|
43
|
-
cosyLogger.debug('正在获取祖先ID,level:\n' + level);
|
44
|
-
|
45
|
-
throw new Error('Level must be greater than 0');
|
46
|
-
}
|
47
|
-
|
48
|
-
return ancestorIds[level - 1];
|
49
|
-
}
|
50
|
-
|
51
|
-
getParentId(): string | null {
|
52
|
-
return this.getAncestorId(this.getLevel() - 1);
|
53
|
-
}
|
54
|
-
|
55
|
-
getTopDocId(): string {
|
56
|
-
const level = this.getLevel();
|
57
|
-
if (level <= 2) {
|
58
|
-
return this.entry.id;
|
59
|
-
}
|
60
|
-
return this.getAncestorId(2);
|
61
|
-
}
|
62
|
-
|
63
|
-
getSlug(): string {
|
64
|
-
// 从 ID 中获取 slug,即删除以/分割后的第一个元素
|
65
|
-
return this.getId().split('/').slice(1).join('/');
|
66
|
-
}
|
67
|
-
|
68
|
-
getDescription(): string {
|
69
|
-
return this.entry.data.description as string;
|
70
|
-
}
|
71
|
-
|
72
|
-
getTopDoc(): Promise<MetaDoc | null> {
|
73
|
-
return Promise.resolve(null);
|
74
|
-
}
|
75
|
-
|
76
|
-
getChildren(): Promise<MetaDoc[]> {
|
77
|
-
return Promise.resolve([]);
|
78
|
-
}
|
79
|
-
|
80
|
-
getLink(): string {
|
81
|
-
return LinkUtil.getMetaLink(this.getLang(), this.getSlug());
|
82
|
-
}
|
83
|
-
|
84
|
-
async getSiblingDocs(): Promise<MetaDoc[]> {
|
85
|
-
return await metaRepo.getSiblings(this.entry.id);
|
86
|
-
}
|
87
|
-
|
88
|
-
async getSiblingSidebarItems(): Promise<SidebarItemEntity[]> {
|
89
|
-
const siblings = await this.getSiblingDocs();
|
90
|
-
const siblingItems = await Promise.all(
|
91
|
-
siblings.map((sibling) => {
|
92
|
-
return new SidebarItemEntity({
|
93
|
-
text: sibling.getTitle(),
|
94
|
-
link: sibling.getLink(),
|
95
|
-
});
|
96
|
-
})
|
97
|
-
);
|
98
|
-
return siblingItems;
|
99
|
-
}
|
100
|
-
|
101
|
-
async toSidebarItem(): Promise<SidebarItemEntity> {
|
102
|
-
return new SidebarItemEntity({
|
103
|
-
text: this.getTitle(),
|
104
|
-
link: this.getLink(),
|
105
|
-
});
|
106
|
-
}
|
107
|
-
|
108
|
-
async getTopSidebarItem(): Promise<SidebarItemEntity> {
|
109
|
-
return new SidebarItemEntity({
|
110
|
-
text: '了解我们',
|
111
|
-
items: await this.getSiblingSidebarItems(),
|
112
|
-
link: '',
|
113
|
-
});
|
114
|
-
}
|
115
|
-
}
|
@@ -1,91 +0,0 @@
|
|
1
|
-
import { type ISidebarItem } from '../../types/sidebar';
|
2
|
-
|
3
|
-
/**
|
4
|
-
* 侧边栏提供者接口
|
5
|
-
* 实现此接口的类可以提供侧边栏项目
|
6
|
-
*/
|
7
|
-
export interface SidebarProvider {
|
8
|
-
/**
|
9
|
-
* 转换为侧边栏项目
|
10
|
-
*/
|
11
|
-
toSidebarItem(): Promise<SidebarItemEntity>;
|
12
|
-
|
13
|
-
/**
|
14
|
-
* 获取顶级侧边栏项目
|
15
|
-
*/
|
16
|
-
getTopSidebarItem?(): Promise<SidebarItemEntity>;
|
17
|
-
}
|
18
|
-
|
19
|
-
/**
|
20
|
-
* 侧边栏项目类
|
21
|
-
* 用于构建网站的侧边栏导航
|
22
|
-
*/
|
23
|
-
export class SidebarItemEntity implements ISidebarItem {
|
24
|
-
text: string;
|
25
|
-
href: string;
|
26
|
-
items: ISidebarItem[];
|
27
|
-
badge?: string | number;
|
28
|
-
|
29
|
-
constructor(props: { text: string; link?: string; items?: ISidebarItem[]; badge?: string | number }) {
|
30
|
-
this.text = props.text;
|
31
|
-
this.href = props.link || '';
|
32
|
-
this.items = props.items || [];
|
33
|
-
this.badge = props.badge;
|
34
|
-
}
|
35
|
-
|
36
|
-
/**
|
37
|
-
* 添加子项目
|
38
|
-
* @param item 要添加的子项目
|
39
|
-
*/
|
40
|
-
addItem(item: SidebarItemEntity): void {
|
41
|
-
this.items.push(item);
|
42
|
-
}
|
43
|
-
|
44
|
-
/**
|
45
|
-
* 获取所有子项目
|
46
|
-
* @returns 子项目数组
|
47
|
-
*/
|
48
|
-
getItems(): SidebarItemEntity[] {
|
49
|
-
return this.items.map((item) => new SidebarItemEntity(item));
|
50
|
-
}
|
51
|
-
|
52
|
-
/**
|
53
|
-
* 获取项目标签
|
54
|
-
* @returns 项目标签
|
55
|
-
*/
|
56
|
-
getLabel(): string {
|
57
|
-
return this.text;
|
58
|
-
}
|
59
|
-
|
60
|
-
/**
|
61
|
-
* 获取项目链接
|
62
|
-
* @returns 项目链接
|
63
|
-
*/
|
64
|
-
getLink(): string {
|
65
|
-
return this.href;
|
66
|
-
}
|
67
|
-
|
68
|
-
/**
|
69
|
-
* 获取包括自身在内的所有项目
|
70
|
-
* @returns 包括自身在内的所有项目
|
71
|
-
*/
|
72
|
-
getItemsIncludingSelf(): SidebarItemEntity[] {
|
73
|
-
return [this, ...this.getItems()];
|
74
|
-
}
|
75
|
-
|
76
|
-
/**
|
77
|
-
* 判断是否是分组(有子项目)
|
78
|
-
* @returns 是否是分组
|
79
|
-
*/
|
80
|
-
isGroup(): boolean {
|
81
|
-
return this.items.length > 0;
|
82
|
-
}
|
83
|
-
|
84
|
-
/**
|
85
|
-
* 判断是否不是分组
|
86
|
-
* @returns 是否不是分组
|
87
|
-
*/
|
88
|
-
isNotGroup(): boolean {
|
89
|
-
return !this.isGroup();
|
90
|
-
}
|
91
|
-
}
|
@@ -1,42 +0,0 @@
|
|
1
|
-
import { blogRepo } from '../repos/BlogRepo';
|
2
|
-
import { SidebarItemEntity } from './SidebarItem';
|
3
|
-
import { type ITagStaticPath } from '../../types/static-path';
|
4
|
-
import { LinkUtil } from '../../../src/utils/link';
|
5
|
-
|
6
|
-
export class Tag {
|
7
|
-
name: string;
|
8
|
-
lang: string;
|
9
|
-
count: number;
|
10
|
-
|
11
|
-
constructor(name: string, count: number, lang: string) {
|
12
|
-
this.name = name;
|
13
|
-
this.count = count;
|
14
|
-
this.lang = lang;
|
15
|
-
}
|
16
|
-
|
17
|
-
toSidebarItem(lang: string): SidebarItemEntity {
|
18
|
-
return new SidebarItemEntity({
|
19
|
-
text: this.name,
|
20
|
-
link: LinkUtil.getTagLink(lang, this.name),
|
21
|
-
});
|
22
|
-
}
|
23
|
-
|
24
|
-
toTagPath(): ITagStaticPath {
|
25
|
-
return {
|
26
|
-
params: { slug: this.lang + '/blogs/tag/' + this.name },
|
27
|
-
props: { tag: this.name },
|
28
|
-
};
|
29
|
-
}
|
30
|
-
|
31
|
-
static async makeRootSidebarItem(lang: string): Promise<SidebarItemEntity> {
|
32
|
-
const tags = await blogRepo.getTagsByLang(lang);
|
33
|
-
|
34
|
-
return new SidebarItemEntity({
|
35
|
-
text: 'Tags',
|
36
|
-
link: LinkUtil.getTagLink(lang, ''),
|
37
|
-
items: tags.map((tag: Tag) => tag.toSidebarItem(lang)),
|
38
|
-
});
|
39
|
-
}
|
40
|
-
}
|
41
|
-
|
42
|
-
export default Tag;
|
@@ -1,11 +0,0 @@
|
|
1
|
-
export * from './repos/BaseRepo';
|
2
|
-
export * from './repos/BlogRepo';
|
3
|
-
export * from './repos/ExperimentRepo';
|
4
|
-
export * from './repos/LessonRepo';
|
5
|
-
export * from './repos/MetaRepo';
|
6
|
-
export * from './repos/CourseRepo';
|
7
|
-
|
8
|
-
export * from './entities/BlogDoc';
|
9
|
-
export * from './entities/ExperimentDoc';
|
10
|
-
export * from './entities/LessonDoc';
|
11
|
-
export * from './entities/MetaDoc';
|