@coffic/cosy-ui 0.8.11 → 0.8.13
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/app.css +1 -1
- package/dist/index-astro.ts +18 -10
- package/dist/{src-astro → src}/utils/language.ts +1 -1
- package/dist/src/utils/link.ts +250 -0
- package/dist/{src-astro → src}/utils/path.ts +1 -1
- package/dist/src-astro/article/index.ts +1 -1
- package/dist/src-astro/assets/iconData.ts +5 -0
- package/dist/src-astro/banner/index.ts +1 -1
- package/dist/src-astro/code-container/CodeContainer.astro +6 -91
- package/dist/src-astro/confirm-dialog/ConfirmDialog.astro +119 -0
- package/dist/src-astro/confirm-dialog/index.ts +2 -0
- package/dist/src-astro/confirm-dialog/types.ts +47 -0
- package/dist/src-astro/cosy.ts +1 -1
- package/dist/src-astro/database/index.ts +3 -0
- package/dist/src-astro/entities/BlogDoc.ts +1 -1
- package/dist/src-astro/entities/CourseDoc.ts +1 -1
- package/dist/src-astro/entities/ExperimentDoc.ts +1 -1
- package/dist/src-astro/entities/LessonDoc.ts +1 -1
- package/dist/src-astro/entities/MetaDoc.ts +1 -1
- package/dist/src-astro/entities/Tag.ts +1 -1
- package/dist/src-astro/errors/403.astro +1 -1
- package/dist/src-astro/errors/404.astro +1 -1
- package/dist/src-astro/errors/500.astro +1 -1
- package/dist/src-astro/errors/503.astro +1 -1
- package/dist/src-astro/flex/index.ts +1 -1
- package/dist/src-astro/footer/Footer.astro +1 -1
- package/dist/src-astro/grid/index.ts +1 -1
- package/dist/src-astro/heading/index.ts +1 -1
- package/dist/src-astro/icons/LogOut.astro +28 -0
- package/dist/src-astro/icons/index.ts +1 -0
- package/dist/src-astro/image/index.ts +1 -1
- package/dist/src-astro/language-switcher/index.ts +1 -1
- package/dist/src-astro/layout-basic/index.ts +1 -1
- package/dist/src-astro/layout-dashboard/DashboardLayout.astro +156 -23
- package/dist/src-astro/layout-dashboard/DashboardSidebar.astro +76 -63
- package/dist/src-astro/layout-dashboard/DashboardTopNavbar.astro +47 -15
- package/dist/src-astro/layout-dashboard/tools.ts +158 -0
- package/dist/src-astro/layout-dashboard/types.ts +37 -184
- package/dist/src-astro/link/index.ts +1 -1
- package/dist/src-astro/login/Login.astro +251 -0
- package/dist/src-astro/login/index.ts +2 -0
- package/dist/src-astro/logout/Logout.astro +117 -0
- package/dist/src-astro/logout/index.ts +2 -0
- package/dist/src-astro/module/index.ts +1 -1
- package/dist/src-astro/nav-item/NavItems.astro +1 -1
- package/dist/src-astro/nav-item/index.ts +1 -1
- package/dist/src-astro/nav-section/index.ts +1 -1
- package/dist/src-astro/register/Register.astro +289 -0
- package/dist/src-astro/register/index.ts +2 -0
- package/dist/src-astro/sidebar/Sidebar.astro +1 -1
- package/dist/src-astro/sidebar/index.ts +1 -1
- package/dist/src-astro/sidebar-nav/SidebarNav.astro +1 -1
- package/dist/src-astro/sidebar-nav/index.ts +1 -1
- package/dist/src-astro/speak/index.ts +1 -1
- package/dist/src-astro/stack/index.ts +1 -1
- package/dist/src-astro/team-member/TeamMemberBasic.astro +1 -1
- package/dist/src-astro/team-member/TeamMemberCustomStyle.astro +1 -1
- package/dist/src-astro/team-member/TeamMemberGroup.astro +1 -1
- package/dist/src-astro/team-member/TeamMemberWithSocial.astro +1 -1
- package/dist/src-astro/team-member/index.ts +1 -1
- package/dist/src-astro/text/index.ts +1 -1
- package/dist/src-astro/theme-switcher/ThemeSwitcher.astro +1 -1
- package/dist/src-astro/theme-switcher/index.ts +1 -1
- package/dist/src-astro/toast/Toast.astro +114 -0
- package/dist/src-astro/toast/ToastContainer.astro +249 -0
- package/dist/src-astro/toast/index.ts +4 -0
- package/dist/src-astro/toast/types.ts +78 -0
- package/dist/src-astro/toc/TableOfContents.astro +2 -2
- package/dist/src-astro/toc/index.ts +1 -1
- package/dist/src-astro/types/nav.ts +26 -1
- package/dist/vue/utils/link.ts +238 -238
- package/package.json +1 -1
- package/dist/src-astro/utils/link.ts +0 -250
- /package/dist/{src-astro → src}/utils/component.ts +0 -0
- /package/dist/{src-astro → src}/utils/i18n.ts +0 -0
- /package/dist/{src-astro → src}/utils/image.ts +0 -0
- /package/dist/{src-astro → src}/utils/lang_entry.ts +0 -0
- /package/dist/{src-astro → src}/utils/lang_package.ts +0 -0
- /package/dist/{src-astro → src}/utils/logger.ts +0 -0
- /package/dist/{src-astro → src}/utils/social.ts +0 -0
- /package/dist/{src-astro → src}/utils/theme.ts +0 -0
- /package/dist/{src-astro → src}/utils/url.ts +0 -0
package/dist/index-astro.ts
CHANGED
@@ -24,12 +24,15 @@ export * from './src-astro/layout-basic';
|
|
24
24
|
export * from './src-astro/layout-basic/BaseLayout.astro';
|
25
25
|
export * from './src-astro/layout-dashboard';
|
26
26
|
export * from './src-astro/link';
|
27
|
+
export * from './src-astro/login';
|
28
|
+
export * from './src-astro/logout';
|
27
29
|
export * from './src-astro/main';
|
28
30
|
export * from './src-astro/modal';
|
29
31
|
export * from './src-astro/module';
|
30
32
|
export * from './src-astro/nav-item';
|
31
33
|
export * from './src-astro/nav-section';
|
32
34
|
export * from './src-astro/products';
|
35
|
+
export * from './src-astro/register';
|
33
36
|
export * from './src-astro/section';
|
34
37
|
export * from './src-astro/sidebar';
|
35
38
|
export * from './src-astro/sidebar-nav';
|
@@ -39,6 +42,8 @@ export * from './src-astro/team-member';
|
|
39
42
|
export * from './src-astro/text';
|
40
43
|
export * from './src-astro/theme-switcher';
|
41
44
|
export * from './src-astro/toc';
|
45
|
+
export * from './src-astro/toast';
|
46
|
+
export * from './src-astro/confirm-dialog';
|
42
47
|
|
43
48
|
// 类型定义 (按字母顺序)
|
44
49
|
export * from './src-astro/types/article';
|
@@ -72,15 +77,18 @@ export * from './src-astro/database/LessonDB';
|
|
72
77
|
export * from './src-astro/database/MetaDB';
|
73
78
|
|
74
79
|
// 工具类型
|
75
|
-
export type { ImageProvider, ImageOptions } from './src
|
76
|
-
export * from './src
|
77
|
-
export * from './src
|
78
|
-
export * from './src
|
79
|
-
export * from './src
|
80
|
-
export * from './src
|
81
|
-
export * from './src
|
82
|
-
export * from './src
|
83
|
-
export * from './src
|
80
|
+
export type { ImageProvider, ImageOptions } from './src/utils/image';
|
81
|
+
export * from './src/utils/image';
|
82
|
+
export * from './src/utils/i18n';
|
83
|
+
export * from './src/utils/path';
|
84
|
+
export * from './src/utils/url';
|
85
|
+
export * from './src/utils/language';
|
86
|
+
export * from './src/utils/lang_package';
|
87
|
+
export * from './src/utils/logger';
|
88
|
+
export * from './src/utils/link';
|
84
89
|
|
85
90
|
// 图标组件
|
86
|
-
export * from './src-astro/icons';
|
91
|
+
export * from './src-astro/icons';
|
92
|
+
|
93
|
+
// 数据库
|
94
|
+
export * from './src-astro/database/index';
|
@@ -0,0 +1,250 @@
|
|
1
|
+
import { cosyLogger } from '../../src-astro/cosy';
|
2
|
+
|
3
|
+
export class LinkUtil {
|
4
|
+
// 从 astro.config.ts 中获取基础路径
|
5
|
+
static getBaseUrl = (): string => {
|
6
|
+
return import.meta.env.BASE_URL;
|
7
|
+
};
|
8
|
+
|
9
|
+
// 生成带基础路径的完整 URL
|
10
|
+
static createUrl = (path: string): string => {
|
11
|
+
const baseUrl = LinkUtil.getBaseUrl();
|
12
|
+
// 如果路径以 '/' 开头,去除开头的 '/'
|
13
|
+
if (path.startsWith('/')) {
|
14
|
+
path = path.substring(1);
|
15
|
+
}
|
16
|
+
|
17
|
+
return `${baseUrl}${path}`;
|
18
|
+
};
|
19
|
+
|
20
|
+
/**
|
21
|
+
* 规范化语言代码
|
22
|
+
* @param lang - 语言代码
|
23
|
+
* @returns 规范化后的语言代码
|
24
|
+
*/
|
25
|
+
static normalizeLanguage(lang: string): string {
|
26
|
+
const normalizedLang = lang.toLowerCase().replace('zh-CN', 'zh-cn');
|
27
|
+
if (normalizedLang.length == 0) {
|
28
|
+
console.error('lang is empty');
|
29
|
+
return 'en';
|
30
|
+
}
|
31
|
+
return normalizedLang;
|
32
|
+
}
|
33
|
+
|
34
|
+
static getHomeLink(lang: string): string {
|
35
|
+
return `${this.getBaseUrl}/${lang}`;
|
36
|
+
}
|
37
|
+
|
38
|
+
static getLessonsLink(lang: string): string {
|
39
|
+
return `/${lang}/lessons`;
|
40
|
+
}
|
41
|
+
|
42
|
+
static getExperimentsLink(lang: string): string {
|
43
|
+
return `/${lang}/experiments`;
|
44
|
+
}
|
45
|
+
|
46
|
+
static getExperimentLink(lang: string, experimentId: string): string {
|
47
|
+
if (experimentId.endsWith(lang)) {
|
48
|
+
return `/${lang}/experiments/${experimentId.replace(`${lang}`, '')}`;
|
49
|
+
} else {
|
50
|
+
const idWithoutLang = experimentId.replace(`${lang}/`, '');
|
51
|
+
return `/${lang}/experiments/${idWithoutLang}`;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
static getCoursesLink(lang: string): string {
|
56
|
+
return `/${lang}/courses`;
|
57
|
+
}
|
58
|
+
|
59
|
+
static getBlogsLink(lang: string): string {
|
60
|
+
return `/${lang}/blogs`;
|
61
|
+
}
|
62
|
+
|
63
|
+
static getLessonLink(lang: string, lessonId: string): string {
|
64
|
+
if (lessonId.endsWith(lang)) {
|
65
|
+
return `${this.getBaseUrl()}${lang}/lessons/${lessonId.replace(`${lang}`, '')}`;
|
66
|
+
} else {
|
67
|
+
const idWithoutLang = lessonId.replace(`${lang}/`, '');
|
68
|
+
return `${this.getBaseUrl()}${lang}/lessons/${idWithoutLang}`;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
static getTagLink(lang: string, tagName: string): string {
|
73
|
+
return `/${lang}/blogs/tag/${tagName}`;
|
74
|
+
}
|
75
|
+
|
76
|
+
static getBlogLink(blogId: string, lang: string): string {
|
77
|
+
const debug = false;
|
78
|
+
const blogIdWithoutLang = blogId.replace(`${lang}/`, '');
|
79
|
+
|
80
|
+
if (debug) {
|
81
|
+
cosyLogger.info(`获取博客文档链接,博客文档ID: ${blogId}`);
|
82
|
+
}
|
83
|
+
|
84
|
+
return `/${lang}/blogs/${blogIdWithoutLang}`;
|
85
|
+
}
|
86
|
+
|
87
|
+
static getCourseLink(courseId: string): string {
|
88
|
+
const debug = false;
|
89
|
+
const lang = courseId.split('/')[0];
|
90
|
+
const courseIdWithoutLang = courseId.replace(`${lang}/`, '');
|
91
|
+
|
92
|
+
if (debug) {
|
93
|
+
cosyLogger.info(`获取课程文档链接,课程文档ID: ${courseId}`);
|
94
|
+
}
|
95
|
+
|
96
|
+
return LinkUtil.createUrl(`/${lang}/courses/${courseIdWithoutLang}`);
|
97
|
+
}
|
98
|
+
|
99
|
+
static getMetaLink(lang: string, slug: string): string {
|
100
|
+
return `/${this.normalizeLanguage(lang)}/meta/${slug}`;
|
101
|
+
}
|
102
|
+
|
103
|
+
static getSigninLink(lang: string): string {
|
104
|
+
return `/${this.normalizeLanguage(lang)}/signin`;
|
105
|
+
}
|
106
|
+
|
107
|
+
static getAuthCallbackCookieLink(lang: string): string {
|
108
|
+
return `/${this.normalizeLanguage(lang)}/auth/callback_cookie`;
|
109
|
+
}
|
110
|
+
|
111
|
+
static getAuthCallbackTokenLink(lang: string): string {
|
112
|
+
return `/${this.normalizeLanguage(lang)}/auth/callback_token`;
|
113
|
+
}
|
114
|
+
|
115
|
+
static getAuthAccountLink(lang: string): string {
|
116
|
+
return `/${this.normalizeLanguage(lang)}/auth/account`;
|
117
|
+
}
|
118
|
+
|
119
|
+
static getDashboardUrl(lang: string): string {
|
120
|
+
return `/${this.normalizeLanguage(lang)}/auth/dashboard`;
|
121
|
+
}
|
122
|
+
|
123
|
+
static getAuthErrorLink(lang: string): string {
|
124
|
+
return `/${this.normalizeLanguage(lang)}/auth/error`;
|
125
|
+
}
|
126
|
+
|
127
|
+
static getPrivacyLink(lang: string): string {
|
128
|
+
return this.getMetaLink(lang, 'privacy');
|
129
|
+
}
|
130
|
+
|
131
|
+
static getTermsLink(lang: string): string {
|
132
|
+
return this.getMetaLink(lang, 'terms');
|
133
|
+
}
|
134
|
+
|
135
|
+
static getAboutLink(lang: string): string {
|
136
|
+
return this.getMetaLink(lang, 'about');
|
137
|
+
}
|
138
|
+
|
139
|
+
/**
|
140
|
+
* 根据ID生成链接
|
141
|
+
*
|
142
|
+
* 该函数根据文档ID生成对应的链接路径。
|
143
|
+
*
|
144
|
+
* @param {string} id - 文档ID, 例如 'courses/zh-cn/supervisor/index.md'
|
145
|
+
* @returns {string} 返回生成的链接路径
|
146
|
+
* @example
|
147
|
+
* // 例如:
|
148
|
+
* // id=courses/zh-cn/supervisor/index.md,则返回/zh-cn/courses/supervisor
|
149
|
+
* // id=courses/en/supervisor/index.md,则返回/en/courses/supervisor
|
150
|
+
*/
|
151
|
+
static getLink(id: string): string {
|
152
|
+
const category = id.split('/')[0];
|
153
|
+
const lang = id.split('/')[1];
|
154
|
+
const path = id.split('/').slice(2).join('/');
|
155
|
+
|
156
|
+
const link = `/${lang}/${category}/${path}`;
|
157
|
+
return link.replace(/\/+/g, '/');
|
158
|
+
}
|
159
|
+
|
160
|
+
/**
|
161
|
+
* 根据分类生成顶级链接
|
162
|
+
*
|
163
|
+
* @param {string} category - 分类名称
|
164
|
+
* @param {string} lang - 语言代码,例如 'zh-cn', 'en'
|
165
|
+
* @returns {string} 返回生成的顶级链接路径
|
166
|
+
* @example
|
167
|
+
* // 例如:
|
168
|
+
* // category=courses, lang=zh-cn,则返回/zh-cn/courses
|
169
|
+
* // category=courses, lang=en,则返回/en/courses
|
170
|
+
*/
|
171
|
+
static getTopLevelLink(category: string, lang: string): string {
|
172
|
+
return `/${lang}/${category}`;
|
173
|
+
}
|
174
|
+
|
175
|
+
/**
|
176
|
+
* 处理首页重定向
|
177
|
+
* @param locale - 语言代码
|
178
|
+
* @returns 规范化的语言代码
|
179
|
+
*/
|
180
|
+
static homeRedirect(locale: string): string {
|
181
|
+
return locale || 'en';
|
182
|
+
}
|
183
|
+
|
184
|
+
/**
|
185
|
+
* 检查是否为首页路径
|
186
|
+
* @param pathname - 路径
|
187
|
+
* @returns 是否为首页
|
188
|
+
*/
|
189
|
+
static isHomePath(pathname: string): boolean {
|
190
|
+
return pathname === '/' || pathname === '';
|
191
|
+
}
|
192
|
+
|
193
|
+
static isHomeLink(path: string, lang: string): boolean {
|
194
|
+
return path === `/${lang}` || path === `/${lang}/`;
|
195
|
+
}
|
196
|
+
|
197
|
+
static isLessonsLink(path: string, lang: string): boolean {
|
198
|
+
return (
|
199
|
+
path === `/${lang}/lessons` ||
|
200
|
+
path === `/${lang}/lessons/` ||
|
201
|
+
path.startsWith(`/${lang}/lessons/`)
|
202
|
+
);
|
203
|
+
}
|
204
|
+
|
205
|
+
static isExperimentsLink(path: string, lang: string): boolean {
|
206
|
+
return (
|
207
|
+
path === `/${lang}/experiments` ||
|
208
|
+
path === `/${lang}/experiments/` ||
|
209
|
+
path.startsWith(`/${lang}/experiments/`)
|
210
|
+
);
|
211
|
+
}
|
212
|
+
|
213
|
+
static isCoursesLink(path: string, lang: string): boolean {
|
214
|
+
return (
|
215
|
+
path === `/${lang}/courses` ||
|
216
|
+
path === `/${lang}/courses/` ||
|
217
|
+
path.startsWith(`/${lang}/courses/`)
|
218
|
+
);
|
219
|
+
}
|
220
|
+
|
221
|
+
static isBlogsLink(path: string, lang: string): boolean {
|
222
|
+
return (
|
223
|
+
path === `/${lang}/blogs` ||
|
224
|
+
path === `/${lang}/blogs/` ||
|
225
|
+
path.startsWith(`/${lang}/blogs/`)
|
226
|
+
);
|
227
|
+
}
|
228
|
+
|
229
|
+
static getOAuthSuccessLink(currentOrigin: string): string {
|
230
|
+
return `${currentOrigin}/api/callback_success`;
|
231
|
+
}
|
232
|
+
|
233
|
+
static getOAuthErrorLink(currentOrigin: string): string {
|
234
|
+
return `${currentOrigin}/api/callback_error`;
|
235
|
+
}
|
236
|
+
|
237
|
+
static getLoginLink(currentOrigin: string): string {
|
238
|
+
return `${currentOrigin}/api/login`;
|
239
|
+
}
|
240
|
+
|
241
|
+
static getActiveLink(currentLink: string, links: string[]): string {
|
242
|
+
let activeLink = '';
|
243
|
+
for (const link of links) {
|
244
|
+
if (currentLink.startsWith(link) && link.length > activeLink.length) {
|
245
|
+
activeLink = link;
|
246
|
+
}
|
247
|
+
}
|
248
|
+
return activeLink;
|
249
|
+
}
|
250
|
+
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import Article from './Article.astro';
|
2
2
|
import ArticleBasic from './ArticleBasic.astro';
|
3
3
|
import BasicSourceCode from './ArticleBasic.astro?raw';
|
4
|
-
import { extractSimpleExample } from '
|
4
|
+
import { extractSimpleExample } from '../../src/utils/component';
|
5
5
|
|
6
6
|
export { Article, ArticleBasic };
|
7
7
|
|
@@ -200,6 +200,11 @@ export const iconData: Record<string, IconData> = {
|
|
200
200
|
path: 'M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2m2 4h10a2 2 0 002-2v-6a2 2 0 00-2-2H9a2 2 0 00-2 2v6a2 2 0 002 2zm7-5a2 2 0 11-4 0 2 2 0 014 0z',
|
201
201
|
},
|
202
202
|
|
203
|
+
// 退出登录图标
|
204
|
+
logOut: {
|
205
|
+
path: 'M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4m7 14l5-5-5-5m5 5H9',
|
206
|
+
},
|
207
|
+
|
203
208
|
// 报告图标
|
204
209
|
report: {
|
205
210
|
path: 'M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z',
|
@@ -21,7 +21,7 @@ import CustomStyleSourceCode from './BannerCustomStyle.astro?raw';
|
|
21
21
|
import FadeInSourceCode from './BannerFadeIn.astro?raw';
|
22
22
|
import SlideUpSourceCode from './BannerSlideUp.astro?raw';
|
23
23
|
import AllAnimationsSourceCode from './BannerAllAnimations.astro?raw';
|
24
|
-
import { extractSimpleExample } from '
|
24
|
+
import { extractSimpleExample } from '../../src/utils/component';
|
25
25
|
|
26
26
|
export {
|
27
27
|
Banner,
|
@@ -4,13 +4,12 @@
|
|
4
4
|
*
|
5
5
|
* @description
|
6
6
|
* 用于展示代码示例的容器组件,提供样式隔离功能防止内外样式相互影响。
|
7
|
-
*
|
7
|
+
* 支持样式重置模式。
|
8
8
|
* 使用时只需在默认slot中传入内容,并为每个示例设置对应的id (tab-1, tab-2等)
|
9
9
|
*
|
10
10
|
* @features
|
11
11
|
* - 样式隔离:防止外部样式影响内部组件展示
|
12
12
|
* - 样式重置:重置内部样式,避免样式冲突
|
13
|
-
* - iframe模式:完全隔离的预览环境
|
14
13
|
* - 代码预览切换:支持预览和代码视图切换
|
15
14
|
* - 多标签页:支持多个示例的标签页展示
|
16
15
|
*
|
@@ -26,13 +25,6 @@
|
|
26
25
|
* </div>
|
27
26
|
* </CodeContainer>
|
28
27
|
*
|
29
|
-
* <!-- 使用iframe完全隔离 -->
|
30
|
-
* <CodeContainer codes={[code]} useIframe={true}>
|
31
|
-
* <div id="tab-1">
|
32
|
-
* <SomeComponent />
|
33
|
-
* </div>
|
34
|
-
* </CodeContainer>
|
35
|
-
*
|
36
28
|
* <!-- 禁用样式重置 -->
|
37
29
|
* <CodeContainer codes={[code]} resetStyles={false}>
|
38
30
|
* <div id="tab-1">
|
@@ -58,11 +50,6 @@ interface Props {
|
|
58
50
|
* 每个示例对应的源代码
|
59
51
|
*/
|
60
52
|
codes: string[];
|
61
|
-
/**
|
62
|
-
* 是否使用iframe隔离内容
|
63
|
-
* @default false
|
64
|
-
*/
|
65
|
-
useIframe?: boolean;
|
66
53
|
/**
|
67
54
|
* 是否重置内部样式
|
68
55
|
* @default true
|
@@ -74,7 +61,6 @@ const {
|
|
74
61
|
titles = [],
|
75
62
|
descriptions = [],
|
76
63
|
codes,
|
77
|
-
useIframe = false,
|
78
64
|
resetStyles = true,
|
79
65
|
} = Astro.props;
|
80
66
|
---
|
@@ -132,22 +118,11 @@ const {
|
|
132
118
|
|
133
119
|
<div class="cosy:relative cosy:p-4 cosy:bg-gradient-to-br cosy:from-red-100 cosy:to-green-300 cosy:rounded-b">
|
134
120
|
<div class="cosy:block cosy:code-example-panel" data-panel="preview">
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
sandbox="allow-scripts allow-same-origin"
|
141
|
-
title={`示例预览 ${index + 1}`}
|
142
|
-
/>
|
143
|
-
</div>
|
144
|
-
) : (
|
145
|
-
<div
|
146
|
-
class={`cosy:code-preview-area ${resetStyles ? 'cosy:reset-styles' : ''}`}
|
147
|
-
data-preview-area={`tab-${index + 1}`}>
|
148
|
-
<slot />
|
149
|
-
</div>
|
150
|
-
)}
|
121
|
+
<div
|
122
|
+
class={`cosy:code-preview-area ${resetStyles ? 'cosy:reset-styles' : ''}`}
|
123
|
+
data-preview-area={`tab-${index + 1}`}>
|
124
|
+
<slot />
|
125
|
+
</div>
|
151
126
|
</div>
|
152
127
|
|
153
128
|
<div class="cosy:hidden cosy:code-example-panel" data-panel="code">
|
@@ -228,13 +203,6 @@ const {
|
|
228
203
|
margin-bottom: 0.25em;
|
229
204
|
}
|
230
205
|
|
231
|
-
/* iframe 隔离样式 */
|
232
|
-
[data-role='code-container'] iframe[data-preview-frame] {
|
233
|
-
background: white;
|
234
|
-
border: 1px solid #e5e7eb;
|
235
|
-
border-radius: 0.375rem;
|
236
|
-
}
|
237
|
-
|
238
206
|
/* 防止内部组件的样式泄漏到外部 */
|
239
207
|
[data-role='code-container'] .cosy\:code-preview-area {
|
240
208
|
position: relative;
|
@@ -255,62 +223,9 @@ const {
|
|
255
223
|
</style>
|
256
224
|
|
257
225
|
<script>
|
258
|
-
function initializeIframePreviews() {
|
259
|
-
const iframes = document.querySelectorAll('[data-preview-frame]');
|
260
|
-
|
261
|
-
iframes.forEach((iframe) => {
|
262
|
-
const container = iframe.closest('[data-role="code-container"]');
|
263
|
-
if (!container) return;
|
264
|
-
|
265
|
-
const frameId = iframe.getAttribute('data-preview-frame');
|
266
|
-
const contentElement = container.querySelector(`#${frameId}`);
|
267
|
-
|
268
|
-
if (contentElement) {
|
269
|
-
// 创建独立的HTML文档内容
|
270
|
-
const iframeElement = iframe as HTMLIFrameElement;
|
271
|
-
const iframeDoc =
|
272
|
-
iframeElement.contentDocument ||
|
273
|
-
iframeElement.contentWindow?.document;
|
274
|
-
if (iframeDoc) {
|
275
|
-
const htmlContent = `
|
276
|
-
<!DOCTYPE html>
|
277
|
-
<html>
|
278
|
-
<head>
|
279
|
-
<meta charset="UTF-8">
|
280
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
281
|
-
<title>示例预览</title>
|
282
|
-
<style>
|
283
|
-
/* 基础样式重置 */
|
284
|
-
* { margin: 0; padding: 0; box-sizing: border-box; }
|
285
|
-
body {
|
286
|
-
font-family: system-ui, -apple-system, sans-serif;
|
287
|
-
padding: 1rem;
|
288
|
-
background: white;
|
289
|
-
color: #374151;
|
290
|
-
line-height: 1.5;
|
291
|
-
}
|
292
|
-
</style>
|
293
|
-
</head>
|
294
|
-
<body>
|
295
|
-
${contentElement.innerHTML}
|
296
|
-
</body>
|
297
|
-
</html>
|
298
|
-
`;
|
299
|
-
|
300
|
-
iframeDoc.open();
|
301
|
-
iframeDoc.write(htmlContent);
|
302
|
-
iframeDoc.close();
|
303
|
-
}
|
304
|
-
}
|
305
|
-
});
|
306
|
-
}
|
307
|
-
|
308
226
|
function initializeCodeContainer() {
|
309
227
|
console.log('CodeContainer: 初始化代码容器');
|
310
228
|
|
311
|
-
// 初始化 iframe 预览
|
312
|
-
initializeIframePreviews();
|
313
|
-
|
314
229
|
// 示例切换功能
|
315
230
|
const exampleTabs = document.querySelectorAll(
|
316
231
|
'[role="tab"][data-tab^="tab-"]'
|
@@ -0,0 +1,119 @@
|
|
1
|
+
---
|
2
|
+
/**
|
3
|
+
* @component ConfirmDialog
|
4
|
+
*
|
5
|
+
* @description
|
6
|
+
* ConfirmDialog 组件用于显示确认对话框,支持自定义标题、消息内容和按钮文本。
|
7
|
+
* 它会覆盖在页面内容上方,并提供一个聚焦的交互环境。
|
8
|
+
*
|
9
|
+
* @design
|
10
|
+
* 设计理念:
|
11
|
+
* 1. 聚焦交互 - 通过遮罩层和动画效果引导用户注意力
|
12
|
+
* 2. 灵活布局 - 支持标题、内容和操作按钮的自定义
|
13
|
+
* 3. 可访问性 - 支持键盘导航和屏幕阅读器
|
14
|
+
* 4. 响应式设计 - 在不同屏幕尺寸下保持良好的用户体验
|
15
|
+
*
|
16
|
+
* @usage
|
17
|
+
* 基本用法:
|
18
|
+
* ```astro
|
19
|
+
* <ConfirmDialog
|
20
|
+
* id="delete-confirm"
|
21
|
+
* title="确认删除"
|
22
|
+
* message="您确定要删除这个项目吗?此操作无法撤销。"
|
23
|
+
* />
|
24
|
+
*
|
25
|
+
* <!-- 触发按钮 -->
|
26
|
+
* <button data-confirm-dialog-target="delete-confirm">删除</button>
|
27
|
+
* ```
|
28
|
+
*
|
29
|
+
* 自定义按钮文本:
|
30
|
+
* ```astro
|
31
|
+
* <ConfirmDialog
|
32
|
+
* id="save-confirm"
|
33
|
+
* title="保存更改"
|
34
|
+
* message="您确定要保存这些更改吗?"
|
35
|
+
* confirmText="保存"
|
36
|
+
* cancelText="取消"
|
37
|
+
* />
|
38
|
+
* ```
|
39
|
+
*/
|
40
|
+
|
41
|
+
import '../../style.ts';
|
42
|
+
import type { ConfirmDialogProps } from './types';
|
43
|
+
import { getConfirmDialogStyle } from './types';
|
44
|
+
|
45
|
+
const {
|
46
|
+
id,
|
47
|
+
title = '确认操作',
|
48
|
+
message,
|
49
|
+
cancelText = '取消',
|
50
|
+
confirmText = '确认',
|
51
|
+
class: className = '',
|
52
|
+
} = Astro.props as ConfirmDialogProps;
|
53
|
+
|
54
|
+
const style = getConfirmDialogStyle();
|
55
|
+
---
|
56
|
+
|
57
|
+
<dialog id={id} class:list={['cosy:modal', 'cosy:modal-middle', className]}>
|
58
|
+
<div
|
59
|
+
class:list={[
|
60
|
+
'cosy:modal-box',
|
61
|
+
'cosy:p-6',
|
62
|
+
'cosy:max-w-sm',
|
63
|
+
'cosy:rounded-lg',
|
64
|
+
'cosy:shadow-lg',
|
65
|
+
style.bg,
|
66
|
+
]}>
|
67
|
+
{
|
68
|
+
title && (
|
69
|
+
<h3 class:list={['cosy:text-lg', 'cosy:font-medium', style.text]}>
|
70
|
+
{title}
|
71
|
+
</h3>
|
72
|
+
)
|
73
|
+
}
|
74
|
+
<p class:list={['cosy:py-4', style.text]}>{message}</p>
|
75
|
+
|
76
|
+
<div class:list={['cosy:modal-action', 'cosy:gap-2']}>
|
77
|
+
<form method="dialog" class="cosy:flex cosy:gap-2">
|
78
|
+
<button class:list={[style.cancelBtn]}>{cancelText}</button>
|
79
|
+
<button
|
80
|
+
class:list={[style.confirmBtn]}
|
81
|
+
onclick={`window.handleConfirmDialog?.('${id}')`}
|
82
|
+
type="submit">{confirmText}</button
|
83
|
+
>
|
84
|
+
</form>
|
85
|
+
</div>
|
86
|
+
</div>
|
87
|
+
|
88
|
+
<form method="dialog" class="cosy:modal-backdrop">
|
89
|
+
<button>关闭</button>
|
90
|
+
</form>
|
91
|
+
</dialog>
|
92
|
+
|
93
|
+
<script is:inline define:vars={{ id }}>
|
94
|
+
// 为了方便使用,我们提供一些辅助方法
|
95
|
+
document.addEventListener('DOMContentLoaded', () => {
|
96
|
+
const dialog = document.getElementById(id);
|
97
|
+
if (!dialog) return;
|
98
|
+
|
99
|
+
// 为所有触发这个确认框的按钮添加点击事件
|
100
|
+
document
|
101
|
+
.querySelectorAll(`[data-confirm-dialog-target="${id}"]`)
|
102
|
+
.forEach((trigger) => {
|
103
|
+
trigger.addEventListener('click', () => {
|
104
|
+
dialog.showModal();
|
105
|
+
});
|
106
|
+
});
|
107
|
+
|
108
|
+
// 全局处理确认事件的方法
|
109
|
+
if (!window.handleConfirmDialog) {
|
110
|
+
window.handleConfirmDialog = (dialogId) => {
|
111
|
+
// 触发自定义事件
|
112
|
+
const event = new CustomEvent('confirm-dialog-confirm', {
|
113
|
+
detail: { dialogId },
|
114
|
+
});
|
115
|
+
document.dispatchEvent(event);
|
116
|
+
};
|
117
|
+
}
|
118
|
+
});
|
119
|
+
</script>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
export interface ConfirmDialogProps {
|
2
|
+
/**
|
3
|
+
* 对话框的唯一标识符
|
4
|
+
*/
|
5
|
+
id: string;
|
6
|
+
|
7
|
+
/**
|
8
|
+
* 对话框标题
|
9
|
+
*/
|
10
|
+
title?: string;
|
11
|
+
|
12
|
+
/**
|
13
|
+
* 对话框消息内容
|
14
|
+
*/
|
15
|
+
message: string;
|
16
|
+
|
17
|
+
/**
|
18
|
+
* 取消按钮文本
|
19
|
+
*/
|
20
|
+
cancelText?: string;
|
21
|
+
|
22
|
+
/**
|
23
|
+
* 确认按钮文本
|
24
|
+
*/
|
25
|
+
confirmText?: string;
|
26
|
+
|
27
|
+
/**
|
28
|
+
* 自定义类名
|
29
|
+
*/
|
30
|
+
class?: string;
|
31
|
+
}
|
32
|
+
|
33
|
+
export interface ConfirmDialogStyle {
|
34
|
+
bg: string;
|
35
|
+
border: string;
|
36
|
+
text: string;
|
37
|
+
confirmBtn: string;
|
38
|
+
cancelBtn: string;
|
39
|
+
}
|
40
|
+
|
41
|
+
export const getConfirmDialogStyle = (): ConfirmDialogStyle => ({
|
42
|
+
bg: 'cosy:bg-base-100',
|
43
|
+
border: 'cosy:border-base-300',
|
44
|
+
text: 'cosy:text-base-content',
|
45
|
+
confirmBtn: 'cosy:btn cosy:btn-primary',
|
46
|
+
cancelBtn: 'cosy:btn cosy:btn-ghost',
|
47
|
+
});
|
package/dist/src-astro/cosy.ts
CHANGED