@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 CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![English](https://img.shields.io/badge/English-violet)](README.md)
4
4
  [![简体中文](https://img.shields.io/badge/中文文档-gray)](README-zh.md)
5
+ [![DEV](https://img.shields.io/badge/DEV-gray)](README-dev.md)
5
6
  [![NPM](https://img.shields.io/badge/NPM-orange)](https://www.npmjs.com/package/@coffic/cosy-ui)
6
7
  [![Coffic](https://img.shields.io/badge/Coffic-green)](https://coffic.cn)
7
8
  [![Maintainer](https://img.shields.io/badge/Maintainer-blue)](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,11 @@
1
+ import { glob } from 'astro/loaders';
2
+ import { defineCollection } from 'astro:content';
3
+
4
+ export const makeCourseCollection = (base: string) => {
5
+ return defineCollection({
6
+ loader: glob({
7
+ pattern: '**/*.{md,mdx}',
8
+ base,
9
+ }),
10
+ });
11
+ };
@@ -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, index: number) => (
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>
@@ -80,9 +80,6 @@ interface Props {
80
80
 
81
81
  const { title, subtitle, imageUrl, href, class: className = '' } = Astro.props;
82
82
 
83
- // 定义动画的CSS类
84
- const fadeInAnimation = 'cosy:animate-fadeIn';
85
-
86
83
  // 定义卡片的CSS类
87
84
  const cardClasses = [
88
85
  'cosy:bg-base-100',
@@ -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, lang = 'plaintext', title, showLineNumbers = true } = Astro.props;
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
- * @default "24px"
6
- */
7
- size?: string;
8
- /**
9
- * 图标的颜色
10
- * @default "currentColor"
11
- */
12
- color?: string;
13
- /**
14
- * 自定义类名
15
- */
16
- class?: string;
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 = '', slot } = Astro.props;
19
+ const { size = '24px', color = 'currentColor', class: className = '' } = Astro.props;
24
20
  ---
25
21
 
26
- <svg
27
- xmlns="http://www.w3.org/2000/svg"
28
- width={size}
29
- height={size}
30
- viewBox="0 0 24 24"
31
- fill="none"
32
- stroke={color}
33
- stroke-width="2"
34
- stroke-linecap="round"
35
- stroke-linejoin="round"
36
- class={className}
37
- >
38
- <circle cx="11" cy="11" r="8" />
39
- <line x1="21" y1="21" x2="16.65" y2="16.65" />
40
- </svg>
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
- * @default "24px"
6
- */
7
- size?: string;
8
- /**
9
- * 图标的颜色
10
- * @default "currentColor"
11
- */
12
- color?: string;
13
- /**
14
- * 自定义类名
15
- */
16
- class?: string;
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 = '', slot } = Astro.props;
19
+ const { size = '24px', color = 'currentColor', class: className = '' } = Astro.props;
24
20
  ---
25
21
 
26
- <svg
27
- xmlns="http://www.w3.org/2000/svg"
28
- width={size}
29
- height={size}
30
- viewBox="0 0 24 24"
31
- fill="none"
32
- stroke={color}
33
- stroke-width="2"
34
- stroke-linecap="round"
35
- stroke-linejoin="round"
36
- class={className}
37
- >
38
- <path d="M12 2v2" />
39
- <path d="M2 12h2" />
40
- <path d="M20 12h2" />
41
- <path d="M4.93 4.93l1.41 1.41" />
42
- <path d="M17.66 4.93l-1.41 1.41" />
43
- <path d="M12 19a4 4 0 100-8 4 4 0 000 8z" />
44
- <path d="M12 15a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
45
- </svg>
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 { MetaProps } from '../../index';
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="/favicon.png" />
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 define:vars={{ selector, maxDepth, tocId, containerSelector, minHeadings, langInfo }}>
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
  // 使用指定的容器选择器查找内容容器
@@ -97,7 +97,7 @@
97
97
 
98
98
  import '../../app.css';
99
99
 
100
- interface Props {
100
+ export interface Props {
101
101
  as?: string;
102
102
  size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
103
103
  weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';
@@ -1,4 +1,4 @@
1
- import { SidebarItem } from './SidebarItem';
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<SidebarItem[]> {
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 SidebarItem({
52
- label: sibling.getTitle(),
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<SidebarItem> {
65
- return new SidebarItem({
66
- label: this.getTitle(),
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<SidebarItem> {
76
- return new SidebarItem({
77
- label: '了解我们',
75
+ async getTopSidebarItem(): Promise<SidebarItemEntity> {
76
+ return new SidebarItemEntity({
77
+ text: '了解我们',
78
78
  items: await this.getSiblingSidebarItems(),
79
79
  link: '',
80
80
  });
@@ -1,5 +1,5 @@
1
1
  import blogDB from '../database/BlogDB';
2
- import { SidebarItem } from './SidebarItem';
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): SidebarItem {
18
- return new SidebarItem({
19
- label: this.name,
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<SidebarItem> {
31
+ static async makeRootSidebarItem(lang: string): Promise<SidebarItemEntity> {
32
32
  const tags = await blogDB.getTagsByLang(lang);
33
33
 
34
- return new SidebarItem({
35
- label: 'Tags',
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
- 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;
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
- get(target: LangEntry, prop: string | symbol): any {
129
- // 如果是字符串属性并且不是LangEntry的方法,则尝试作为语言代码获取翻译
130
- if (typeof prop === 'string' &&
131
- !(prop in Object.getPrototypeOf(target)) &&
132
- prop !== 'translations') {
133
- return target.get(prop);
134
- }
135
-
136
- // 否则返回原始属性
137
- return (target as any)[prop];
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
- private static _instance = new Proxy(new LangEntry(), langEntryHandler);
148
-
149
- /**
150
- * 创建一个新的语言条目
151
- */
152
- static make(): LangEntry {
153
- return new Proxy(new LangEntry(), langEntryHandler);
154
- }
155
-
156
- /**
157
- * 从对象创建语言条目
158
- * @param obj 包含语言翻译的对象
159
- */
160
- static from(obj: Record<string, string>): LangEntry {
161
- const entry = new LangEntry();
162
- Object.entries(obj).forEach(([lang, text]) => {
163
- entry.set(lang, text);
164
- });
165
- return new Proxy(entry, langEntryHandler);
166
- }
167
-
168
- /**
169
- * 创建只包含中文和英文的语言条目
170
- * @param zh 中文文本
171
- * @param en 英文文本
172
- */
173
- static zhEn(zh: string, en: string): LangEntry {
174
- return new Proxy(new LangEntry().setZh(zh).setEn(en), langEntryHandler);
175
- }
176
-
177
- /**
178
- * 创建所有语言都使用相同文本的语言条目
179
- * 适用于品牌名、产品名等不需要翻译的文本
180
- * @param text 所有语言共用的文本
181
- */
182
- static common(text: string): LangEntry {
183
- return new Proxy(new LangEntry().setAll(text), langEntryHandler);
184
- }
185
-
186
- /**
187
- * 设置中文文本
188
- * 快捷方法,直接返回一个新的LangEntry实例
189
- * @param text 中文文本
190
- */
191
- static setZh(text: string): LangEntry {
192
- return new Proxy(new LangEntry().setZh(text), langEntryHandler);
193
- }
194
-
195
- /**
196
- * 设置英文文本
197
- * 快捷方法,直接返回一个新的LangEntry实例
198
- * @param text 英文文本
199
- */
200
- static setEn(text: string): LangEntry {
201
- return new Proxy(new LangEntry().setEn(text), langEntryHandler);
202
- }
203
-
204
- /**
205
- * 设置日文文本
206
- * 快捷方法,直接返回一个新的LangEntry实例
207
- * @param text 日文文本
208
- */
209
- static setJa(text: string): LangEntry {
210
- return new Proxy(new LangEntry().setJa(text), langEntryHandler);
211
- }
212
-
213
- /**
214
- * 设置任意语言的文本
215
- * 快捷方法,直接返回一个新的LangEntry实例
216
- * @param lang 语言代码
217
- * @param text 文本内容
218
- */
219
- static set(lang: string, text: string): LangEntry {
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.12",
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.16",
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.11",
65
+ "astro": "^5.7.12",
66
66
  "chai": "^4.5.0",
67
67
  "daisyui": "^5.0.35",
68
68
  "eslint": "^9.26.0",