@jet-w/astro-blog 0.2.1 → 0.2.3

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.
@@ -0,0 +1,485 @@
1
+ /**
2
+ * i18n Configuration Module
3
+ *
4
+ * Provides multi-language support configuration for the blog.
5
+ */
6
+
7
+ import type { NavigationItem, SiteConfig } from '../types';
8
+ import type { FooterConfig } from './footer';
9
+ import type { SidebarConfig } from './sidebar';
10
+
11
+ /**
12
+ * Locale definition
13
+ */
14
+ export interface Locale {
15
+ /** Language code (e.g., 'en', 'zh-CN', 'ja') */
16
+ code: string;
17
+ /** Display name (e.g., 'English', '中文') */
18
+ name: string;
19
+ /** HTML lang attribute value */
20
+ htmlLang: string;
21
+ /** Locale for Intl.DateTimeFormat */
22
+ dateLocale: string;
23
+ /** Text direction */
24
+ direction?: 'ltr' | 'rtl';
25
+ }
26
+
27
+ /**
28
+ * UI translation strings
29
+ */
30
+ export interface UITranslations {
31
+ // Navigation
32
+ home: string;
33
+ blog: string;
34
+ about: string;
35
+ search: string;
36
+
37
+ // Posts
38
+ posts: string;
39
+ postList: string;
40
+ noPostsFound: string;
41
+ readMore: string;
42
+ readingTime: string;
43
+ minuteRead: string;
44
+
45
+ // Tags & Categories
46
+ tags: string;
47
+ categories: string;
48
+ allTags: string;
49
+ allCategories: string;
50
+ taggedWith: string;
51
+ inCategory: string;
52
+
53
+ // Archives
54
+ archives: string;
55
+ postsInArchive: string;
56
+
57
+ // Sidebar
58
+ recentPosts: string;
59
+ popularTags: string;
60
+ friendLinks: string;
61
+ documentTree: string;
62
+
63
+ // Footer
64
+ quickLinks: string;
65
+ contact: string;
66
+
67
+ // Search
68
+ searchPlaceholder: string;
69
+ searchResults: string;
70
+ noResults: string;
71
+ searching: string;
72
+ searchArticles: string;
73
+ searchInAllArticles: string;
74
+ searchTips: string;
75
+ basicSearch: string;
76
+ advancedFeatures: string;
77
+ searchTipKeyword: string;
78
+ searchTipMixedLang: string;
79
+ searchTipCaseInsensitive: string;
80
+ searchTipRealtime: string;
81
+ searchTipFilter: string;
82
+ searchTipFuzzy: string;
83
+
84
+ // Hero section
85
+ browsePosts: string;
86
+ aboutMe: string;
87
+
88
+ // Pagination
89
+ previousPage: string;
90
+ nextPage: string;
91
+ page: string;
92
+ of: string;
93
+
94
+ // Article details
95
+ publishedOn: string;
96
+ updatedOn: string;
97
+ author: string;
98
+ tableOfContents: string;
99
+ readingProgress: string;
100
+ relatedPosts: string;
101
+ sharePost: string;
102
+ previousPost: string;
103
+ nextPost: string;
104
+
105
+ // Misc
106
+ backToTop: string;
107
+ copyCode: string;
108
+ copied: string;
109
+ expand: string;
110
+ collapse: string;
111
+ expandCode: string;
112
+ collapseCode: string;
113
+ lines: string;
114
+ viewMode: string;
115
+ cardView: string;
116
+ listView: string;
117
+ sortBy: string;
118
+ sortByDate: string;
119
+ sortByTitle: string;
120
+ filterByTag: string;
121
+ filterByCategory: string;
122
+ clearFilter: string;
123
+ allPosts: string;
124
+ draft: string;
125
+
126
+ // Slides
127
+ slides: string;
128
+ slidesList: string;
129
+
130
+ // RSS
131
+ rssFeed: string;
132
+
133
+ // Quick Navigation
134
+ quickNavigation: string;
135
+ timeline: string;
136
+ viewAllTimeline: string;
137
+ postsCount: string;
138
+ }
139
+
140
+ /**
141
+ * Locale-specific configuration
142
+ */
143
+ export interface LocaleConfig {
144
+ /** Site configuration overrides */
145
+ site?: Partial<SiteConfig>;
146
+ /** Navigation menu items */
147
+ menu?: NavigationItem[];
148
+ /** Footer configuration overrides */
149
+ footer?: Partial<FooterConfig>;
150
+ /** Sidebar configuration overrides */
151
+ sidebar?: Partial<SidebarConfig>;
152
+ /** UI translation overrides */
153
+ ui?: Partial<UITranslations>;
154
+ /** Content path prefix for filtering posts by locale (e.g., 'blog_docs_en' for English) */
155
+ contentPathPrefix?: string;
156
+ }
157
+
158
+ /**
159
+ * i18n routing configuration
160
+ */
161
+ export interface I18nRoutingConfig {
162
+ /** Whether to add prefix for default locale (e.g., /zh-CN/posts vs /posts) */
163
+ prefixDefaultLocale: boolean;
164
+ }
165
+
166
+ /**
167
+ * Complete i18n configuration
168
+ */
169
+ export interface I18nConfig {
170
+ /** Default locale code */
171
+ defaultLocale: string;
172
+ /** Available locales */
173
+ locales: Locale[];
174
+ /** Locale-specific configurations */
175
+ localeConfigs: Record<string, LocaleConfig>;
176
+ /** Routing configuration */
177
+ routing: I18nRoutingConfig;
178
+ }
179
+
180
+ /**
181
+ * Default Chinese (Simplified) UI translations
182
+ */
183
+ export const zhCNTranslations: UITranslations = {
184
+ // Navigation
185
+ home: '首页',
186
+ blog: '博客',
187
+ about: '关于',
188
+ search: '搜索',
189
+
190
+ // Posts
191
+ posts: '文章',
192
+ postList: '文章列表',
193
+ noPostsFound: '暂无文章',
194
+ readMore: '阅读更多',
195
+ readingTime: '阅读时间',
196
+ minuteRead: '分钟',
197
+
198
+ // Tags & Categories
199
+ tags: '标签',
200
+ categories: '分类',
201
+ allTags: '全部标签',
202
+ allCategories: '全部分类',
203
+ taggedWith: '标签',
204
+ inCategory: '分类',
205
+
206
+ // Archives
207
+ archives: '归档',
208
+ postsInArchive: '篇文章',
209
+
210
+ // Sidebar
211
+ recentPosts: '最新文章',
212
+ popularTags: '热门标签',
213
+ friendLinks: '友情链接',
214
+ documentTree: '文档目录',
215
+
216
+ // Footer
217
+ quickLinks: '快速链接',
218
+ contact: '联系方式',
219
+
220
+ // Search
221
+ searchPlaceholder: '搜索文章标题、内容、标签...',
222
+ searchResults: '搜索结果',
223
+ noResults: '没有找到相关结果',
224
+ searching: '搜索中...',
225
+ searchArticles: '搜索文章',
226
+ searchInAllArticles: '在所有文章中查找您感兴趣的内容',
227
+ searchTips: '搜索技巧',
228
+ basicSearch: '基础搜索',
229
+ advancedFeatures: '高级功能',
230
+ searchTipKeyword: '输入关键词搜索标题和内容',
231
+ searchTipMixedLang: '支持中英文混合搜索',
232
+ searchTipCaseInsensitive: '自动忽略大小写',
233
+ searchTipRealtime: '实时搜索建议',
234
+ searchTipFilter: '按标签和分类筛选',
235
+ searchTipFuzzy: '支持模糊匹配',
236
+
237
+ // Hero section
238
+ browsePosts: '浏览文章',
239
+ aboutMe: '关于我',
240
+
241
+ // Pagination
242
+ previousPage: '上一页',
243
+ nextPage: '下一页',
244
+ page: '第',
245
+ of: '页,共',
246
+
247
+ // Article details
248
+ publishedOn: '发布于',
249
+ updatedOn: '更新于',
250
+ author: '作者',
251
+ tableOfContents: '页面目录',
252
+ readingProgress: '阅读进度',
253
+ relatedPosts: '相关文章',
254
+ sharePost: '分享文章',
255
+ previousPost: '上一篇',
256
+ nextPost: '下一篇',
257
+
258
+ // Misc
259
+ backToTop: '回到顶部',
260
+ copyCode: '复制',
261
+ copied: '已复制',
262
+ expand: '展开',
263
+ collapse: '收起',
264
+ expandCode: '展开代码',
265
+ collapseCode: '收起代码',
266
+ lines: '行',
267
+ viewMode: '视图模式',
268
+ cardView: '卡片视图',
269
+ listView: '列表视图',
270
+ sortBy: '排序',
271
+ sortByDate: '按日期',
272
+ sortByTitle: '按标题',
273
+ filterByTag: '按标签筛选',
274
+ filterByCategory: '按分类筛选',
275
+ clearFilter: '清除筛选',
276
+ allPosts: '全部文章',
277
+ draft: '草稿',
278
+
279
+ // Slides
280
+ slides: '演示',
281
+ slidesList: '演示列表',
282
+
283
+ // RSS
284
+ rssFeed: 'RSS 订阅',
285
+
286
+ // Quick Navigation
287
+ quickNavigation: '快速导航',
288
+ timeline: '时间轴',
289
+ viewAllTimeline: '查看全部时间轴',
290
+ postsCount: '篇',
291
+ };
292
+
293
+ /**
294
+ * Default English UI translations
295
+ */
296
+ export const enTranslations: UITranslations = {
297
+ // Navigation
298
+ home: 'Home',
299
+ blog: 'Blog',
300
+ about: 'About',
301
+ search: 'Search',
302
+
303
+ // Posts
304
+ posts: 'Posts',
305
+ postList: 'All Posts',
306
+ noPostsFound: 'No posts found',
307
+ readMore: 'Read more',
308
+ readingTime: 'Reading time',
309
+ minuteRead: 'min',
310
+
311
+ // Tags & Categories
312
+ tags: 'Tags',
313
+ categories: 'Categories',
314
+ allTags: 'All Tags',
315
+ allCategories: 'All Categories',
316
+ taggedWith: 'Tagged with',
317
+ inCategory: 'In category',
318
+
319
+ // Archives
320
+ archives: 'Archives',
321
+ postsInArchive: 'posts',
322
+
323
+ // Sidebar
324
+ recentPosts: 'Recent Posts',
325
+ popularTags: 'Popular Tags',
326
+ friendLinks: 'Friend Links',
327
+ documentTree: 'Document Tree',
328
+
329
+ // Footer
330
+ quickLinks: 'Quick Links',
331
+ contact: 'Contact',
332
+
333
+ // Search
334
+ searchPlaceholder: 'Search posts, tags, content...',
335
+ searchResults: 'Search Results',
336
+ noResults: 'No results found',
337
+ searching: 'Searching...',
338
+ searchArticles: 'Search Articles',
339
+ searchInAllArticles: 'Find content that interests you in all articles',
340
+ searchTips: 'Search Tips',
341
+ basicSearch: 'Basic Search',
342
+ advancedFeatures: 'Advanced Features',
343
+ searchTipKeyword: 'Enter keywords to search titles and content',
344
+ searchTipMixedLang: 'Supports mixed language search',
345
+ searchTipCaseInsensitive: 'Case insensitive',
346
+ searchTipRealtime: 'Real-time search suggestions',
347
+ searchTipFilter: 'Filter by tags and categories',
348
+ searchTipFuzzy: 'Supports fuzzy matching',
349
+
350
+ // Hero section
351
+ browsePosts: 'Browse Posts',
352
+ aboutMe: 'About Me',
353
+
354
+ // Pagination
355
+ previousPage: 'Previous',
356
+ nextPage: 'Next',
357
+ page: 'Page',
358
+ of: 'of',
359
+
360
+ // Article details
361
+ publishedOn: 'Published on',
362
+ updatedOn: 'Updated on',
363
+ author: 'Author',
364
+ tableOfContents: 'Table of Contents',
365
+ readingProgress: 'Reading Progress',
366
+ relatedPosts: 'Related Posts',
367
+ sharePost: 'Share',
368
+ previousPost: 'Previous',
369
+ nextPost: 'Next',
370
+
371
+ // Misc
372
+ backToTop: 'Back to Top',
373
+ copyCode: 'Copy',
374
+ copied: 'Copied',
375
+ expand: 'Expand',
376
+ collapse: 'Collapse',
377
+ expandCode: 'Expand code',
378
+ collapseCode: 'Collapse code',
379
+ lines: 'lines',
380
+ viewMode: 'View Mode',
381
+ cardView: 'Card View',
382
+ listView: 'List View',
383
+ sortBy: 'Sort by',
384
+ sortByDate: 'Date',
385
+ sortByTitle: 'Title',
386
+ filterByTag: 'Filter by tag',
387
+ filterByCategory: 'Filter by category',
388
+ clearFilter: 'Clear filter',
389
+ allPosts: 'All Posts',
390
+ draft: 'Draft',
391
+
392
+ // Slides
393
+ slides: 'Slides',
394
+ slidesList: 'All Slides',
395
+
396
+ // RSS
397
+ rssFeed: 'RSS Feed',
398
+
399
+ // Quick Navigation
400
+ quickNavigation: 'Quick Navigation',
401
+ timeline: 'Timeline',
402
+ viewAllTimeline: 'View all timeline',
403
+ postsCount: 'posts',
404
+ };
405
+
406
+ /**
407
+ * Built-in translations for common languages
408
+ */
409
+ export const builtInTranslations: Record<string, UITranslations> = {
410
+ 'zh-CN': zhCNTranslations,
411
+ 'zh': zhCNTranslations,
412
+ 'en': enTranslations,
413
+ 'en-US': enTranslations,
414
+ 'en-GB': enTranslations,
415
+ };
416
+
417
+ /**
418
+ * Default locales
419
+ */
420
+ export const defaultLocales: Locale[] = [
421
+ {
422
+ code: 'zh-CN',
423
+ name: '中文',
424
+ htmlLang: 'zh-CN',
425
+ dateLocale: 'zh-CN',
426
+ direction: 'ltr',
427
+ },
428
+ ];
429
+
430
+ /**
431
+ * Default i18n configuration (Chinese only, backward compatible)
432
+ */
433
+ export const defaultI18nConfig: I18nConfig = {
434
+ defaultLocale: 'zh-CN',
435
+ locales: defaultLocales,
436
+ localeConfigs: {},
437
+ routing: {
438
+ prefixDefaultLocale: false,
439
+ },
440
+ };
441
+
442
+ /**
443
+ * Helper function to define i18n configuration with type safety
444
+ */
445
+ export function defineI18nConfig(config: Partial<I18nConfig>): I18nConfig {
446
+ return {
447
+ defaultLocale: config.defaultLocale || 'zh-CN',
448
+ locales: config.locales || defaultLocales,
449
+ localeConfigs: config.localeConfigs || {},
450
+ routing: {
451
+ prefixDefaultLocale: config.routing?.prefixDefaultLocale ?? false,
452
+ },
453
+ };
454
+ }
455
+
456
+ /**
457
+ * Get UI translations for a specific locale
458
+ * Falls back to built-in translations, then to English
459
+ */
460
+ export function getUITranslations(
461
+ locale: string,
462
+ config?: I18nConfig
463
+ ): UITranslations {
464
+ // Check locale-specific config first
465
+ const localeConfig = config?.localeConfigs?.[locale];
466
+ const customTranslations = localeConfig?.ui;
467
+
468
+ // Get built-in translations as base
469
+ const baseTranslations =
470
+ builtInTranslations[locale] ||
471
+ builtInTranslations[locale.split('-')[0]] ||
472
+ builtInTranslations['en'];
473
+
474
+ // Merge custom translations over base
475
+ if (customTranslations) {
476
+ return { ...baseTranslations, ...customTranslations };
477
+ }
478
+
479
+ return baseTranslations;
480
+ }
481
+
482
+ // Re-export for convenience
483
+ export type { NavigationItem, SiteConfig } from '../types';
484
+ export type { FooterConfig } from './footer';
485
+ export type { SidebarConfig } from './sidebar';
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 配置文件统一导出
3
+ */
4
+
5
+ export { siteConfig, defaultSiteConfig, defaultSEO, defineSiteConfig } from './site';
6
+ export { menu, defaultMenu, defineMenu } from './menu';
7
+ export { sidebarConfig, defaultSidebarConfig, defineSidebarConfig } from './sidebar';
8
+ export { defaultIcons, socialLinks, defaultSocialLinks, defineSocialLinks } from './social';
9
+ export { footerConfig, defaultFooterConfig, defineFooterConfig } from './footer';
10
+
11
+ // i18n exports
12
+ export {
13
+ defaultI18nConfig,
14
+ defineI18nConfig,
15
+ getUITranslations,
16
+ builtInTranslations,
17
+ zhCNTranslations,
18
+ enTranslations,
19
+ defaultLocales,
20
+ } from './i18n';
21
+
22
+ export type {
23
+ SidebarConfig,
24
+ SidebarGroup,
25
+ SidebarItem,
26
+ ScanConfig,
27
+ ManualConfig,
28
+ MixedConfig,
29
+ DividerConfig,
30
+ PathMatchConfig
31
+ } from './sidebar';
32
+ export type { SocialLink } from './social';
33
+ export type { FooterConfig, FooterLink } from './footer';
34
+
35
+ // i18n types
36
+ export type {
37
+ I18nConfig,
38
+ Locale,
39
+ LocaleConfig,
40
+ UITranslations,
41
+ I18nRoutingConfig,
42
+ } from './i18n';
@@ -0,0 +1,32 @@
1
+ import type { NavigationItem } from '../types';
2
+
3
+ /**
4
+ * Default menu configuration
5
+ */
6
+ export const menu: NavigationItem[] = [
7
+ {
8
+ name: '首页',
9
+ href: '/',
10
+ icon: 'home'
11
+ },
12
+ {
13
+ name: '博客',
14
+ href: '/posts',
15
+ icon: 'posts'
16
+ },
17
+ {
18
+ name: '关于',
19
+ href: '/about',
20
+ icon: 'about'
21
+ }
22
+ ];
23
+
24
+ /**
25
+ * Define custom menu items
26
+ */
27
+ export function defineMenu(items: NavigationItem[]): NavigationItem[] {
28
+ return items;
29
+ }
30
+
31
+ // 向后兼容
32
+ export const defaultMenu = menu;
@@ -0,0 +1,142 @@
1
+ /**
2
+ * 侧边栏配置系统
3
+ *
4
+ * 支持三种配置类型:
5
+ * 1. scan - 扫描指定文件夹,自动生成树形结构
6
+ * 2. manual - 手动配置显示特定内容
7
+ * 3. mixed - 混合使用以上两种方式
8
+ */
9
+
10
+ // 路径匹配配置
11
+ export interface PathMatchConfig {
12
+ pattern: string;
13
+ exact?: boolean;
14
+ }
15
+
16
+ // 侧边栏项目类型
17
+ export interface SidebarItem {
18
+ title: string;
19
+ slug?: string;
20
+ link?: string;
21
+ icon?: string;
22
+ badge?: string;
23
+ badgeType?: 'info' | 'success' | 'warning' | 'error';
24
+ children?: SidebarItem[];
25
+ collapsed?: boolean;
26
+ }
27
+
28
+ // 扫描配置
29
+ export interface ScanConfig {
30
+ type: 'scan';
31
+ title: string;
32
+ icon?: string;
33
+ scanPath: string;
34
+ collapsed?: boolean;
35
+ maxDepth?: number;
36
+ exclude?: string[];
37
+ include?: string[];
38
+ sortBy?: 'name' | 'date' | 'title' | 'custom';
39
+ sortOrder?: 'asc' | 'desc';
40
+ showForPaths?: string[];
41
+ hideForPaths?: string[];
42
+ }
43
+
44
+ // 手动配置
45
+ export interface ManualConfig {
46
+ type: 'manual';
47
+ title: string;
48
+ icon?: string;
49
+ collapsed?: boolean;
50
+ items: SidebarItem[];
51
+ showForPaths?: string[];
52
+ hideForPaths?: string[];
53
+ }
54
+
55
+ // 混合配置
56
+ export interface MixedConfig {
57
+ type: 'mixed';
58
+ title: string;
59
+ icon?: string;
60
+ collapsed?: boolean;
61
+ sections: (ScanConfig | ManualConfig)[];
62
+ showForPaths?: string[];
63
+ hideForPaths?: string[];
64
+ }
65
+
66
+ // 分隔符
67
+ export interface DividerConfig {
68
+ type: 'divider';
69
+ title?: string;
70
+ showForPaths?: string[];
71
+ hideForPaths?: string[];
72
+ }
73
+
74
+ // 侧边栏组配置
75
+ export type SidebarGroup = ScanConfig | ManualConfig | MixedConfig | DividerConfig;
76
+
77
+ // 完整侧边栏配置
78
+ export interface SidebarConfig {
79
+ enabled: boolean;
80
+ width?: string;
81
+ position?: 'left' | 'right';
82
+ showSearch?: boolean;
83
+ showRecentPosts?: boolean;
84
+ recentPostsCount?: number;
85
+ showPopularTags?: boolean;
86
+ popularTagsCount?: number;
87
+ showArchives?: boolean;
88
+ archivesCount?: number;
89
+ showFriendLinks?: boolean;
90
+ friendLinks?: Array<{
91
+ title: string;
92
+ url: string;
93
+ icon?: string;
94
+ description?: string;
95
+ }>;
96
+ groups: SidebarGroup[];
97
+ }
98
+
99
+ /**
100
+ * 默认侧边栏配置
101
+ */
102
+ export const sidebarConfig: SidebarConfig = {
103
+ enabled: true,
104
+ width: '280px',
105
+ position: 'right',
106
+ showSearch: true,
107
+ showRecentPosts: true,
108
+ recentPostsCount: 5,
109
+ showPopularTags: true,
110
+ popularTagsCount: 8,
111
+ showArchives: true,
112
+ archivesCount: 6,
113
+ showFriendLinks: true,
114
+ friendLinks: [
115
+ { title: 'Astro 官网', url: 'https://astro.build' },
116
+ { title: 'Tailwind CSS', url: 'https://tailwindcss.com' },
117
+ { title: 'Vue.js', url: 'https://vuejs.org' },
118
+ ],
119
+ groups: [
120
+ {
121
+ type: 'scan',
122
+ title: '文档目录',
123
+ icon: 'folder',
124
+ scanPath: '',
125
+ collapsed: false,
126
+ }
127
+ ]
128
+ };
129
+
130
+ /**
131
+ * Define sidebar configuration
132
+ */
133
+ export function defineSidebarConfig(config: Partial<SidebarConfig>): SidebarConfig {
134
+ return {
135
+ ...sidebarConfig,
136
+ ...config,
137
+ groups: config.groups || sidebarConfig.groups
138
+ };
139
+ }
140
+
141
+ // 向后兼容
142
+ export const defaultSidebarConfig = sidebarConfig;