@coffic/cosy-ui 0.5.12 → 0.5.14
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/README.md +2 -31
- package/dist/collections/ArticleCollection.ts +19 -0
- package/dist/collections/BlogCollection.ts +28 -0
- package/dist/collections/CourseCollection.ts +11 -0
- package/dist/collections/ExperimentCollection.ts +18 -0
- package/dist/collections/LessonCollection.ts +25 -0
- package/dist/collections/MetaCollection.ts +17 -0
- package/dist/components/data-display/TeamMembers.astro +1 -1
- package/dist/components/display/Card.astro +0 -3
- package/dist/components/display/CodeBlock.astro +1 -2
- package/dist/components/display/Modal.astro +1 -2
- package/dist/components/icons/SearchIcon.astro +30 -34
- package/dist/components/icons/SunCloudyIcon.astro +35 -39
- package/dist/components/layouts/BaseLayout.astro +3 -2
- package/dist/components/navigation/TableOfContents.astro +6 -3
- package/dist/components/typography/Text.astro +1 -1
- package/dist/entities/MetaDoc.ts +10 -10
- package/dist/entities/Tag.ts +7 -7
- package/dist/index.ts +8 -0
- package/dist/utils/lang_package.ts +205 -206
- package/package.json +3 -3
package/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
[](README.md)
|
4
4
|
[](README-zh.md)
|
5
|
+
[](README-dev.md)
|
5
6
|
[](https://www.npmjs.com/package/@coffic/cosy-ui)
|
6
7
|
[](https://coffic.cn)
|
7
8
|
[](https://github.com/nookery)
|
@@ -23,34 +24,4 @@ Usage in Astro components:
|
|
23
24
|
import { Button } from "@coffic/cosy-ui";
|
24
25
|
---
|
25
26
|
<Button>Hi</Button>
|
26
|
-
```
|
27
|
-
|
28
|
-
## Development
|
29
|
-
|
30
|
-
### Install Dependencies
|
31
|
-
|
32
|
-
```bash
|
33
|
-
pnpm install
|
34
|
-
```
|
35
|
-
|
36
|
-
### Start Development Server
|
37
|
-
|
38
|
-
```bash
|
39
|
-
pnpm dev
|
40
|
-
```
|
41
|
-
|
42
|
-
### Build
|
43
|
-
|
44
|
-
Build:
|
45
|
-
|
46
|
-
```bash
|
47
|
-
pnpm build
|
48
|
-
```
|
49
|
-
|
50
|
-
## Contributing
|
51
|
-
|
52
|
-
Issues and Pull Requests are welcome!
|
53
|
-
|
54
|
-
## License
|
55
|
-
|
56
|
-
MIT
|
27
|
+
```
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { defineCollection, z } from 'astro:content';
|
2
|
+
import { glob } from 'astro/loaders';
|
3
|
+
|
4
|
+
export const makeArticleCollection = (base: string) => {
|
5
|
+
return defineCollection({
|
6
|
+
loader: glob({
|
7
|
+
pattern: '**/*.{md,mdx}',
|
8
|
+
base,
|
9
|
+
}),
|
10
|
+
schema: articleSchema,
|
11
|
+
});
|
12
|
+
};
|
13
|
+
|
14
|
+
export const articleSchema = z.object({
|
15
|
+
title: z.string(),
|
16
|
+
folder: z.boolean(),
|
17
|
+
order: z.number(),
|
18
|
+
description: z.string().optional(),
|
19
|
+
});
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { defineCollection, z } from 'astro:content';
|
2
|
+
import { glob } from 'astro/loaders';
|
3
|
+
|
4
|
+
export const blogSchema = z.object({
|
5
|
+
title: z.string(),
|
6
|
+
description: z.string().optional(),
|
7
|
+
tags: z.array(z.string()).optional(),
|
8
|
+
date: z.date().optional(),
|
9
|
+
authors: z
|
10
|
+
.array(
|
11
|
+
z.object({
|
12
|
+
name: z.string(),
|
13
|
+
picture: z.string().optional(),
|
14
|
+
url: z.string().optional(),
|
15
|
+
})
|
16
|
+
)
|
17
|
+
.optional(),
|
18
|
+
});
|
19
|
+
|
20
|
+
export const makeBlogCollection = (base: string) => {
|
21
|
+
return defineCollection({
|
22
|
+
loader: glob({
|
23
|
+
pattern: '**/*.{md,mdx}',
|
24
|
+
base,
|
25
|
+
}),
|
26
|
+
schema: blogSchema,
|
27
|
+
});
|
28
|
+
};
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { defineCollection, z } from 'astro:content';
|
2
|
+
import { glob } from 'astro/loaders';
|
3
|
+
|
4
|
+
export const experimentSchema = z.object({
|
5
|
+
title: z.string(),
|
6
|
+
description: z.string().optional(),
|
7
|
+
pubDate: z.date().optional(),
|
8
|
+
});
|
9
|
+
|
10
|
+
export const makeExperimentCollection = (base: string) => {
|
11
|
+
return defineCollection({
|
12
|
+
loader: glob({
|
13
|
+
pattern: '**/*.{md,mdx}',
|
14
|
+
base,
|
15
|
+
}),
|
16
|
+
schema: experimentSchema,
|
17
|
+
});
|
18
|
+
};
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import { defineCollection, z } from 'astro:content';
|
2
|
+
import { glob } from 'astro/loaders';
|
3
|
+
|
4
|
+
export const lessonSchema = z.object({
|
5
|
+
title: z.string(),
|
6
|
+
description: z.string().optional(),
|
7
|
+
authors: z
|
8
|
+
.array(
|
9
|
+
z.object({
|
10
|
+
name: z.string(),
|
11
|
+
picture: z.string().optional(),
|
12
|
+
})
|
13
|
+
)
|
14
|
+
.optional(),
|
15
|
+
});
|
16
|
+
|
17
|
+
export const makeLessonCollection = (base: string) => {
|
18
|
+
return defineCollection({
|
19
|
+
loader: glob({
|
20
|
+
pattern: '**/*.{md,mdx}',
|
21
|
+
base,
|
22
|
+
}),
|
23
|
+
schema: lessonSchema,
|
24
|
+
});
|
25
|
+
};
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { defineCollection, z } from 'astro:content';
|
2
|
+
import { glob } from 'astro/loaders';
|
3
|
+
|
4
|
+
export const metaSchema = z.object({
|
5
|
+
title: z.string(),
|
6
|
+
description: z.string().optional(),
|
7
|
+
});
|
8
|
+
|
9
|
+
export const makeMetaCollection = (base: string) => {
|
10
|
+
return defineCollection({
|
11
|
+
loader: glob({
|
12
|
+
pattern: '**/*.{md,mdx}',
|
13
|
+
base,
|
14
|
+
}),
|
15
|
+
schema: metaSchema,
|
16
|
+
});
|
17
|
+
};
|
@@ -93,7 +93,7 @@ const getGridClasses = (cols: 2 | 3 | 4) => {
|
|
93
93
|
<div class:list={['cosy:w-full cosy:mx-auto cosy:px-4', className]}>
|
94
94
|
<div class:list={['cosy:grid cosy:gap-6', ...getGridClasses(columnsValue)]}>
|
95
95
|
{
|
96
|
-
members.map((member: TeamMemberData
|
96
|
+
members.map((member: TeamMemberData) => (
|
97
97
|
<div class="cosy:transition-all cosy:hover:-translate-y-1 cosy:duration-300 cosy:transform">
|
98
98
|
<TeamMember {...member} />
|
99
99
|
</div>
|
@@ -51,12 +51,11 @@ import '../../app.css';
|
|
51
51
|
|
52
52
|
interface Props {
|
53
53
|
code: string;
|
54
|
-
lang?: string;
|
55
54
|
title?: string;
|
56
55
|
showLineNumbers?: boolean;
|
57
56
|
}
|
58
57
|
|
59
|
-
const { code,
|
58
|
+
const { code, title, showLineNumbers = true } = Astro.props;
|
60
59
|
|
61
60
|
// 移除代码字符串开头和结尾的空行
|
62
61
|
const trimmedCode = code.trim();
|
@@ -103,7 +103,7 @@ const { id, title, showCloseButton = true, class: className = '' } = Astro.props
|
|
103
103
|
</form>
|
104
104
|
</dialog>
|
105
105
|
|
106
|
-
<script define:vars={{ id }}>
|
106
|
+
<script is:inline define:vars={{ id }}>
|
107
107
|
// 为了方便使用,我们提供一些辅助方法
|
108
108
|
document.addEventListener('DOMContentLoaded', () => {
|
109
109
|
const modal = document.getElementById(id);
|
@@ -117,4 +117,3 @@ const { id, title, showCloseButton = true, class: className = '' } = Astro.props
|
|
117
117
|
});
|
118
118
|
});
|
119
119
|
</script>
|
120
|
-
|
@@ -1,40 +1,36 @@
|
|
1
1
|
---
|
2
2
|
interface Props {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
/**
|
18
|
-
* 插槽名称
|
19
|
-
*/
|
20
|
-
slot?: string;
|
3
|
+
/**
|
4
|
+
* 图标的大小
|
5
|
+
* @default "24px"
|
6
|
+
*/
|
7
|
+
size?: string;
|
8
|
+
/**
|
9
|
+
* 图标的颜色
|
10
|
+
* @default "currentColor"
|
11
|
+
*/
|
12
|
+
color?: string;
|
13
|
+
/**
|
14
|
+
* 自定义类名
|
15
|
+
*/
|
16
|
+
class?: string;
|
21
17
|
}
|
22
18
|
|
23
|
-
const { size = '24px', color = 'currentColor', class: className = ''
|
19
|
+
const { size = '24px', color = 'currentColor', class: className = '' } = Astro.props;
|
24
20
|
---
|
25
21
|
|
26
|
-
<svg
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
>
|
38
|
-
|
39
|
-
|
40
|
-
|
22
|
+
<svg
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
24
|
+
width={size}
|
25
|
+
height={size}
|
26
|
+
viewBox="0 0 24 24"
|
27
|
+
fill="none"
|
28
|
+
stroke={color}
|
29
|
+
stroke-width="2"
|
30
|
+
stroke-linecap="round"
|
31
|
+
stroke-linejoin="round"
|
32
|
+
class={className}>
|
33
|
+
<circle cx="11" cy="11" r="8"></circle>
|
34
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
35
|
+
</svg>
|
36
|
+
|
@@ -1,45 +1,41 @@
|
|
1
1
|
---
|
2
2
|
interface Props {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
/**
|
18
|
-
* 插槽名称
|
19
|
-
*/
|
20
|
-
slot?: string;
|
3
|
+
/**
|
4
|
+
* 图标的大小
|
5
|
+
* @default "24px"
|
6
|
+
*/
|
7
|
+
size?: string;
|
8
|
+
/**
|
9
|
+
* 图标的颜色
|
10
|
+
* @default "currentColor"
|
11
|
+
*/
|
12
|
+
color?: string;
|
13
|
+
/**
|
14
|
+
* 自定义类名
|
15
|
+
*/
|
16
|
+
class?: string;
|
21
17
|
}
|
22
18
|
|
23
|
-
const { size = '24px', color = 'currentColor', class: className = ''
|
19
|
+
const { size = '24px', color = 'currentColor', class: className = '' } = Astro.props;
|
24
20
|
---
|
25
21
|
|
26
|
-
<svg
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
>
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
22
|
+
<svg
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
24
|
+
width={size}
|
25
|
+
height={size}
|
26
|
+
viewBox="0 0 24 24"
|
27
|
+
fill="none"
|
28
|
+
stroke={color}
|
29
|
+
stroke-width="2"
|
30
|
+
stroke-linecap="round"
|
31
|
+
stroke-linejoin="round"
|
32
|
+
class={className}>
|
33
|
+
<path d="M12 2v2"></path>
|
34
|
+
<path d="M2 12h2"></path>
|
35
|
+
<path d="M20 12h2"></path>
|
36
|
+
<path d="M4.93 4.93l1.41 1.41"></path>
|
37
|
+
<path d="M17.66 4.93l-1.41 1.41"></path>
|
38
|
+
<path d="M12 19a4 4 0 100-8 4 4 0 000 8z"></path>
|
39
|
+
<path d="M12 15a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
|
40
|
+
</svg>
|
41
|
+
|
@@ -50,7 +50,7 @@
|
|
50
50
|
*/
|
51
51
|
|
52
52
|
import '../../app.css';
|
53
|
-
import type
|
53
|
+
import { LinkUtil, type MetaProps } from '../../index';
|
54
54
|
|
55
55
|
export interface Props extends MetaProps {
|
56
56
|
debug?: boolean;
|
@@ -71,6 +71,7 @@ const {
|
|
71
71
|
|
72
72
|
// 处理类名
|
73
73
|
let bodyClasses = debug ? 'cosy:border cosy:border-red-500' : className || '';
|
74
|
+
const faviconPath = LinkUtil.createUrl('/favicon.png');
|
74
75
|
---
|
75
76
|
|
76
77
|
<!doctype html>
|
@@ -82,7 +83,7 @@ let bodyClasses = debug ? 'cosy:border cosy:border-red-500' : className || '';
|
|
82
83
|
{description && <meta name="description" content={description} />}
|
83
84
|
{keywords && <meta name="keywords" content={keywords} />}
|
84
85
|
<meta name="generator" content={Astro.generator} />
|
85
|
-
<link rel="icon" type="image/svg+xml" href=
|
86
|
+
<link rel="icon" type="image/svg+xml" href={faviconPath} />
|
86
87
|
|
87
88
|
<!-- 自定义样式 -->
|
88
89
|
{customStyles && <style set:html={customStyles} />}
|
@@ -125,8 +125,7 @@ const tocId = `toc-${Math.random().toString(36).substring(2, 9)}`;
|
|
125
125
|
<div
|
126
126
|
class={`toc-container toc-scroll-container ${fixed ? 'cosy:w-64' : 'cosy:w-full cosy:max-w-xs'}`}
|
127
127
|
id={`${tocId}-container`}
|
128
|
-
style="display: none;"
|
129
|
-
>
|
128
|
+
style="display: none;">
|
130
129
|
<div class="cosy:bg-base-100 cosy:shadow-inner cosy:card">
|
131
130
|
<div class="cosy:p-4 cosy:card-body">
|
132
131
|
<div class="cosy:mb-2 cosy:font-bold cosy:text-lg cosy:card-title">{titleText}</div>
|
@@ -140,7 +139,11 @@ const tocId = `toc-${Math.random().toString(36).substring(2, 9)}`;
|
|
140
139
|
</div>
|
141
140
|
</aside>
|
142
141
|
|
143
|
-
<script
|
142
|
+
<script
|
143
|
+
is:inline
|
144
|
+
define:vars={{ selector, maxDepth, tocId, containerSelector, minHeadings, langInfo }}
|
145
|
+
>
|
146
|
+
// @ts-nocheck
|
144
147
|
// 在页面加载完成后生成目录
|
145
148
|
function generateTOC() {
|
146
149
|
// 使用指定的容器选择器查找内容容器
|
package/dist/entities/MetaDoc.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { SidebarItemEntity } from './SidebarItem';
|
2
2
|
import type { MetaEntry } from '../database/MetaDB';
|
3
3
|
import { LinkUtil } from '../utils/link';
|
4
4
|
import { BaseDoc } from './BaseDoc';
|
@@ -44,12 +44,12 @@ export default class MetaDoc extends BaseDoc<typeof COLLECTION_NAME, MetaEntry>
|
|
44
44
|
/**
|
45
45
|
* 获取兄弟文档的侧边栏项目
|
46
46
|
*/
|
47
|
-
async getSiblingSidebarItems(): Promise<
|
47
|
+
async getSiblingSidebarItems(): Promise<SidebarItemEntity[]> {
|
48
48
|
const siblings = await this.getSiblingDocs();
|
49
49
|
const siblingItems = await Promise.all(
|
50
50
|
siblings.map((sibling) => {
|
51
|
-
return new
|
52
|
-
|
51
|
+
return new SidebarItemEntity({
|
52
|
+
text: sibling.getTitle(),
|
53
53
|
link: sibling.getLink(),
|
54
54
|
});
|
55
55
|
})
|
@@ -61,9 +61,9 @@ export default class MetaDoc extends BaseDoc<typeof COLLECTION_NAME, MetaEntry>
|
|
61
61
|
* 重写侧边栏项目方法
|
62
62
|
* 对于元数据页面,我们不显示子项目
|
63
63
|
*/
|
64
|
-
override async toSidebarItem(): Promise<
|
65
|
-
return new
|
66
|
-
|
64
|
+
override async toSidebarItem(): Promise<SidebarItemEntity> {
|
65
|
+
return new SidebarItemEntity({
|
66
|
+
text: this.getTitle(),
|
67
67
|
link: this.getLink(),
|
68
68
|
});
|
69
69
|
}
|
@@ -72,9 +72,9 @@ export default class MetaDoc extends BaseDoc<typeof COLLECTION_NAME, MetaEntry>
|
|
72
72
|
* 重写顶级侧边栏项目方法
|
73
73
|
* 对于元数据页面,我们显示所有兄弟页面作为侧边栏项目
|
74
74
|
*/
|
75
|
-
async getTopSidebarItem(): Promise<
|
76
|
-
return new
|
77
|
-
|
75
|
+
async getTopSidebarItem(): Promise<SidebarItemEntity> {
|
76
|
+
return new SidebarItemEntity({
|
77
|
+
text: '了解我们',
|
78
78
|
items: await this.getSiblingSidebarItems(),
|
79
79
|
link: '',
|
80
80
|
});
|
package/dist/entities/Tag.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import blogDB from '../database/BlogDB';
|
2
|
-
import {
|
2
|
+
import { SidebarItemEntity } from './SidebarItem';
|
3
3
|
import { type TagStaticPath } from '../types/static-path';
|
4
4
|
import { LinkUtil } from '../utils/link';
|
5
5
|
|
@@ -14,9 +14,9 @@ export class Tag {
|
|
14
14
|
this.lang = lang;
|
15
15
|
}
|
16
16
|
|
17
|
-
toSidebarItem(lang: string):
|
18
|
-
return new
|
19
|
-
|
17
|
+
toSidebarItem(lang: string): SidebarItemEntity {
|
18
|
+
return new SidebarItemEntity({
|
19
|
+
text: this.name,
|
20
20
|
link: LinkUtil.getTagLink(lang, this.name),
|
21
21
|
});
|
22
22
|
}
|
@@ -28,11 +28,11 @@ export class Tag {
|
|
28
28
|
};
|
29
29
|
}
|
30
30
|
|
31
|
-
static async makeRootSidebarItem(lang: string): Promise<
|
31
|
+
static async makeRootSidebarItem(lang: string): Promise<SidebarItemEntity> {
|
32
32
|
const tags = await blogDB.getTagsByLang(lang);
|
33
33
|
|
34
|
-
return new
|
35
|
-
|
34
|
+
return new SidebarItemEntity({
|
35
|
+
text: 'Tags',
|
36
36
|
link: LinkUtil.getTagLink(lang, ''),
|
37
37
|
items: tags.map((tag: Tag) => tag.toSidebarItem(lang)),
|
38
38
|
});
|
package/dist/index.ts
CHANGED
@@ -7,6 +7,14 @@ export { default as Alert } from './components/base/Alert.astro';
|
|
7
7
|
export { default as Speak } from './components/base/Speak.astro';
|
8
8
|
export { default as Module } from './components/base/Module.astro';
|
9
9
|
|
10
|
+
// Collections
|
11
|
+
export * from './collections/ArticleCollection';
|
12
|
+
export * from './collections/BlogCollection';
|
13
|
+
export * from './collections/CourseCollection';
|
14
|
+
export * from './collections/ExperimentCollection';
|
15
|
+
export * from './collections/LessonCollection';
|
16
|
+
export * from './collections/MetaCollection';
|
17
|
+
|
10
18
|
// Navigation
|
11
19
|
export { default as ThemeSwitcher } from './components/navigation/ThemeSwitcher.astro';
|
12
20
|
export { default as TableOfContents } from './components/navigation/TableOfContents.astro';
|
@@ -3,139 +3,141 @@
|
|
3
3
|
* 提供链式API来创建和管理多语言文本
|
4
4
|
*/
|
5
5
|
export class LangEntry {
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
6
|
+
private translations: Record<string, string> = {};
|
7
|
+
|
8
|
+
/**
|
9
|
+
* 设置中文文本
|
10
|
+
* @param text 中文文本
|
11
|
+
*/
|
12
|
+
setZh(text: string): LangEntry {
|
13
|
+
this.translations['zh-cn'] = text;
|
14
|
+
return this;
|
15
|
+
}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* 设置英文文本
|
19
|
+
* @param text 英文文本
|
20
|
+
*/
|
21
|
+
setEn(text: string): LangEntry {
|
22
|
+
this.translations['en'] = text;
|
23
|
+
return this;
|
24
|
+
}
|
25
|
+
|
26
|
+
/**
|
27
|
+
* 设置日文文本
|
28
|
+
* @param text 日文文本
|
29
|
+
*/
|
30
|
+
setJa(text: string): LangEntry {
|
31
|
+
this.translations['ja'] = text;
|
32
|
+
return this;
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* 设置任意语言的文本
|
37
|
+
* @param lang 语言代码
|
38
|
+
* @param text 文本内容
|
39
|
+
*/
|
40
|
+
set(lang: string, text: string): LangEntry {
|
41
|
+
this.translations[lang] = text;
|
42
|
+
return this;
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* 设置所有语言为相同的文本值
|
47
|
+
* 适用于不需要翻译的品牌名、专有名词等
|
48
|
+
* @param text 所有语言共用的文本
|
49
|
+
*/
|
50
|
+
setAll(text: string): LangEntry {
|
51
|
+
// 如果已有语言,则更新它们
|
52
|
+
if (Object.keys(this.translations).length > 0) {
|
53
|
+
for (const lang of Object.keys(this.translations)) {
|
54
|
+
this.translations[lang] = text;
|
55
|
+
}
|
56
|
+
} else {
|
57
|
+
// 默认至少设置中英文
|
58
|
+
this.translations['zh-cn'] = text;
|
59
|
+
this.translations['en'] = text;
|
60
|
+
}
|
61
|
+
return this;
|
62
|
+
}
|
63
|
+
|
64
|
+
/**
|
65
|
+
* 获取指定语言的文本
|
66
|
+
* @param lang 语言代码
|
67
|
+
* @param defaultValue 默认值,如果未找到翻译则返回此值
|
68
|
+
*/
|
69
|
+
get(lang: string, defaultValue?: string): string {
|
70
|
+
return this.translations[lang] || defaultValue || this.getFirst() || '';
|
71
|
+
}
|
72
|
+
|
73
|
+
/**
|
74
|
+
* 获取第一个可用的翻译文本
|
75
|
+
*/
|
76
|
+
getFirst(): string | undefined {
|
77
|
+
const keys = Object.keys(this.translations);
|
78
|
+
return keys.length > 0 ? this.translations[keys[0]] : undefined;
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* 获取所有可用的语言代码
|
83
|
+
*/
|
84
|
+
getLanguages(): string[] {
|
85
|
+
return Object.keys(this.translations);
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* 获取所有翻译
|
90
|
+
*/
|
91
|
+
getAll(): Record<string, string> {
|
92
|
+
return { ...this.translations };
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* 合并另一个语言条目
|
97
|
+
* @param other 要合并的语言条目
|
98
|
+
*/
|
99
|
+
merge(other: LangEntry): LangEntry {
|
100
|
+
Object.assign(this.translations, other.getAll());
|
101
|
+
return this;
|
102
|
+
}
|
103
|
+
|
104
|
+
/**
|
105
|
+
* 检查是否包含指定语言
|
106
|
+
* @param lang 语言代码
|
107
|
+
*/
|
108
|
+
has(lang: string): boolean {
|
109
|
+
return lang in this.translations;
|
110
|
+
}
|
111
|
+
|
112
|
+
/**
|
113
|
+
* 转换为普通对象
|
114
|
+
*/
|
115
|
+
toObject(): Record<string, string> {
|
116
|
+
return { ...this.translations };
|
117
|
+
}
|
118
|
+
|
119
|
+
/**
|
120
|
+
* 允许以对象属性方式访问翻译
|
121
|
+
* 例如: entry['zh-cn'] 或 entry.en
|
122
|
+
*/
|
123
|
+
[key: string]: any;
|
124
124
|
}
|
125
125
|
|
126
126
|
// 创建索引访问器的Proxy处理程序
|
127
127
|
const langEntryHandler: ProxyHandler<LangEntry> = {
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
128
|
+
get(target: LangEntry, prop: string | symbol): any {
|
129
|
+
// 如果是字符串属性并且不是LangEntry的方法,则尝试作为语言代码获取翻译
|
130
|
+
if (
|
131
|
+
typeof prop === 'string' &&
|
132
|
+
!(prop in Object.getPrototypeOf(target)) &&
|
133
|
+
prop !== 'translations'
|
134
|
+
) {
|
135
|
+
return target.get(prop);
|
136
|
+
}
|
137
|
+
|
138
|
+
// 否则返回原始属性
|
139
|
+
return (target as any)[prop];
|
140
|
+
},
|
139
141
|
};
|
140
142
|
|
141
143
|
/**
|
@@ -143,80 +145,77 @@ const langEntryHandler: ProxyHandler<LangEntry> = {
|
|
143
145
|
* 可以直接通过静态方法创建和配置语言条目
|
144
146
|
*/
|
145
147
|
export class LangPackage {
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
return new Proxy(new LangEntry().set(lang, text), langEntryHandler);
|
221
|
-
}
|
222
|
-
}
|
148
|
+
/**
|
149
|
+
* 创建一个新的语言条目
|
150
|
+
*/
|
151
|
+
static make(): LangEntry {
|
152
|
+
return new Proxy(new LangEntry(), langEntryHandler);
|
153
|
+
}
|
154
|
+
|
155
|
+
/**
|
156
|
+
* 从对象创建语言条目
|
157
|
+
* @param obj 包含语言翻译的对象
|
158
|
+
*/
|
159
|
+
static from(obj: Record<string, string>): LangEntry {
|
160
|
+
const entry = new LangEntry();
|
161
|
+
Object.entries(obj).forEach(([lang, text]) => {
|
162
|
+
entry.set(lang, text);
|
163
|
+
});
|
164
|
+
return new Proxy(entry, langEntryHandler);
|
165
|
+
}
|
166
|
+
|
167
|
+
/**
|
168
|
+
* 创建只包含中文和英文的语言条目
|
169
|
+
* @param zh 中文文本
|
170
|
+
* @param en 英文文本
|
171
|
+
*/
|
172
|
+
static zhEn(zh: string, en: string): LangEntry {
|
173
|
+
return new Proxy(new LangEntry().setZh(zh).setEn(en), langEntryHandler);
|
174
|
+
}
|
175
|
+
|
176
|
+
/**
|
177
|
+
* 创建所有语言都使用相同文本的语言条目
|
178
|
+
* 适用于品牌名、产品名等不需要翻译的文本
|
179
|
+
* @param text 所有语言共用的文本
|
180
|
+
*/
|
181
|
+
static common(text: string): LangEntry {
|
182
|
+
return new Proxy(new LangEntry().setAll(text), langEntryHandler);
|
183
|
+
}
|
184
|
+
|
185
|
+
/**
|
186
|
+
* 设置中文文本
|
187
|
+
* 快捷方法,直接返回一个新的LangEntry实例
|
188
|
+
* @param text 中文文本
|
189
|
+
*/
|
190
|
+
static setZh(text: string): LangEntry {
|
191
|
+
return new Proxy(new LangEntry().setZh(text), langEntryHandler);
|
192
|
+
}
|
193
|
+
|
194
|
+
/**
|
195
|
+
* 设置英文文本
|
196
|
+
* 快捷方法,直接返回一个新的LangEntry实例
|
197
|
+
* @param text 英文文本
|
198
|
+
*/
|
199
|
+
static setEn(text: string): LangEntry {
|
200
|
+
return new Proxy(new LangEntry().setEn(text), langEntryHandler);
|
201
|
+
}
|
202
|
+
|
203
|
+
/**
|
204
|
+
* 设置日文文本
|
205
|
+
* 快捷方法,直接返回一个新的LangEntry实例
|
206
|
+
* @param text 日文文本
|
207
|
+
*/
|
208
|
+
static setJa(text: string): LangEntry {
|
209
|
+
return new Proxy(new LangEntry().setJa(text), langEntryHandler);
|
210
|
+
}
|
211
|
+
|
212
|
+
/**
|
213
|
+
* 设置任意语言的文本
|
214
|
+
* 快捷方法,直接返回一个新的LangEntry实例
|
215
|
+
* @param lang 语言代码
|
216
|
+
* @param text 文本内容
|
217
|
+
*/
|
218
|
+
static set(lang: string, text: string): LangEntry {
|
219
|
+
return new Proxy(new LangEntry().set(lang, text), langEntryHandler);
|
220
|
+
}
|
221
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@coffic/cosy-ui",
|
3
|
-
"version": "0.5.
|
3
|
+
"version": "0.5.14",
|
4
4
|
"description": "An astro component library",
|
5
5
|
"author": {
|
6
6
|
"name": "nookery",
|
@@ -59,10 +59,10 @@
|
|
59
59
|
"@types/eslint": "^9.6.1",
|
60
60
|
"@types/fs-extra": "^11.0.4",
|
61
61
|
"@types/mocha": "^10.0.10",
|
62
|
-
"@types/node": "^22.15.
|
62
|
+
"@types/node": "^22.15.17",
|
63
63
|
"@types/react": "^19.1.3",
|
64
64
|
"@typescript-eslint/parser": "^8.32.0",
|
65
|
-
"astro": "^5.7.
|
65
|
+
"astro": "^5.7.12",
|
66
66
|
"chai": "^4.5.0",
|
67
67
|
"daisyui": "^5.0.35",
|
68
68
|
"eslint": "^9.26.0",
|