@anglefeint/astro-theme 0.1.34 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +2 -4
- package/src/components/BaseHead.astro +101 -90
- package/src/config/theme.ts +10 -0
- package/src/i18n/messages.ts +36 -0
- package/src/index.ts +0 -1
- package/src/layouts/BlogPost.astro +36 -24
- package/src/layouts/HomePage.astro +30 -28
- package/src/consts.ts +0 -12
package/README.md
CHANGED
|
@@ -54,6 +54,8 @@ This package reads site-specific config from alias imports:
|
|
|
54
54
|
|
|
55
55
|
In the starter/site project, map these aliases to `src/config/*` and `src/i18n/*` in both Vite and TS config.
|
|
56
56
|
|
|
57
|
+
Giscus comments are configured from site-side `theme.comments` (enabled + repo/category IDs). If required fields are not set, comments are not rendered.
|
|
58
|
+
|
|
57
59
|
## CLI
|
|
58
60
|
|
|
59
61
|
- `anglefeint-new-post`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anglefeint/astro-theme",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Anglefeint core theme package for Astro",
|
|
6
6
|
"keywords": [
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
20
|
"src/index.ts",
|
|
21
|
-
"src/consts.ts",
|
|
22
21
|
"src/content-schema.ts",
|
|
23
22
|
"src/config",
|
|
24
23
|
"src/components",
|
|
@@ -46,8 +45,7 @@
|
|
|
46
45
|
"./assets/*": "./src/assets/*",
|
|
47
46
|
"./utils/merge": "./src/utils/merge.ts",
|
|
48
47
|
"./utils/*": "./src/utils/*",
|
|
49
|
-
"./content-schema": "./src/content-schema.ts"
|
|
50
|
-
"./consts": "./src/consts.ts"
|
|
48
|
+
"./content-schema": "./src/content-schema.ts"
|
|
51
49
|
},
|
|
52
50
|
"peerDependencies": {
|
|
53
51
|
"astro": "^5.0.0 || ^6.0.0-beta.0"
|
|
@@ -6,105 +6,109 @@ import type { ImageMetadata } from 'astro';
|
|
|
6
6
|
import FallbackImage from '../assets/theme/placeholders/theme-placeholder-1.jpg';
|
|
7
7
|
import { SITE_AUTHOR, SITE_TITLE, SITE_URL } from '@anglefeint/site-config/site';
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
DEFAULT_LOCALE,
|
|
10
|
+
SUPPORTED_LOCALES,
|
|
11
|
+
alternatePathForLocale,
|
|
12
|
+
isLocale,
|
|
13
|
+
stripLocaleFromPath,
|
|
14
14
|
} from '@anglefeint/site-i18n/config';
|
|
15
15
|
|
|
16
16
|
interface Props {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
image?: ImageMetadata;
|
|
20
|
+
pageType?: 'website' | 'article';
|
|
21
|
+
publishedTime?: Date;
|
|
22
|
+
modifiedTime?: Date;
|
|
23
|
+
author?: string;
|
|
24
|
+
tags?: string[];
|
|
25
|
+
schema?: Record<string, unknown> | Record<string, unknown>[];
|
|
26
|
+
noindex?: boolean;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
const siteURL = Astro.site ?? new URL(SITE_URL);
|
|
30
30
|
const canonicalURL = new URL(Astro.url.pathname, siteURL);
|
|
31
31
|
|
|
32
32
|
const {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
title,
|
|
34
|
+
description,
|
|
35
|
+
image = FallbackImage,
|
|
36
|
+
pageType = 'website',
|
|
37
|
+
publishedTime,
|
|
38
|
+
modifiedTime,
|
|
39
|
+
author = SITE_AUTHOR,
|
|
40
|
+
tags,
|
|
41
|
+
schema,
|
|
42
|
+
noindex = false,
|
|
43
43
|
} = Astro.props;
|
|
44
44
|
|
|
45
45
|
const imageURL = new URL(image.src, siteURL).toString();
|
|
46
46
|
const robotsContent = noindex ? 'noindex, nofollow' : 'index, follow, max-image-preview:large';
|
|
47
47
|
const isArticle = pageType === 'article';
|
|
48
48
|
const pathParts = Astro.url.pathname.split('/').filter(Boolean);
|
|
49
|
-
const currentLocale =
|
|
49
|
+
const currentLocale =
|
|
50
|
+
pathParts.length > 0 && isLocale(pathParts[0]) ? pathParts[0] : DEFAULT_LOCALE;
|
|
50
51
|
const rssURL = new URL(`/${currentLocale}/rss.xml`, siteURL);
|
|
51
52
|
const localeSubpath = stripLocaleFromPath(Astro.url.pathname, currentLocale);
|
|
52
53
|
const alternatePaths = SUPPORTED_LOCALES.map((locale) => ({
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
locale,
|
|
55
|
+
href: new URL(alternatePathForLocale(locale, localeSubpath), siteURL).toString(),
|
|
55
56
|
}));
|
|
56
57
|
const xDefaultHref = new URL(alternatePathForLocale(DEFAULT_LOCALE, localeSubpath), siteURL);
|
|
57
58
|
|
|
58
59
|
const OG_LOCALE: Record<string, string> = {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
en: 'en_US',
|
|
61
|
+
ja: 'ja_JP',
|
|
62
|
+
ko: 'ko_KR',
|
|
63
|
+
es: 'es_ES',
|
|
64
|
+
zh: 'zh_CN',
|
|
64
65
|
};
|
|
65
66
|
const ogLocale = OG_LOCALE[currentLocale] ?? 'en_US';
|
|
66
|
-
const ogLocaleAlternates = SUPPORTED_LOCALES.filter((l) => l !== currentLocale).map(
|
|
67
|
+
const ogLocaleAlternates = SUPPORTED_LOCALES.filter((l) => l !== currentLocale).map(
|
|
68
|
+
(l) => OG_LOCALE[l]
|
|
69
|
+
);
|
|
70
|
+
const articleModifiedISO = (modifiedTime ?? publishedTime)?.toISOString();
|
|
67
71
|
|
|
68
72
|
const websiteSchema = {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
'@context': 'https://schema.org',
|
|
74
|
+
'@type': 'WebSite',
|
|
75
|
+
name: SITE_TITLE,
|
|
76
|
+
url: siteURL.toString(),
|
|
77
|
+
description,
|
|
78
|
+
publisher: {
|
|
79
|
+
'@type': 'Person',
|
|
80
|
+
name: SITE_AUTHOR,
|
|
81
|
+
},
|
|
78
82
|
};
|
|
79
83
|
|
|
80
84
|
const personSchema = {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
'@context': 'https://schema.org',
|
|
86
|
+
'@type': 'Person',
|
|
87
|
+
name: SITE_AUTHOR,
|
|
88
|
+
url: siteURL.toString(),
|
|
85
89
|
};
|
|
86
90
|
|
|
87
91
|
const articleSchema = isArticle
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
92
|
+
? {
|
|
93
|
+
'@context': 'https://schema.org',
|
|
94
|
+
'@type': 'BlogPosting',
|
|
95
|
+
headline: title,
|
|
96
|
+
description,
|
|
97
|
+
image: [imageURL],
|
|
98
|
+
author: {
|
|
99
|
+
'@type': 'Person',
|
|
100
|
+
name: author,
|
|
101
|
+
},
|
|
102
|
+
publisher: {
|
|
103
|
+
'@type': 'Person',
|
|
104
|
+
name: SITE_AUTHOR,
|
|
105
|
+
},
|
|
106
|
+
mainEntityOfPage: canonicalURL.toString(),
|
|
107
|
+
datePublished: publishedTime?.toISOString(),
|
|
108
|
+
dateModified: (modifiedTime ?? publishedTime)?.toISOString(),
|
|
109
|
+
keywords: tags?.length ? tags.join(', ') : undefined,
|
|
110
|
+
}
|
|
111
|
+
: undefined;
|
|
108
112
|
|
|
109
113
|
const extraSchemas = schema ? (Array.isArray(schema) ? schema : [schema]) : [];
|
|
110
114
|
const jsonLdSchemas = [websiteSchema, personSchema, articleSchema, ...extraSchemas].filter(Boolean);
|
|
@@ -116,12 +120,7 @@ const jsonLdSchemas = [websiteSchema, personSchema, articleSchema, ...extraSchem
|
|
|
116
120
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
117
121
|
<link rel="icon" href="/favicon.ico" />
|
|
118
122
|
<link rel="sitemap" href="/sitemap-index.xml" />
|
|
119
|
-
<link
|
|
120
|
-
rel="alternate"
|
|
121
|
-
type="application/rss+xml"
|
|
122
|
-
title={SITE_TITLE}
|
|
123
|
-
href={rssURL}
|
|
124
|
-
/>
|
|
123
|
+
<link rel="alternate" type="application/rss+xml" title={SITE_TITLE} href={rssURL} />
|
|
125
124
|
<meta name="generator" content={Astro.generator} />
|
|
126
125
|
<meta name="robots" content={robotsContent} />
|
|
127
126
|
<meta name="author" content={author} />
|
|
@@ -133,9 +132,9 @@ const jsonLdSchemas = [websiteSchema, personSchema, articleSchema, ...extraSchem
|
|
|
133
132
|
<!-- Canonical URL -->
|
|
134
133
|
<link rel="canonical" href={canonicalURL} />
|
|
135
134
|
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
alternatePaths.map((alternate) => (
|
|
136
|
+
<link rel="alternate" hreflang={alternate.locale} href={alternate.href} />
|
|
137
|
+
))
|
|
139
138
|
}
|
|
140
139
|
<link rel="alternate" hreflang="x-default" href={xDefaultHref} />
|
|
141
140
|
|
|
@@ -151,16 +150,28 @@ const jsonLdSchemas = [websiteSchema, personSchema, articleSchema, ...extraSchem
|
|
|
151
150
|
<meta property="og:title" content={title} />
|
|
152
151
|
<meta property="og:description" content={description} />
|
|
153
152
|
<meta property="og:image" content={imageURL} />
|
|
154
|
-
{
|
|
155
|
-
|
|
153
|
+
{
|
|
154
|
+
typeof image?.width === 'number' && (
|
|
155
|
+
<meta property="og:image:width" content={String(image.width)} />
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
{
|
|
159
|
+
typeof image?.height === 'number' && (
|
|
160
|
+
<meta property="og:image:height" content={String(image.height)} />
|
|
161
|
+
)
|
|
162
|
+
}
|
|
156
163
|
<meta property="og:locale" content={ogLocale} />
|
|
157
|
-
{ogLocaleAlternates.map((loc) =>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
+
{ogLocaleAlternates.map((loc) => <meta property="og:locale:alternate" content={loc} />)}
|
|
165
|
+
{
|
|
166
|
+
isArticle && publishedTime && (
|
|
167
|
+
<meta property="article:published_time" content={publishedTime.toISOString()} />
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
{
|
|
171
|
+
isArticle && articleModifiedISO && (
|
|
172
|
+
<meta property="article:modified_time" content={articleModifiedISO} />
|
|
173
|
+
)
|
|
174
|
+
}
|
|
164
175
|
{isArticle && <meta property="article:author" content={author} />}
|
|
165
176
|
|
|
166
177
|
<!-- Twitter -->
|
|
@@ -170,8 +181,8 @@ const jsonLdSchemas = [websiteSchema, personSchema, articleSchema, ...extraSchem
|
|
|
170
181
|
<meta name="twitter:description" content={description} />
|
|
171
182
|
<meta name="twitter:image" content={imageURL} />
|
|
172
183
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
184
|
+
{
|
|
185
|
+
jsonLdSchemas.map((schemaItem) => (
|
|
186
|
+
<script is:inline type="application/ld+json" set:html={JSON.stringify(schemaItem)} />
|
|
187
|
+
))
|
|
188
|
+
}
|
package/src/config/theme.ts
CHANGED
|
@@ -27,4 +27,14 @@ export const THEME = {
|
|
|
27
27
|
EFFECTS: {
|
|
28
28
|
ENABLE_RED_QUEEN: true,
|
|
29
29
|
},
|
|
30
|
+
/** Optional comments integration (Giscus) */
|
|
31
|
+
COMMENTS: {
|
|
32
|
+
ENABLED: false,
|
|
33
|
+
REPO: '',
|
|
34
|
+
REPO_ID: '',
|
|
35
|
+
CATEGORY: '',
|
|
36
|
+
CATEGORY_ID: '',
|
|
37
|
+
THEME: 'dark',
|
|
38
|
+
LANG: 'en',
|
|
39
|
+
},
|
|
30
40
|
} as const;
|
package/src/i18n/messages.ts
CHANGED
|
@@ -37,7 +37,13 @@ export type Messages = {
|
|
|
37
37
|
jumpGo: string;
|
|
38
38
|
jumpInputLabel: string;
|
|
39
39
|
backToBlog: string;
|
|
40
|
+
backToTop: string;
|
|
40
41
|
related: string;
|
|
42
|
+
comments: string;
|
|
43
|
+
responseOutput: string;
|
|
44
|
+
heroMonitor: string;
|
|
45
|
+
heroSignalSync: string;
|
|
46
|
+
heroModelOnline: string;
|
|
41
47
|
regenerate: string;
|
|
42
48
|
toastP10: string;
|
|
43
49
|
toastP30: string;
|
|
@@ -79,7 +85,13 @@ export const DEFAULT_MESSAGES: Record<Locale, Messages> = {
|
|
|
79
85
|
jumpGo: 'Go',
|
|
80
86
|
jumpInputLabel: 'Page number',
|
|
81
87
|
backToBlog: 'Back to blog',
|
|
88
|
+
backToTop: 'Back to top',
|
|
82
89
|
related: 'Related',
|
|
90
|
+
comments: 'Comments',
|
|
91
|
+
responseOutput: 'Output',
|
|
92
|
+
heroMonitor: 'neural monitor',
|
|
93
|
+
heroSignalSync: 'signal sync active',
|
|
94
|
+
heroModelOnline: 'model online',
|
|
83
95
|
regenerate: 'Regenerate',
|
|
84
96
|
toastP10: 'context parsed 10%',
|
|
85
97
|
toastP30: 'context parsed 30%',
|
|
@@ -119,7 +131,13 @@ export const DEFAULT_MESSAGES: Record<Locale, Messages> = {
|
|
|
119
131
|
jumpGo: '移動',
|
|
120
132
|
jumpInputLabel: 'ページ番号',
|
|
121
133
|
backToBlog: 'ブログへ戻る',
|
|
134
|
+
backToTop: '先頭へ戻る',
|
|
122
135
|
related: '関連記事',
|
|
136
|
+
comments: 'コメント',
|
|
137
|
+
responseOutput: '出力',
|
|
138
|
+
heroMonitor: 'ニューラルモニター',
|
|
139
|
+
heroSignalSync: 'シグナル同期中',
|
|
140
|
+
heroModelOnline: 'モデルオンライン',
|
|
123
141
|
regenerate: '再生成',
|
|
124
142
|
toastP10: '文脈解析 10%',
|
|
125
143
|
toastP30: '文脈解析 30%',
|
|
@@ -159,7 +177,13 @@ export const DEFAULT_MESSAGES: Record<Locale, Messages> = {
|
|
|
159
177
|
jumpGo: '이동',
|
|
160
178
|
jumpInputLabel: '페이지 번호',
|
|
161
179
|
backToBlog: '블로그로 돌아가기',
|
|
180
|
+
backToTop: '맨 위로',
|
|
162
181
|
related: '관련 글',
|
|
182
|
+
comments: '댓글',
|
|
183
|
+
responseOutput: '출력',
|
|
184
|
+
heroMonitor: '뉴럴 모니터',
|
|
185
|
+
heroSignalSync: '신호 동기화 활성',
|
|
186
|
+
heroModelOnline: '모델 온라인',
|
|
163
187
|
regenerate: '재생성',
|
|
164
188
|
toastP10: '컨텍스트 파싱 10%',
|
|
165
189
|
toastP30: '컨텍스트 파싱 30%',
|
|
@@ -200,7 +224,13 @@ export const DEFAULT_MESSAGES: Record<Locale, Messages> = {
|
|
|
200
224
|
jumpGo: 'Ir',
|
|
201
225
|
jumpInputLabel: 'Número de página',
|
|
202
226
|
backToBlog: 'Volver al blog',
|
|
227
|
+
backToTop: 'Volver arriba',
|
|
203
228
|
related: 'Relacionados',
|
|
229
|
+
comments: 'Comentarios',
|
|
230
|
+
responseOutput: 'Salida',
|
|
231
|
+
heroMonitor: 'monitor neural',
|
|
232
|
+
heroSignalSync: 'sincronización de señal activa',
|
|
233
|
+
heroModelOnline: 'modelo en línea',
|
|
204
234
|
regenerate: 'Regenerar',
|
|
205
235
|
toastP10: 'contexto analizado 10%',
|
|
206
236
|
toastP30: 'contexto analizado 30%',
|
|
@@ -240,7 +270,13 @@ export const DEFAULT_MESSAGES: Record<Locale, Messages> = {
|
|
|
240
270
|
jumpGo: '跳转',
|
|
241
271
|
jumpInputLabel: '页码',
|
|
242
272
|
backToBlog: '返回博客',
|
|
273
|
+
backToTop: '返回顶部',
|
|
243
274
|
related: '相关文章',
|
|
275
|
+
comments: '评论',
|
|
276
|
+
responseOutput: '输出',
|
|
277
|
+
heroMonitor: '神经监视器',
|
|
278
|
+
heroSignalSync: '信号同步中',
|
|
279
|
+
heroModelOnline: '模型在线',
|
|
244
280
|
regenerate: '重新生成',
|
|
245
281
|
toastP10: '语境解析 10%',
|
|
246
282
|
toastP30: '语境解析 30%',
|
package/src/index.ts
CHANGED
|
@@ -57,6 +57,10 @@ const hasResponseMeta = aiLatencyMs !== undefined || aiConfidence !== undefined;
|
|
|
57
57
|
const hasStats = aiModel || wordCount !== undefined || tokenCount !== undefined;
|
|
58
58
|
const confidenceText = aiConfidence !== undefined ? aiConfidence.toFixed(2) : undefined;
|
|
59
59
|
const enableRedQueen = THEME.EFFECTS.ENABLE_RED_QUEEN;
|
|
60
|
+
const comments = THEME.COMMENTS;
|
|
61
|
+
const hasCommentsConfig = Boolean(
|
|
62
|
+
comments.ENABLED && comments.REPO && comments.REPO_ID && comments.CATEGORY && comments.CATEGORY_ID
|
|
63
|
+
);
|
|
60
64
|
---
|
|
61
65
|
|
|
62
66
|
<AiShell
|
|
@@ -116,8 +120,11 @@ const enableRedQueen = THEME.EFFECTS.ENABLE_RED_QUEEN;
|
|
|
116
120
|
)
|
|
117
121
|
}
|
|
118
122
|
<div class="ai-read-progress" aria-hidden="true"></div>
|
|
119
|
-
<button
|
|
120
|
-
|
|
123
|
+
<button
|
|
124
|
+
type="button"
|
|
125
|
+
class="ai-back-to-top"
|
|
126
|
+
aria-label={messages.blog.backToTop}
|
|
127
|
+
title={messages.blog.backToTop}>↑</button
|
|
121
128
|
>
|
|
122
129
|
<div
|
|
123
130
|
class="ai-stage-toast"
|
|
@@ -156,13 +163,13 @@ const enableRedQueen = THEME.EFFECTS.ENABLE_RED_QUEEN;
|
|
|
156
163
|
</div>
|
|
157
164
|
</div>
|
|
158
165
|
<div class="hero-frame" aria-hidden="true">
|
|
159
|
-
<span>
|
|
166
|
+
<span>{messages.blog.heroMonitor}</span>
|
|
160
167
|
<span class="hero-frame-dot" />
|
|
161
168
|
</div>
|
|
162
169
|
</div>
|
|
163
170
|
<div class="hero-threat-bar" aria-hidden="true">
|
|
164
|
-
<span>
|
|
165
|
-
<span>
|
|
171
|
+
<span>{messages.blog.heroSignalSync}</span>
|
|
172
|
+
<span>{messages.blog.heroModelOnline}</span>
|
|
166
173
|
</div>
|
|
167
174
|
</div>
|
|
168
175
|
</div>
|
|
@@ -199,7 +206,7 @@ const enableRedQueen = THEME.EFFECTS.ENABLE_RED_QUEEN;
|
|
|
199
206
|
<div class="ai-response-wrap">
|
|
200
207
|
<div class="ai-response-header">
|
|
201
208
|
<div class="ai-response-avatar" aria-hidden="true"></div>
|
|
202
|
-
<span class="ai-response-label">
|
|
209
|
+
<span class="ai-response-label">{messages.blog.responseOutput}</span>
|
|
203
210
|
{
|
|
204
211
|
hasResponseMeta && (
|
|
205
212
|
<div class="ai-response-meta">
|
|
@@ -273,24 +280,29 @@ const enableRedQueen = THEME.EFFECTS.ENABLE_RED_QUEEN;
|
|
|
273
280
|
<span class="ai-back-text">← {messages.blog.backToBlog}</span>
|
|
274
281
|
</a>
|
|
275
282
|
</nav>
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
283
|
+
{
|
|
284
|
+
hasCommentsConfig && (
|
|
285
|
+
<section class="prose ai-comments" aria-label={messages.blog.comments}>
|
|
286
|
+
<script
|
|
287
|
+
src="https://giscus.app/client.js"
|
|
288
|
+
data-repo={comments.REPO}
|
|
289
|
+
data-repo-id={comments.REPO_ID}
|
|
290
|
+
data-category={comments.CATEGORY}
|
|
291
|
+
data-category-id={comments.CATEGORY_ID}
|
|
292
|
+
data-mapping="pathname"
|
|
293
|
+
data-strict="0"
|
|
294
|
+
data-reactions-enabled="1"
|
|
295
|
+
data-emit-metadata="0"
|
|
296
|
+
data-input-position="bottom"
|
|
297
|
+
data-theme={comments.THEME}
|
|
298
|
+
data-lang={comments.LANG || resolvedLocale}
|
|
299
|
+
data-loading="lazy"
|
|
300
|
+
crossorigin="anonymous"
|
|
301
|
+
async
|
|
302
|
+
/>
|
|
303
|
+
</section>
|
|
304
|
+
)
|
|
305
|
+
}
|
|
294
306
|
<Fragment slot="body-end">
|
|
295
307
|
<script>
|
|
296
308
|
import { initBlogpostEffects } from '../scripts/blogpost-effects.js';
|
|
@@ -7,8 +7,8 @@ import { getMessages } from '@anglefeint/site-i18n/messages';
|
|
|
7
7
|
import MatrixShell from './shells/MatrixShell.astro';
|
|
8
8
|
|
|
9
9
|
interface Props {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
locale: Locale;
|
|
11
|
+
latestPosts: CollectionEntry<'blog'>[];
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const { locale, latestPosts } = Astro.props;
|
|
@@ -17,31 +17,33 @@ const heroText = SITE_HERO_BY_LOCALE[locale] ?? messages.home.hero;
|
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
<MatrixShell locale={locale} title={SITE_TITLE} description={messages.siteDescription}>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<p class="home-hero-copy">{heroText}</p>
|
|
20
|
+
<h1>{SITE_TITLE}</h1>
|
|
21
|
+
<p class="home-hero-copy">{heroText}</p>
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
23
|
+
<section class="home-latest">
|
|
24
|
+
<h2 class="home-section-title">{messages.home.latest}</h2>
|
|
25
|
+
<ul class="home-post-list">
|
|
26
|
+
{
|
|
27
|
+
latestPosts.length > 0 ? (
|
|
28
|
+
latestPosts.map((post) => (
|
|
29
|
+
<li>
|
|
30
|
+
<a
|
|
31
|
+
class="home-post-title"
|
|
32
|
+
href={localePath(locale, `/blog/${blogIdToSlugAnyLocale(post.id)}`)}
|
|
33
|
+
>
|
|
34
|
+
{post.data.title}
|
|
35
|
+
</a>
|
|
36
|
+
<div class="home-post-meta">
|
|
37
|
+
<FormattedDate date={post.data.pubDate} locale={locale} />
|
|
38
|
+
{post.data.description && <> · {post.data.description}</>}
|
|
39
|
+
</div>
|
|
40
|
+
</li>
|
|
41
|
+
))
|
|
42
|
+
) : (
|
|
43
|
+
<li>{messages.home.noPosts}</li>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
</ul>
|
|
47
|
+
<p><a href={localePath(locale, '/blog/')}>{messages.home.viewAll}</a></p>
|
|
48
|
+
</section>
|
|
47
49
|
</MatrixShell>
|
package/src/consts.ts
DELETED