@jet-w/astro-blog 0.2.5 → 0.2.6
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/package.json +1 -1
- package/src/components/blog/Hero.astro +9 -6
- package/src/components/blog/PostCard.astro +4 -8
- package/src/components/home/FeaturedPostsSection.astro +9 -4
- package/src/components/home/QuickNavSection.astro +9 -4
- package/src/components/home/RecentPostsSection.astro +9 -4
- package/src/components/home/StatsSection.astro +9 -3
- package/src/components/layout/Footer.astro +16 -7
- package/src/components/layout/Header.astro +15 -12
- package/src/components/layout/Sidebar.astro +11 -6
- package/src/components/media/Slides.astro +22 -6
- package/src/components/ui/LanguageSwitcher.vue +24 -12
- package/src/components/ui/MobileMenu.vue +20 -3
- package/src/layouts/BaseLayout.astro +14 -7
- package/src/layouts/PageLayout.astro +9 -3
- package/src/layouts/SlidesLayout.astro +34 -16
- package/src/pages/archives/[year]/[month]/page/[page].astro +42 -18
- package/src/pages/archives/[year]/[month].astro +7 -2
- package/src/pages/archives/index.astro +7 -3
- package/src/pages/categories/[category]/page/[page].astro +40 -18
- package/src/pages/categories/[category].astro +7 -2
- package/src/pages/categories/index.astro +7 -3
- package/src/pages/posts/[...slug].astro +7 -3
- package/src/pages/posts/index.astro +7 -3
- package/src/pages/posts/page/[page].astro +7 -2
- package/src/pages/search.astro +9 -3
- package/src/pages/slides/index.astro +7 -3
- package/src/pages/tags/[tag]/page/[page].astro +39 -17
- package/src/pages/tags/[tag].astro +7 -2
- package/src/pages/tags/index.astro +7 -3
- package/src/plugins/rehype-relative-links.mjs +90 -14
- package/templates/default/.claude/ralph-loop.local.md +2 -32
- package/templates/default/Makefile +37 -0
- package/templates/default/astro.config.mjs +7 -3
- package/templates/default/package.prod.json +31 -0
|
@@ -3,7 +3,7 @@ import { siteConfig } from '@jet-w/astro-blog/config';
|
|
|
3
3
|
import '@jet-w/astro-blog/styles/slides.css';
|
|
4
4
|
import type { I18nConfig } from '../config/i18n';
|
|
5
5
|
import { defaultI18nConfig } from '../config/i18n';
|
|
6
|
-
import { getLocaleFromPath, getLocaleConfig } from '../utils/i18n';
|
|
6
|
+
import { getLocaleFromPath, getLocaleConfig, removeBase } from '../utils/i18n';
|
|
7
7
|
|
|
8
8
|
export interface Props {
|
|
9
9
|
title: string;
|
|
@@ -33,8 +33,14 @@ const {
|
|
|
33
33
|
i18nConfig = defaultI18nConfig,
|
|
34
34
|
} = Astro.props;
|
|
35
35
|
|
|
36
|
-
// Get
|
|
37
|
-
const
|
|
36
|
+
// Get base URL for prefixing links
|
|
37
|
+
const base = import.meta.env.BASE_URL;
|
|
38
|
+
|
|
39
|
+
// Remove base URL from current path for locale detection
|
|
40
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
41
|
+
|
|
42
|
+
// Get current locale (use path without base)
|
|
43
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
38
44
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
39
45
|
const localeData = localeConfig.locale;
|
|
40
46
|
const localeSiteConfig = localeConfig.site;
|
|
@@ -65,7 +71,7 @@ const revealConfig = JSON.stringify({
|
|
|
65
71
|
<meta charset="UTF-8" />
|
|
66
72
|
<meta name="description" content={description} />
|
|
67
73
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
68
|
-
<link rel="icon" type="image/svg+xml" href=
|
|
74
|
+
<link rel="icon" type="image/svg+xml" href={`${base}favicon.svg`} />
|
|
69
75
|
<meta name="generator" content={Astro.generator} />
|
|
70
76
|
<title>{fullTitle}</title>
|
|
71
77
|
|
|
@@ -75,11 +81,11 @@ const revealConfig = JSON.stringify({
|
|
|
75
81
|
<meta property="og:description" content={description} />
|
|
76
82
|
|
|
77
83
|
<!-- Reveal.js CSS -->
|
|
78
|
-
<link rel="stylesheet" href=
|
|
79
|
-
<link rel="stylesheet" href={
|
|
84
|
+
<link rel="stylesheet" href={`${base}slides/reveal.css`} />
|
|
85
|
+
<link rel="stylesheet" href={`${base}slides/theme/${theme}.css`} id="theme" />
|
|
80
86
|
|
|
81
87
|
<!-- Reveal.js 代码高亮主题 -->
|
|
82
|
-
<link rel="stylesheet" href=
|
|
88
|
+
<link rel="stylesheet" href={`${base}slides/plugin/highlight/monokai.css`} />
|
|
83
89
|
|
|
84
90
|
<!-- KaTeX for math -->
|
|
85
91
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" />
|
|
@@ -117,7 +123,7 @@ const revealConfig = JSON.stringify({
|
|
|
117
123
|
</a>
|
|
118
124
|
|
|
119
125
|
<!-- 检测嵌入模式并隐藏返回按钮,设置返回链接为父路径 -->
|
|
120
|
-
<script is:inline>
|
|
126
|
+
<script is:inline define:vars={{ baseUrl: base }}>
|
|
121
127
|
(function() {
|
|
122
128
|
var btn = document.getElementById('slides-back-btn');
|
|
123
129
|
if (!btn) return;
|
|
@@ -138,17 +144,29 @@ const revealConfig = JSON.stringify({
|
|
|
138
144
|
}
|
|
139
145
|
// 获取父路径
|
|
140
146
|
var parentPath = path.substring(0, path.lastIndexOf('/'));
|
|
141
|
-
//
|
|
142
|
-
btn.href = parentPath ||
|
|
147
|
+
// 如果父路径为空,返回base URL
|
|
148
|
+
btn.href = parentPath || baseUrl;
|
|
143
149
|
})();
|
|
144
150
|
</script>
|
|
145
151
|
|
|
146
|
-
<!-- Reveal.js -->
|
|
147
|
-
<script is:inline
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
<!-- Reveal.js - dynamically loaded with base URL -->
|
|
153
|
+
<script is:inline define:vars={{ baseUrl: base }}>
|
|
154
|
+
(function() {
|
|
155
|
+
var scripts = [
|
|
156
|
+
baseUrl + 'slides/reveal.js',
|
|
157
|
+
baseUrl + 'slides/plugin/markdown/markdown.js',
|
|
158
|
+
baseUrl + 'slides/plugin/highlight/highlight.js',
|
|
159
|
+
baseUrl + 'slides/plugin/notes/notes.js',
|
|
160
|
+
baseUrl + 'slides/plugin/math/math.js'
|
|
161
|
+
];
|
|
162
|
+
scripts.forEach(function(src) {
|
|
163
|
+
var script = document.createElement('script');
|
|
164
|
+
script.src = src;
|
|
165
|
+
script.async = false;
|
|
166
|
+
document.head.appendChild(script);
|
|
167
|
+
});
|
|
168
|
+
})();
|
|
169
|
+
</script>
|
|
152
170
|
|
|
153
171
|
<!-- Mermaid -->
|
|
154
172
|
<script is:inline src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
|
@@ -3,6 +3,9 @@ import { getCollection } from 'astro:content';
|
|
|
3
3
|
import PageLayout from '@jet-w/astro-blog/layouts/PageLayout.astro';
|
|
4
4
|
import PostCard from '@jet-w/astro-blog/components/blog/PostCard.astro';
|
|
5
5
|
import Pagination from '@jet-w/astro-blog/components/ui/Pagination.astro';
|
|
6
|
+
import { i18nConfig as virtualI18nConfig } from 'virtual:astro-blog-i18n';
|
|
7
|
+
import { defaultI18nConfig } from '../../../../../config/i18n';
|
|
8
|
+
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, filterPostsByLocale, removeBase } from '../../../../../utils/i18n';
|
|
6
9
|
|
|
7
10
|
export async function getStaticPaths() {
|
|
8
11
|
const postsPerPage = 10;
|
|
@@ -57,8 +60,23 @@ export async function getStaticPaths() {
|
|
|
57
60
|
const { year, month, page: currentPage, totalPages } = Astro.props;
|
|
58
61
|
const postsPerPage = 10;
|
|
59
62
|
|
|
63
|
+
// Get i18n config
|
|
64
|
+
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
65
|
+
const base = import.meta.env.BASE_URL;
|
|
66
|
+
|
|
67
|
+
// Remove base URL from current path for locale detection
|
|
68
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
69
|
+
|
|
70
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
71
|
+
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
72
|
+
const ui = localeConfig.ui;
|
|
73
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
74
|
+
|
|
60
75
|
// 获取该月的所有文章
|
|
61
|
-
const
|
|
76
|
+
const allPostsCollection = await getCollection('posts', ({ data }) => !data.draft);
|
|
77
|
+
|
|
78
|
+
// Filter posts by current locale
|
|
79
|
+
const allPosts = filterPostsByLocale(allPostsCollection, currentLocale, i18nConfig);
|
|
62
80
|
|
|
63
81
|
const filteredPosts = allPosts
|
|
64
82
|
.filter(post => {
|
|
@@ -80,29 +98,32 @@ const posts = filteredPosts.slice(startIndex, endIndex);
|
|
|
80
98
|
|
|
81
99
|
// 月份名称
|
|
82
100
|
const monthNames = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'];
|
|
83
|
-
const
|
|
101
|
+
const monthNamesEn = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
102
|
+
const monthName = currentLocale.startsWith('en') ? monthNamesEn[month - 1] : monthNames[month - 1];
|
|
103
|
+
const archiveTitle = currentLocale.startsWith('en') ? `${monthName} ${year}` : `${year}年${monthName}`;
|
|
84
104
|
---
|
|
85
105
|
|
|
86
106
|
<PageLayout
|
|
87
|
-
title={
|
|
88
|
-
description={`${
|
|
107
|
+
title={`${ui.archives}: ${archiveTitle} - ${ui.page} ${currentPage}`}
|
|
108
|
+
description={`${ui.archives} ${archiveTitle} - ${ui.page} ${currentPage}`}
|
|
89
109
|
showSidebar={true}
|
|
110
|
+
i18nConfig={i18nConfig}
|
|
90
111
|
>
|
|
91
112
|
<!-- 面包屑导航 -->
|
|
92
113
|
<nav class="flex items-center space-x-2 text-sm text-slate-600 dark:text-slate-400 mb-8">
|
|
93
|
-
<a href=
|
|
114
|
+
<a href={`${localePrefix}/`} class="hover:text-primary-500 transition-colors">{ui.home}</a>
|
|
94
115
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
95
116
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
96
117
|
</svg>
|
|
97
|
-
<a href=
|
|
118
|
+
<a href={`${localePrefix}/archives`} class="hover:text-primary-500 transition-colors">{ui.archives}</a>
|
|
98
119
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
99
120
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
100
121
|
</svg>
|
|
101
|
-
<a href={
|
|
122
|
+
<a href={`${localePrefix}/archives/${year}/${String(month).padStart(2, '0')}`} class="hover:text-primary-500 transition-colors">{archiveTitle}</a>
|
|
102
123
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
103
124
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
104
125
|
</svg>
|
|
105
|
-
<span class="text-slate-900 dark:text-slate-100"
|
|
126
|
+
<span class="text-slate-900 dark:text-slate-100">{ui.page} {currentPage}</span>
|
|
106
127
|
</nav>
|
|
107
128
|
|
|
108
129
|
<!-- 页面头部 -->
|
|
@@ -114,20 +135,20 @@ const monthName = monthNames[month - 1];
|
|
|
114
135
|
</div>
|
|
115
136
|
|
|
116
137
|
<h1 class="text-4xl font-bold text-slate-900 dark:text-slate-100 mb-4">
|
|
117
|
-
{
|
|
138
|
+
{archiveTitle}
|
|
118
139
|
</h1>
|
|
119
140
|
|
|
120
141
|
<p class="text-xl text-slate-600 dark:text-slate-400 mb-8">
|
|
121
|
-
|
|
142
|
+
{totalPosts} {ui.posts}
|
|
122
143
|
</p>
|
|
123
144
|
|
|
124
145
|
<!-- 归档统计 -->
|
|
125
146
|
<div class="inline-flex items-center space-x-6 text-sm text-slate-500 dark:text-slate-400 bg-slate-50 dark:bg-slate-800 px-6 py-3 rounded-lg">
|
|
126
|
-
<span>{
|
|
147
|
+
<span>{archiveTitle}</span>
|
|
127
148
|
<span>•</span>
|
|
128
|
-
<span>{totalPosts}
|
|
149
|
+
<span>{totalPosts} {ui.posts}</span>
|
|
129
150
|
<span>•</span>
|
|
130
|
-
<span
|
|
151
|
+
<span>{ui.page} {currentPage} / {totalPages}</span>
|
|
131
152
|
</div>
|
|
132
153
|
</div>
|
|
133
154
|
|
|
@@ -147,6 +168,9 @@ const monthName = monthNames[month - 1];
|
|
|
147
168
|
image: post.data.image
|
|
148
169
|
}}
|
|
149
170
|
layout="horizontal"
|
|
171
|
+
localePrefix={localePrefix}
|
|
172
|
+
locale={localeConfig.locale.dateLocale}
|
|
173
|
+
ui={ui}
|
|
150
174
|
/>
|
|
151
175
|
))}
|
|
152
176
|
</div>
|
|
@@ -154,13 +178,13 @@ const monthName = monthNames[month - 1];
|
|
|
154
178
|
<div class="text-center py-16">
|
|
155
179
|
<div class="text-6xl mb-4">📅</div>
|
|
156
180
|
<h3 class="text-xl font-semibold text-slate-900 dark:text-slate-100 mb-2">
|
|
157
|
-
|
|
181
|
+
{ui.noPostsFound}
|
|
158
182
|
</h3>
|
|
159
183
|
<p class="text-slate-600 dark:text-slate-400 mb-6">
|
|
160
|
-
{
|
|
184
|
+
{ui.noPostsFound}
|
|
161
185
|
</p>
|
|
162
|
-
<a href=
|
|
163
|
-
|
|
186
|
+
<a href={`${localePrefix}/archives`} class="btn-secondary">
|
|
187
|
+
{ui.archives}
|
|
164
188
|
</a>
|
|
165
189
|
</div>
|
|
166
190
|
)}
|
|
@@ -170,7 +194,7 @@ const monthName = monthNames[month - 1];
|
|
|
170
194
|
<Pagination
|
|
171
195
|
currentPage={currentPage}
|
|
172
196
|
totalPages={totalPages}
|
|
173
|
-
baseUrl={
|
|
197
|
+
baseUrl={`${localePrefix}/archives/${year}/${String(month).padStart(2, '0')}`}
|
|
174
198
|
/>
|
|
175
199
|
)}
|
|
176
200
|
</PageLayout>
|
|
@@ -40,10 +40,15 @@ const { year, month, count } = Astro.props;
|
|
|
40
40
|
|
|
41
41
|
// Get i18n config
|
|
42
42
|
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
43
|
-
const
|
|
43
|
+
const base = import.meta.env.BASE_URL;
|
|
44
|
+
|
|
45
|
+
// Remove base URL from current path for locale detection
|
|
46
|
+
const { removeBase } = await import('../../../utils/i18n');
|
|
47
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
48
|
+
|
|
49
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
44
50
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
45
51
|
const ui = localeConfig.ui;
|
|
46
|
-
const base = import.meta.env.BASE_URL;
|
|
47
52
|
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
48
53
|
|
|
49
54
|
// 获取该月的所有文章
|
|
@@ -3,14 +3,18 @@ import { getCollection } from 'astro:content';
|
|
|
3
3
|
import PageLayout from '@jet-w/astro-blog/layouts/PageLayout.astro';
|
|
4
4
|
import { i18nConfig as virtualI18nConfig } from 'virtual:astro-blog-i18n';
|
|
5
5
|
import { defaultI18nConfig } from '../../config/i18n';
|
|
6
|
-
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, filterPostsByLocale } from '../../utils/i18n';
|
|
6
|
+
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, filterPostsByLocale, removeBase } from '../../utils/i18n';
|
|
7
7
|
|
|
8
8
|
// Get i18n config
|
|
9
9
|
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
10
|
-
const
|
|
10
|
+
const base = import.meta.env.BASE_URL;
|
|
11
|
+
|
|
12
|
+
// Remove base URL from current path for locale detection
|
|
13
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
14
|
+
|
|
15
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
11
16
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
12
17
|
const ui = localeConfig.ui;
|
|
13
|
-
const base = import.meta.env.BASE_URL;
|
|
14
18
|
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
15
19
|
|
|
16
20
|
// 获取所有非草稿文章
|
|
@@ -3,6 +3,9 @@ import { getCollection } from 'astro:content';
|
|
|
3
3
|
import PageLayout from '@jet-w/astro-blog/layouts/PageLayout.astro';
|
|
4
4
|
import PostCard from '@jet-w/astro-blog/components/blog/PostCard.astro';
|
|
5
5
|
import Pagination from '@jet-w/astro-blog/components/ui/Pagination.astro';
|
|
6
|
+
import { i18nConfig as virtualI18nConfig } from 'virtual:astro-blog-i18n';
|
|
7
|
+
import { defaultI18nConfig } from '../../../../config/i18n';
|
|
8
|
+
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, filterPostsByLocale, removeBase } from '../../../../utils/i18n';
|
|
6
9
|
|
|
7
10
|
export async function getStaticPaths() {
|
|
8
11
|
const postsPerPage = 10;
|
|
@@ -53,8 +56,23 @@ export async function getStaticPaths() {
|
|
|
53
56
|
const { categorySlug, categoryName, page: currentPage, totalPages } = Astro.props;
|
|
54
57
|
const postsPerPage = 10;
|
|
55
58
|
|
|
59
|
+
// Get i18n config
|
|
60
|
+
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
61
|
+
const base = import.meta.env.BASE_URL;
|
|
62
|
+
|
|
63
|
+
// Remove base URL from current path for locale detection
|
|
64
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
65
|
+
|
|
66
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
67
|
+
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
68
|
+
const ui = localeConfig.ui;
|
|
69
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
70
|
+
|
|
56
71
|
// 获取所有文章并筛选包含该分类的文章
|
|
57
|
-
const
|
|
72
|
+
const allPostsCollection = await getCollection('posts', ({ data }) => !data.draft);
|
|
73
|
+
|
|
74
|
+
// Filter posts by current locale
|
|
75
|
+
const allPosts = filterPostsByLocale(allPostsCollection, currentLocale, i18nConfig);
|
|
58
76
|
|
|
59
77
|
// 筛选包含该分类的文章
|
|
60
78
|
const filteredPosts = allPosts
|
|
@@ -95,25 +113,26 @@ const relatedCategories = Array.from(relatedCategoryMap.entries())
|
|
|
95
113
|
---
|
|
96
114
|
|
|
97
115
|
<PageLayout
|
|
98
|
-
title={
|
|
99
|
-
description={
|
|
116
|
+
title={`${ui.inCategory}: ${categoryName} - ${ui.page} ${currentPage}`}
|
|
117
|
+
description={`${ui.inCategory} ${categoryName} - ${ui.page} ${currentPage}`}
|
|
100
118
|
showSidebar={true}
|
|
119
|
+
i18nConfig={i18nConfig}
|
|
101
120
|
>
|
|
102
121
|
<!-- 面包屑导航 -->
|
|
103
122
|
<nav class="flex items-center space-x-2 text-sm text-slate-600 dark:text-slate-400 mb-8">
|
|
104
|
-
<a href=
|
|
123
|
+
<a href={`${localePrefix}/`} class="hover:text-primary-500 transition-colors">{ui.home}</a>
|
|
105
124
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
106
125
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
107
126
|
</svg>
|
|
108
|
-
<a href=
|
|
127
|
+
<a href={`${localePrefix}/categories`} class="hover:text-primary-500 transition-colors">{ui.allCategories}</a>
|
|
109
128
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
110
129
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
111
130
|
</svg>
|
|
112
|
-
<a href={
|
|
131
|
+
<a href={`${localePrefix}/categories/${categorySlug}`} class="hover:text-primary-500 transition-colors">{categoryName}</a>
|
|
113
132
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
114
133
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
115
134
|
</svg>
|
|
116
|
-
<span class="text-slate-900 dark:text-slate-100"
|
|
135
|
+
<span class="text-slate-900 dark:text-slate-100">{ui.page} {currentPage}</span>
|
|
117
136
|
</nav>
|
|
118
137
|
|
|
119
138
|
<!-- 页面头部 -->
|
|
@@ -129,16 +148,16 @@ const relatedCategories = Array.from(relatedCategoryMap.entries())
|
|
|
129
148
|
</h1>
|
|
130
149
|
|
|
131
150
|
<p class="text-xl text-slate-600 dark:text-slate-400 mb-8 max-w-2xl mx-auto">
|
|
132
|
-
|
|
151
|
+
{totalPosts} {ui.posts}
|
|
133
152
|
</p>
|
|
134
153
|
|
|
135
154
|
<!-- 分类统计 -->
|
|
136
155
|
<div class="inline-flex items-center space-x-6 text-sm text-slate-500 dark:text-slate-400 bg-slate-50 dark:bg-slate-800 px-6 py-3 rounded-lg">
|
|
137
156
|
<span>{categoryName}</span>
|
|
138
157
|
<span>•</span>
|
|
139
|
-
<span>{totalPosts}
|
|
158
|
+
<span>{totalPosts} {ui.posts}</span>
|
|
140
159
|
<span>•</span>
|
|
141
|
-
<span
|
|
160
|
+
<span>{ui.page} {currentPage} / {totalPages}</span>
|
|
142
161
|
</div>
|
|
143
162
|
</div>
|
|
144
163
|
|
|
@@ -158,6 +177,9 @@ const relatedCategories = Array.from(relatedCategoryMap.entries())
|
|
|
158
177
|
image: post.data.image
|
|
159
178
|
}}
|
|
160
179
|
layout="horizontal"
|
|
180
|
+
localePrefix={localePrefix}
|
|
181
|
+
locale={localeConfig.locale.dateLocale}
|
|
182
|
+
ui={ui}
|
|
161
183
|
/>
|
|
162
184
|
))}
|
|
163
185
|
</div>
|
|
@@ -165,13 +187,13 @@ const relatedCategories = Array.from(relatedCategoryMap.entries())
|
|
|
165
187
|
<div class="text-center py-16">
|
|
166
188
|
<div class="text-6xl mb-4">📂</div>
|
|
167
189
|
<h3 class="text-xl font-semibold text-slate-900 dark:text-slate-100 mb-2">
|
|
168
|
-
|
|
190
|
+
{ui.noPostsFound}
|
|
169
191
|
</h3>
|
|
170
192
|
<p class="text-slate-600 dark:text-slate-400 mb-6">
|
|
171
|
-
|
|
193
|
+
{ui.noPostsFound}
|
|
172
194
|
</p>
|
|
173
|
-
<a href=
|
|
174
|
-
|
|
195
|
+
<a href={`${localePrefix}/categories`} class="btn-secondary">
|
|
196
|
+
{ui.allCategories}
|
|
175
197
|
</a>
|
|
176
198
|
</div>
|
|
177
199
|
)}
|
|
@@ -181,7 +203,7 @@ const relatedCategories = Array.from(relatedCategoryMap.entries())
|
|
|
181
203
|
<Pagination
|
|
182
204
|
currentPage={currentPage}
|
|
183
205
|
totalPages={totalPages}
|
|
184
|
-
baseUrl={
|
|
206
|
+
baseUrl={`${localePrefix}/categories/${categorySlug}`}
|
|
185
207
|
/>
|
|
186
208
|
)}
|
|
187
209
|
|
|
@@ -189,12 +211,12 @@ const relatedCategories = Array.from(relatedCategoryMap.entries())
|
|
|
189
211
|
{relatedCategories.length > 0 && (
|
|
190
212
|
<section class="mt-16 pt-8 border-t border-slate-200 dark:border-slate-700">
|
|
191
213
|
<h2 class="text-2xl font-bold text-slate-900 dark:text-slate-100 mb-6">
|
|
192
|
-
|
|
214
|
+
{ui.categories}
|
|
193
215
|
</h2>
|
|
194
216
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
195
217
|
{relatedCategories.map((relatedCategory) => (
|
|
196
218
|
<a
|
|
197
|
-
href={
|
|
219
|
+
href={`${localePrefix}/categories/${relatedCategory.slug}`}
|
|
198
220
|
class="group card hover:shadow-lg transform hover:-translate-y-1 transition-all duration-300"
|
|
199
221
|
>
|
|
200
222
|
<div class="flex items-center justify-between">
|
|
@@ -203,7 +225,7 @@ const relatedCategories = Array.from(relatedCategoryMap.entries())
|
|
|
203
225
|
{relatedCategory.name}
|
|
204
226
|
</h3>
|
|
205
227
|
<p class="text-sm text-slate-600 dark:text-slate-400">
|
|
206
|
-
{relatedCategory.count}
|
|
228
|
+
{relatedCategory.count} {ui.posts}
|
|
207
229
|
</p>
|
|
208
230
|
</div>
|
|
209
231
|
<svg class="w-5 h-5 text-slate-400 group-hover:text-amber-500 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -35,10 +35,15 @@ const { categorySlug, categoryName } = Astro.props;
|
|
|
35
35
|
|
|
36
36
|
// Get i18n config
|
|
37
37
|
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
38
|
-
const
|
|
38
|
+
const base = import.meta.env.BASE_URL;
|
|
39
|
+
|
|
40
|
+
// Remove base URL from current path for locale detection
|
|
41
|
+
const { removeBase } = await import('../../utils/i18n');
|
|
42
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
43
|
+
|
|
44
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
39
45
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
40
46
|
const ui = localeConfig.ui;
|
|
41
|
-
const base = import.meta.env.BASE_URL;
|
|
42
47
|
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
43
48
|
|
|
44
49
|
// 获取所有文章并筛选包含该分类的文章
|
|
@@ -3,14 +3,18 @@ import { getCollection } from 'astro:content';
|
|
|
3
3
|
import PageLayout from '@jet-w/astro-blog/layouts/PageLayout.astro';
|
|
4
4
|
import { i18nConfig as virtualI18nConfig } from 'virtual:astro-blog-i18n';
|
|
5
5
|
import { defaultI18nConfig } from '../../config/i18n';
|
|
6
|
-
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, filterPostsByLocale } from '../../utils/i18n';
|
|
6
|
+
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, filterPostsByLocale, removeBase } from '../../utils/i18n';
|
|
7
7
|
|
|
8
8
|
// Get i18n config
|
|
9
9
|
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
10
|
-
const
|
|
10
|
+
const base = import.meta.env.BASE_URL;
|
|
11
|
+
|
|
12
|
+
// Remove base URL from current path for locale detection
|
|
13
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
14
|
+
|
|
15
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
11
16
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
12
17
|
const ui = localeConfig.ui;
|
|
13
|
-
const base = import.meta.env.BASE_URL;
|
|
14
18
|
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
15
19
|
|
|
16
20
|
// 从文章集合动态获取所有分类
|
|
@@ -5,7 +5,7 @@ import SlidesLayout from '@jet-w/astro-blog/layouts/SlidesLayout.astro';
|
|
|
5
5
|
import FloatingToc from '@jet-w/astro-blog/components/blog/FloatingToc.vue';
|
|
6
6
|
import { i18nConfig as virtualI18nConfig } from 'virtual:astro-blog-i18n';
|
|
7
7
|
import { defaultI18nConfig } from '../../config/i18n';
|
|
8
|
-
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix } from '../../utils/i18n';
|
|
8
|
+
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, removeBase } from '../../utils/i18n';
|
|
9
9
|
|
|
10
10
|
export async function getStaticPaths() {
|
|
11
11
|
const posts = await getCollection('posts');
|
|
@@ -153,10 +153,14 @@ const Content = post ? (await render(post)).Content : null;
|
|
|
153
153
|
|
|
154
154
|
// Get i18n config
|
|
155
155
|
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
156
|
-
const
|
|
156
|
+
const base = import.meta.env.BASE_URL;
|
|
157
|
+
|
|
158
|
+
// Remove base URL from current path for locale detection
|
|
159
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
160
|
+
|
|
161
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
157
162
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
158
163
|
const ui = localeConfig.ui;
|
|
159
|
-
const base = import.meta.env.BASE_URL;
|
|
160
164
|
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
161
165
|
|
|
162
166
|
// Get the current slug from URL
|
|
@@ -6,14 +6,18 @@ import NavigationTabs from '@jet-w/astro-blog/components/blog/NavigationTabs.vue
|
|
|
6
6
|
import { getCollection } from 'astro:content';
|
|
7
7
|
import { i18nConfig as virtualI18nConfig } from 'virtual:astro-blog-i18n';
|
|
8
8
|
import { defaultI18nConfig } from '../../config/i18n';
|
|
9
|
-
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, filterPostsByLocale } from '../../utils/i18n';
|
|
9
|
+
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, filterPostsByLocale, removeBase } from '../../utils/i18n';
|
|
10
10
|
|
|
11
11
|
// Get i18n config
|
|
12
12
|
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
13
|
-
const
|
|
13
|
+
const base = import.meta.env.BASE_URL;
|
|
14
|
+
|
|
15
|
+
// Remove base URL from current path for locale detection
|
|
16
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
17
|
+
|
|
18
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
14
19
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
15
20
|
const ui = localeConfig.ui;
|
|
16
|
-
const base = import.meta.env.BASE_URL;
|
|
17
21
|
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
18
22
|
|
|
19
23
|
// 从新的内容目录获取文章数据
|
|
@@ -25,10 +25,15 @@ const currentPage = parseInt(page as string, 10);
|
|
|
25
25
|
|
|
26
26
|
// Get i18n config
|
|
27
27
|
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
28
|
-
const
|
|
28
|
+
const base = import.meta.env.BASE_URL;
|
|
29
|
+
|
|
30
|
+
// Remove base URL from current path for locale detection
|
|
31
|
+
const { removeBase } = await import('../../../utils/i18n');
|
|
32
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
33
|
+
|
|
34
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
29
35
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
30
36
|
const ui = localeConfig.ui;
|
|
31
|
-
const base = import.meta.env.BASE_URL;
|
|
32
37
|
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
33
38
|
|
|
34
39
|
// 从新的内容目录获取文章数据
|
package/src/pages/search.astro
CHANGED
|
@@ -4,7 +4,7 @@ import SearchInterface from '@jet-w/astro-blog/components/ui/SearchInterface.vue
|
|
|
4
4
|
import type { I18nConfig } from '../config/i18n';
|
|
5
5
|
import { defaultI18nConfig } from '../config/i18n';
|
|
6
6
|
import { i18nConfig as virtualI18nConfig } from 'virtual:astro-blog-i18n';
|
|
7
|
-
import { getLocaleFromPath, getLocaleConfig } from '../utils/i18n';
|
|
7
|
+
import { getLocaleFromPath, getLocaleConfig, removeBase } from '../utils/i18n';
|
|
8
8
|
|
|
9
9
|
export interface Props {
|
|
10
10
|
i18nConfig?: I18nConfig;
|
|
@@ -12,8 +12,14 @@ export interface Props {
|
|
|
12
12
|
|
|
13
13
|
const { i18nConfig = virtualI18nConfig || defaultI18nConfig } = Astro.props;
|
|
14
14
|
|
|
15
|
-
// Get
|
|
16
|
-
const
|
|
15
|
+
// Get base URL for prefixing links
|
|
16
|
+
const base = import.meta.env.BASE_URL;
|
|
17
|
+
|
|
18
|
+
// Remove base URL from current path for locale detection
|
|
19
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
20
|
+
|
|
21
|
+
// Get current locale from URL (use path without base)
|
|
22
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
17
23
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
18
24
|
const ui = localeConfig.ui;
|
|
19
25
|
|
|
@@ -3,14 +3,18 @@ import { getCollection } from 'astro:content';
|
|
|
3
3
|
import PageLayout from '@jet-w/astro-blog/layouts/PageLayout.astro';
|
|
4
4
|
import { i18nConfig as virtualI18nConfig } from 'virtual:astro-blog-i18n';
|
|
5
5
|
import { defaultI18nConfig } from '../../config/i18n';
|
|
6
|
-
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix } from '../../utils/i18n';
|
|
6
|
+
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, removeBase } from '../../utils/i18n';
|
|
7
7
|
|
|
8
8
|
// Get i18n config
|
|
9
9
|
const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
10
|
-
const
|
|
10
|
+
const base = import.meta.env.BASE_URL;
|
|
11
|
+
|
|
12
|
+
// Remove base URL from current path for locale detection
|
|
13
|
+
const pathWithoutBase = removeBase(Astro.url.pathname, base);
|
|
14
|
+
|
|
15
|
+
const currentLocale = getLocaleFromPath(pathWithoutBase, i18nConfig);
|
|
11
16
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
12
17
|
const ui = localeConfig.ui;
|
|
13
|
-
const base = import.meta.env.BASE_URL;
|
|
14
18
|
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
15
19
|
|
|
16
20
|
// 获取所有非草稿的 slides
|