@astro-minimax/core 0.1.0
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 +29 -0
- package/package.json +41 -0
- package/src/assets/icons/IconArchive.svg +1 -0
- package/src/assets/icons/IconArrowLeft.svg +1 -0
- package/src/assets/icons/IconArrowNarrowUp.svg +1 -0
- package/src/assets/icons/IconArrowRight.svg +1 -0
- package/src/assets/icons/IconArticle.svg +1 -0
- package/src/assets/icons/IconBrandX.svg +1 -0
- package/src/assets/icons/IconCalendar.svg +1 -0
- package/src/assets/icons/IconChevronLeft.svg +1 -0
- package/src/assets/icons/IconChevronRight.svg +1 -0
- package/src/assets/icons/IconEdit.svg +1 -0
- package/src/assets/icons/IconFacebook.svg +1 -0
- package/src/assets/icons/IconGitHub.svg +1 -0
- package/src/assets/icons/IconHash.svg +1 -0
- package/src/assets/icons/IconHome.svg +1 -0
- package/src/assets/icons/IconLinkedin.svg +1 -0
- package/src/assets/icons/IconMail.svg +1 -0
- package/src/assets/icons/IconMenuDeep.svg +1 -0
- package/src/assets/icons/IconMoon.svg +1 -0
- package/src/assets/icons/IconPinterest.svg +1 -0
- package/src/assets/icons/IconProject.svg +1 -0
- package/src/assets/icons/IconRss.svg +1 -0
- package/src/assets/icons/IconSearch.svg +1 -0
- package/src/assets/icons/IconSeries.svg +1 -0
- package/src/assets/icons/IconSunHigh.svg +1 -0
- package/src/assets/icons/IconTag.svg +1 -0
- package/src/assets/icons/IconTelegram.svg +1 -0
- package/src/assets/icons/IconUser.svg +1 -0
- package/src/assets/icons/IconWhatsapp.svg +1 -0
- package/src/assets/icons/IconX.svg +1 -0
- package/src/components/ai/AIChatWidget.astro +377 -0
- package/src/components/blog/Comments.astro +527 -0
- package/src/components/blog/Copyright.astro +152 -0
- package/src/components/blog/EditPost.astro +59 -0
- package/src/components/blog/FloatingTOC.astro +260 -0
- package/src/components/blog/InlineTOC.astro +223 -0
- package/src/components/blog/PostActions.astro +306 -0
- package/src/components/blog/RelatedPosts.astro +60 -0
- package/src/components/blog/SeriesNav.astro +176 -0
- package/src/components/blog/ShareLinks.astro +26 -0
- package/src/components/nav/BackButton.astro +37 -0
- package/src/components/nav/BackToTopButton.astro +223 -0
- package/src/components/nav/Breadcrumb.astro +57 -0
- package/src/components/nav/FloatingActions.astro +206 -0
- package/src/components/nav/Footer.astro +107 -0
- package/src/components/nav/Header.astro +252 -0
- package/src/components/nav/Pagination.astro +45 -0
- package/src/components/social/Socials.astro +19 -0
- package/src/components/social/Sponsors.astro +34 -0
- package/src/components/social/Sponsorship.astro +44 -0
- package/src/components/ui/Alert.astro +28 -0
- package/src/components/ui/Card.astro +206 -0
- package/src/components/ui/Collapse.astro +82 -0
- package/src/components/ui/ColorPreview.astro +29 -0
- package/src/components/ui/Datetime.astro +61 -0
- package/src/components/ui/GithubCard.astro +191 -0
- package/src/components/ui/LinkButton.astro +21 -0
- package/src/components/ui/Tag.astro +37 -0
- package/src/components/ui/TagCloud.astro +69 -0
- package/src/components/ui/Timeline.astro +39 -0
- package/src/layouts/AboutLayout.astro +24 -0
- package/src/layouts/Layout.astro +329 -0
- package/src/layouts/Main.astro +42 -0
- package/src/layouts/PostDetails.astro +445 -0
- package/src/plugins/rehype-autolink-headings.ts +46 -0
- package/src/plugins/rehype-external-links.ts +35 -0
- package/src/plugins/rehype-table-scroll.ts +35 -0
- package/src/plugins/remark-add-zoomable.ts +28 -0
- package/src/plugins/remark-reading-time.ts +18 -0
- package/src/plugins/shiki-transformers.ts +212 -0
- package/src/scripts/lightbox.ts +63 -0
- package/src/scripts/reading-position.ts +56 -0
- package/src/scripts/theme-utils.ts +19 -0
- package/src/scripts/theme.ts +179 -0
- package/src/scripts/web-vitals.ts +96 -0
- package/src/styles/code-blocks.css +194 -0
- package/src/styles/components.css +252 -0
- package/src/styles/global.css +403 -0
- package/src/styles/typography.css +149 -0
- package/src/types.ts +89 -0
- package/src/utils/generateOgImages.ts +38 -0
- package/src/utils/getCategoryPath.ts +23 -0
- package/src/utils/getPath.ts +52 -0
- package/src/utils/getPostsByCategory.ts +17 -0
- package/src/utils/getPostsByGroupCondition.ts +25 -0
- package/src/utils/getPostsByLang.ts +27 -0
- package/src/utils/getPostsByTag.ts +10 -0
- package/src/utils/getReadingTime.ts +33 -0
- package/src/utils/getRelatedPosts.ts +59 -0
- package/src/utils/getSeriesData.ts +57 -0
- package/src/utils/getSortedPosts.ts +18 -0
- package/src/utils/getTagsWithCount.ts +38 -0
- package/src/utils/getUniqueCategories.ts +81 -0
- package/src/utils/getUniqueTags.ts +23 -0
- package/src/utils/i18n.ts +249 -0
- package/src/utils/loadGoogleFont.ts +38 -0
- package/src/utils/og-templates/post.js +229 -0
- package/src/utils/og-templates/site.js +128 -0
- package/src/utils/pathUtils.ts +17 -0
- package/src/utils/postFilter.ts +11 -0
- package/src/utils/slugify.ts +23 -0
- package/src/utils/toc.ts +27 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { SITE } from "@/config";
|
|
2
|
+
|
|
3
|
+
export type TranslationKey =
|
|
4
|
+
| "nav.home"
|
|
5
|
+
| "nav.posts"
|
|
6
|
+
| "nav.tags"
|
|
7
|
+
| "nav.categories"
|
|
8
|
+
| "nav.about"
|
|
9
|
+
| "nav.friends"
|
|
10
|
+
| "nav.archives"
|
|
11
|
+
| "nav.search"
|
|
12
|
+
| "nav.projects"
|
|
13
|
+
| "projects.title"
|
|
14
|
+
| "projects.desc"
|
|
15
|
+
| "post.featured"
|
|
16
|
+
| "post.recentPosts"
|
|
17
|
+
| "post.allPosts"
|
|
18
|
+
| "post.prev"
|
|
19
|
+
| "post.next"
|
|
20
|
+
| "post.share"
|
|
21
|
+
| "post.like"
|
|
22
|
+
| "post.bookmark"
|
|
23
|
+
| "post.series"
|
|
24
|
+
| "post.editPage"
|
|
25
|
+
| "post.readingMode"
|
|
26
|
+
| "search.title"
|
|
27
|
+
| "search.placeholder"
|
|
28
|
+
| "search.filters"
|
|
29
|
+
| "search.resetFilters"
|
|
30
|
+
| "search.category"
|
|
31
|
+
| "search.language"
|
|
32
|
+
| "search.sortBy"
|
|
33
|
+
| "search.tags"
|
|
34
|
+
| "search.allCategories"
|
|
35
|
+
| "search.allLanguages"
|
|
36
|
+
| "pagination.prev"
|
|
37
|
+
| "pagination.next"
|
|
38
|
+
| "footer.running"
|
|
39
|
+
| "footer.days"
|
|
40
|
+
| "common.backToTop"
|
|
41
|
+
| "common.goBack"
|
|
42
|
+
| "common.notFound"
|
|
43
|
+
| "hero.greeting"
|
|
44
|
+
| "hero.desc"
|
|
45
|
+
| "hero.readMore"
|
|
46
|
+
| "hero.socialLinks"
|
|
47
|
+
| "footer.hi"
|
|
48
|
+
| "footer.copyright"
|
|
49
|
+
| "footer.sitemap"
|
|
50
|
+
| "archives.posts"
|
|
51
|
+
| "archives.years"
|
|
52
|
+
| "tags.tags"
|
|
53
|
+
| "tags.taggedPosts"
|
|
54
|
+
| "tags.sizeLegend"
|
|
55
|
+
| "tags.less"
|
|
56
|
+
| "tags.more"
|
|
57
|
+
| "main.allArticles"
|
|
58
|
+
| "main.allTags"
|
|
59
|
+
| "main.allArchived"
|
|
60
|
+
| "main.tagDesc"
|
|
61
|
+
| "main.categoryDesc"
|
|
62
|
+
| "main.noCategories"
|
|
63
|
+
| "main.searchDesc"
|
|
64
|
+
| "friends.title"
|
|
65
|
+
| "friends.desc"
|
|
66
|
+
| "nav.series"
|
|
67
|
+
| "series.title"
|
|
68
|
+
| "series.desc"
|
|
69
|
+
| "series.articles"
|
|
70
|
+
| "series.latestUpdate"
|
|
71
|
+
| "series.noSeries"
|
|
72
|
+
| "series.seriesDesc"
|
|
73
|
+
| "series.currentReading"
|
|
74
|
+
| "series.progress"
|
|
75
|
+
| "post.updated"
|
|
76
|
+
| "post.readingTime"
|
|
77
|
+
| "post.wordCount"
|
|
78
|
+
| "common.notFoundDesc"
|
|
79
|
+
| "common.goHome";
|
|
80
|
+
|
|
81
|
+
const translations: Record<string, Record<TranslationKey, string>> = {
|
|
82
|
+
en: {
|
|
83
|
+
"nav.home": "Home",
|
|
84
|
+
"nav.posts": "Posts",
|
|
85
|
+
"nav.tags": "Tags",
|
|
86
|
+
"nav.categories": "Categories",
|
|
87
|
+
"nav.about": "About",
|
|
88
|
+
"nav.friends": "Friends",
|
|
89
|
+
"nav.archives": "Archives",
|
|
90
|
+
"nav.search": "Search",
|
|
91
|
+
"nav.projects": "Projects",
|
|
92
|
+
"projects.title": "Projects",
|
|
93
|
+
"projects.desc": "Open source projects and tools.",
|
|
94
|
+
"post.featured": "Featured",
|
|
95
|
+
"post.recentPosts": "Recent Posts",
|
|
96
|
+
"post.allPosts": "All Posts",
|
|
97
|
+
"post.prev": "Previous Post",
|
|
98
|
+
"post.next": "Next Post",
|
|
99
|
+
"post.share": "Share this post on:",
|
|
100
|
+
"post.like": "Like",
|
|
101
|
+
"post.bookmark": "Bookmark",
|
|
102
|
+
"post.series": "Series",
|
|
103
|
+
"post.editPage": "Edit page",
|
|
104
|
+
"post.readingMode": "Reading Mode",
|
|
105
|
+
"search.title": "Search",
|
|
106
|
+
"search.placeholder": "Search any article...",
|
|
107
|
+
"search.filters": "Advanced Filters",
|
|
108
|
+
"search.resetFilters": "Reset Filters",
|
|
109
|
+
"search.category": "Category",
|
|
110
|
+
"search.language": "Language",
|
|
111
|
+
"search.sortBy": "Sort By",
|
|
112
|
+
"search.tags": "Tags",
|
|
113
|
+
"search.allCategories": "All Categories",
|
|
114
|
+
"search.allLanguages": "All Languages",
|
|
115
|
+
"pagination.prev": "Prev",
|
|
116
|
+
"pagination.next": "Next",
|
|
117
|
+
"footer.running": "Running for",
|
|
118
|
+
"footer.days": "days",
|
|
119
|
+
"common.backToTop": "Back to Top",
|
|
120
|
+
"common.goBack": "Go back",
|
|
121
|
+
"common.notFound": "Page Not Found",
|
|
122
|
+
"hero.greeting": "Mingalaba",
|
|
123
|
+
"hero.desc":
|
|
124
|
+
"astro-minimax is a minimal, responsive, accessible and SEO-friendly Astro blog theme. This theme follows best practices and provides accessibility out of the box. Light and dark mode are supported by default. Moreover, additional color schemes can also be configured.",
|
|
125
|
+
"hero.readMore": "Read the blog posts or check",
|
|
126
|
+
"hero.socialLinks": "Social Links:",
|
|
127
|
+
"footer.hi": "Hi",
|
|
128
|
+
"footer.copyright": "© {year} {author}. All rights reserved.",
|
|
129
|
+
"footer.sitemap": "Sitemap",
|
|
130
|
+
"archives.posts": "posts",
|
|
131
|
+
"archives.years": "years",
|
|
132
|
+
"tags.tags": "tags",
|
|
133
|
+
"tags.taggedPosts": "tagged posts",
|
|
134
|
+
"tags.sizeLegend": "Size indicates popularity:",
|
|
135
|
+
"tags.less": "Less",
|
|
136
|
+
"tags.more": "More",
|
|
137
|
+
"main.allArticles": "All the articles I've posted.",
|
|
138
|
+
"main.allTags": "All the tags used in posts.",
|
|
139
|
+
"main.allArchived": "All the articles I've archived.",
|
|
140
|
+
"main.tagDesc": 'All the articles with the tag "{tag}".',
|
|
141
|
+
"main.categoryDesc": 'All the articles in the category "{category}".',
|
|
142
|
+
"main.noCategories": "No categories found.",
|
|
143
|
+
"main.searchDesc": "Search any article with advanced filters ...",
|
|
144
|
+
"friends.title": "Friends",
|
|
145
|
+
"friends.desc": "Friendship links, welcome to exchange.",
|
|
146
|
+
"nav.series": "Series",
|
|
147
|
+
"series.title": "Series",
|
|
148
|
+
"series.desc": "Curated article series for deep-diving into topics.",
|
|
149
|
+
"series.articles": "{count} articles",
|
|
150
|
+
"series.latestUpdate": "Last updated",
|
|
151
|
+
"series.noSeries": "No series found.",
|
|
152
|
+
"series.seriesDesc": 'All articles in the series "{name}".',
|
|
153
|
+
"series.currentReading": "Currently reading",
|
|
154
|
+
"series.progress": "Article {current} of {total}",
|
|
155
|
+
"post.updated": "Updated:",
|
|
156
|
+
"post.readingTime": "{min} min read",
|
|
157
|
+
"post.wordCount": "{count} words",
|
|
158
|
+
"common.notFoundDesc": "The page you are looking for doesn't exist.",
|
|
159
|
+
"common.goHome": "Go back home",
|
|
160
|
+
},
|
|
161
|
+
zh: {
|
|
162
|
+
"nav.home": "首页",
|
|
163
|
+
"nav.posts": "文章",
|
|
164
|
+
"nav.tags": "标签",
|
|
165
|
+
"nav.categories": "分类",
|
|
166
|
+
"nav.about": "关于",
|
|
167
|
+
"nav.friends": "友链",
|
|
168
|
+
"nav.archives": "归档",
|
|
169
|
+
"nav.search": "搜索",
|
|
170
|
+
"nav.projects": "项目",
|
|
171
|
+
"projects.title": "项目",
|
|
172
|
+
"projects.desc": "开源项目与工具展示。",
|
|
173
|
+
"post.featured": "精选文章",
|
|
174
|
+
"post.recentPosts": "最近文章",
|
|
175
|
+
"post.allPosts": "全部文章",
|
|
176
|
+
"post.prev": "上一篇",
|
|
177
|
+
"post.next": "下一篇",
|
|
178
|
+
"post.share": "分享到:",
|
|
179
|
+
"post.like": "喜欢",
|
|
180
|
+
"post.bookmark": "收藏",
|
|
181
|
+
"post.series": "系列",
|
|
182
|
+
"post.editPage": "编辑此页",
|
|
183
|
+
"post.readingMode": "沉浸式阅读",
|
|
184
|
+
"search.title": "搜索",
|
|
185
|
+
"search.placeholder": "搜索文章...",
|
|
186
|
+
"search.filters": "高级筛选",
|
|
187
|
+
"search.resetFilters": "重置筛选",
|
|
188
|
+
"search.category": "分类",
|
|
189
|
+
"search.language": "语言",
|
|
190
|
+
"search.sortBy": "排序方式",
|
|
191
|
+
"search.tags": "标签",
|
|
192
|
+
"search.allCategories": "全部分类",
|
|
193
|
+
"search.allLanguages": "全部语言",
|
|
194
|
+
"pagination.prev": "上一页",
|
|
195
|
+
"pagination.next": "下一页",
|
|
196
|
+
"footer.running": "已运行",
|
|
197
|
+
"footer.days": "天",
|
|
198
|
+
"common.backToTop": "回到顶部",
|
|
199
|
+
"common.goBack": "返回",
|
|
200
|
+
"common.notFound": "页面未找到",
|
|
201
|
+
"hero.greeting": "你好",
|
|
202
|
+
"hero.desc":
|
|
203
|
+
"astro-minimax 是一个极简、响应式、无障碍且 SEO 友好的 Astro 博客主题。本主题遵循最佳实践,开箱即用提供无障碍支持。默认支持亮色和暗色模式,还可配置更多配色方案。",
|
|
204
|
+
"hero.readMore": "阅读博客文章或查看",
|
|
205
|
+
"hero.socialLinks": "社交链接:",
|
|
206
|
+
"footer.hi": "你好",
|
|
207
|
+
"footer.copyright": "© {year} {author},版权所有,禁止转载,转发需注明出处",
|
|
208
|
+
"footer.sitemap": "站点地图",
|
|
209
|
+
"archives.posts": "篇文章",
|
|
210
|
+
"archives.years": "年",
|
|
211
|
+
"tags.tags": "个标签",
|
|
212
|
+
"tags.taggedPosts": "篇已标记文章",
|
|
213
|
+
"tags.sizeLegend": "大小表示使用频率:",
|
|
214
|
+
"tags.less": "少",
|
|
215
|
+
"tags.more": "多",
|
|
216
|
+
"main.allArticles": "我发布的所有文章。",
|
|
217
|
+
"main.allTags": "文章中使用的所有标签。",
|
|
218
|
+
"main.allArchived": "我归档的所有文章。",
|
|
219
|
+
"main.tagDesc": "标签「{tag}」下的所有文章。",
|
|
220
|
+
"main.categoryDesc": "分类「{category}」下的所有文章。",
|
|
221
|
+
"main.noCategories": "暂无分类。",
|
|
222
|
+
"main.searchDesc": "使用高级筛选搜索文章...",
|
|
223
|
+
"friends.title": "友链",
|
|
224
|
+
"friends.desc": "友情链接,欢迎交换",
|
|
225
|
+
"nav.series": "专栏",
|
|
226
|
+
"series.title": "专栏",
|
|
227
|
+
"series.desc": "精心策划的系列文章,深入探索各个主题。",
|
|
228
|
+
"series.articles": "{count} 篇文章",
|
|
229
|
+
"series.latestUpdate": "最近更新",
|
|
230
|
+
"series.noSeries": "暂无系列文章。",
|
|
231
|
+
"series.seriesDesc": "系列「{name}」中的所有文章。",
|
|
232
|
+
"series.currentReading": "正在阅读",
|
|
233
|
+
"series.progress": "第 {current} 篇,共 {total} 篇",
|
|
234
|
+
"post.updated": "更新于:",
|
|
235
|
+
"post.readingTime": "{min} 分钟阅读",
|
|
236
|
+
"post.wordCount": "{count} 字",
|
|
237
|
+
"common.notFoundDesc": "你访问的页面不存在。",
|
|
238
|
+
"common.goHome": "返回首页",
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
export function t(key: TranslationKey, lang?: string): string {
|
|
243
|
+
const l = lang ?? (SITE.lang === "zh" ? "zh" : "en");
|
|
244
|
+
return translations[l]?.[key] ?? translations["en"][key] ?? key;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function getLang(lang?: string): string {
|
|
248
|
+
return lang ?? (SITE.lang === "zh" ? "zh" : "en");
|
|
249
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
async function loadLocalFont(
|
|
5
|
+
weight: number,
|
|
6
|
+
style: string
|
|
7
|
+
): Promise<ArrayBuffer> {
|
|
8
|
+
const filename = `ibm-plex-mono-latin-${weight}-${style}.woff`;
|
|
9
|
+
const fontPath = join(process.cwd(), "public", "fonts", filename);
|
|
10
|
+
const buffer = await readFile(fontPath);
|
|
11
|
+
return buffer.buffer.slice(
|
|
12
|
+
buffer.byteOffset,
|
|
13
|
+
buffer.byteOffset + buffer.byteLength
|
|
14
|
+
) as ArrayBuffer;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function loadGoogleFonts(
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
19
|
+
_text: string
|
|
20
|
+
): Promise<
|
|
21
|
+
Array<{ name: string; data: ArrayBuffer; weight: number; style: string }>
|
|
22
|
+
> {
|
|
23
|
+
const fontsConfig = [
|
|
24
|
+
{ name: "IBM Plex Mono", weight: 400, style: "normal" },
|
|
25
|
+
{ name: "IBM Plex Mono", weight: 700, style: "normal" },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const fonts = await Promise.all(
|
|
29
|
+
fontsConfig.map(async ({ name, weight, style }) => {
|
|
30
|
+
const data = await loadLocalFont(weight, style);
|
|
31
|
+
return { name, data, weight, style };
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return fonts;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default loadGoogleFonts;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import satori from "satori";
|
|
2
|
+
// import { html } from "satori-html";
|
|
3
|
+
import { SITE } from "@/config";
|
|
4
|
+
import loadGoogleFonts from "../loadGoogleFont";
|
|
5
|
+
|
|
6
|
+
// const markup = html`<div
|
|
7
|
+
// style={{
|
|
8
|
+
// background: "#fefbfb",
|
|
9
|
+
// width: "100%",
|
|
10
|
+
// height: "100%",
|
|
11
|
+
// display: "flex",
|
|
12
|
+
// alignItems: "center",
|
|
13
|
+
// justifyContent: "center",
|
|
14
|
+
// }}
|
|
15
|
+
// >
|
|
16
|
+
// <div
|
|
17
|
+
// style={{
|
|
18
|
+
// position: "absolute",
|
|
19
|
+
// top: "-1px",
|
|
20
|
+
// right: "-1px",
|
|
21
|
+
// border: "4px solid #000",
|
|
22
|
+
// background: "#ecebeb",
|
|
23
|
+
// opacity: "0.9",
|
|
24
|
+
// borderRadius: "4px",
|
|
25
|
+
// display: "flex",
|
|
26
|
+
// justifyContent: "center",
|
|
27
|
+
// margin: "2.5rem",
|
|
28
|
+
// width: "88%",
|
|
29
|
+
// height: "80%",
|
|
30
|
+
// }}
|
|
31
|
+
// />
|
|
32
|
+
|
|
33
|
+
// <div
|
|
34
|
+
// style={{
|
|
35
|
+
// border: "4px solid #000",
|
|
36
|
+
// background: "#fefbfb",
|
|
37
|
+
// borderRadius: "4px",
|
|
38
|
+
// display: "flex",
|
|
39
|
+
// justifyContent: "center",
|
|
40
|
+
// margin: "2rem",
|
|
41
|
+
// width: "88%",
|
|
42
|
+
// height: "80%",
|
|
43
|
+
// }}
|
|
44
|
+
// >
|
|
45
|
+
// <div
|
|
46
|
+
// style={{
|
|
47
|
+
// display: "flex",
|
|
48
|
+
// flexDirection: "column",
|
|
49
|
+
// justifyContent: "space-between",
|
|
50
|
+
// margin: "20px",
|
|
51
|
+
// width: "90%",
|
|
52
|
+
// height: "90%",
|
|
53
|
+
// }}
|
|
54
|
+
// >
|
|
55
|
+
// <p
|
|
56
|
+
// style={{
|
|
57
|
+
// fontSize: 72,
|
|
58
|
+
// fontWeight: "bold",
|
|
59
|
+
// maxHeight: "84%",
|
|
60
|
+
// overflow: "hidden",
|
|
61
|
+
// }}
|
|
62
|
+
// >
|
|
63
|
+
// {post.data.title}
|
|
64
|
+
// </p>
|
|
65
|
+
// <div
|
|
66
|
+
// style={{
|
|
67
|
+
// display: "flex",
|
|
68
|
+
// justifyContent: "space-between",
|
|
69
|
+
// width: "100%",
|
|
70
|
+
// marginBottom: "8px",
|
|
71
|
+
// fontSize: 28,
|
|
72
|
+
// }}
|
|
73
|
+
// >
|
|
74
|
+
// <span>
|
|
75
|
+
// by{" "}
|
|
76
|
+
// <span
|
|
77
|
+
// style={{
|
|
78
|
+
// color: "transparent",
|
|
79
|
+
// }}
|
|
80
|
+
// >
|
|
81
|
+
// "
|
|
82
|
+
// </span>
|
|
83
|
+
// <span style={{ overflow: "hidden", fontWeight: "bold" }}>
|
|
84
|
+
// {post.data.author}
|
|
85
|
+
// </span>
|
|
86
|
+
// </span>
|
|
87
|
+
|
|
88
|
+
// <span style={{ overflow: "hidden", fontWeight: "bold" }}>
|
|
89
|
+
// {SITE.title}
|
|
90
|
+
// </span>
|
|
91
|
+
// </div>
|
|
92
|
+
// </div>
|
|
93
|
+
// </div>
|
|
94
|
+
// </div>`;
|
|
95
|
+
|
|
96
|
+
export default async post => {
|
|
97
|
+
return satori(
|
|
98
|
+
{
|
|
99
|
+
type: "div",
|
|
100
|
+
props: {
|
|
101
|
+
style: {
|
|
102
|
+
background: "#fefbfb",
|
|
103
|
+
width: "100%",
|
|
104
|
+
height: "100%",
|
|
105
|
+
display: "flex",
|
|
106
|
+
alignItems: "center",
|
|
107
|
+
justifyContent: "center",
|
|
108
|
+
},
|
|
109
|
+
children: [
|
|
110
|
+
{
|
|
111
|
+
type: "div",
|
|
112
|
+
props: {
|
|
113
|
+
style: {
|
|
114
|
+
position: "absolute",
|
|
115
|
+
top: "-1px",
|
|
116
|
+
right: "-1px",
|
|
117
|
+
border: "4px solid #000",
|
|
118
|
+
background: "#ecebeb",
|
|
119
|
+
opacity: "0.9",
|
|
120
|
+
borderRadius: "4px",
|
|
121
|
+
display: "flex",
|
|
122
|
+
justifyContent: "center",
|
|
123
|
+
margin: "2.5rem",
|
|
124
|
+
width: "88%",
|
|
125
|
+
height: "80%",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
type: "div",
|
|
131
|
+
props: {
|
|
132
|
+
style: {
|
|
133
|
+
border: "4px solid #000",
|
|
134
|
+
background: "#fefbfb",
|
|
135
|
+
borderRadius: "4px",
|
|
136
|
+
display: "flex",
|
|
137
|
+
justifyContent: "center",
|
|
138
|
+
margin: "2rem",
|
|
139
|
+
width: "88%",
|
|
140
|
+
height: "80%",
|
|
141
|
+
},
|
|
142
|
+
children: {
|
|
143
|
+
type: "div",
|
|
144
|
+
props: {
|
|
145
|
+
style: {
|
|
146
|
+
display: "flex",
|
|
147
|
+
flexDirection: "column",
|
|
148
|
+
justifyContent: "space-between",
|
|
149
|
+
margin: "20px",
|
|
150
|
+
width: "90%",
|
|
151
|
+
height: "90%",
|
|
152
|
+
},
|
|
153
|
+
children: [
|
|
154
|
+
{
|
|
155
|
+
type: "p",
|
|
156
|
+
props: {
|
|
157
|
+
style: {
|
|
158
|
+
fontSize: 72,
|
|
159
|
+
fontWeight: "bold",
|
|
160
|
+
maxHeight: "84%",
|
|
161
|
+
overflow: "hidden",
|
|
162
|
+
},
|
|
163
|
+
children: post.data.title,
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
type: "div",
|
|
168
|
+
props: {
|
|
169
|
+
style: {
|
|
170
|
+
display: "flex",
|
|
171
|
+
justifyContent: "space-between",
|
|
172
|
+
width: "100%",
|
|
173
|
+
marginBottom: "8px",
|
|
174
|
+
fontSize: 28,
|
|
175
|
+
},
|
|
176
|
+
children: [
|
|
177
|
+
{
|
|
178
|
+
type: "span",
|
|
179
|
+
props: {
|
|
180
|
+
children: [
|
|
181
|
+
"by ",
|
|
182
|
+
{
|
|
183
|
+
type: "span",
|
|
184
|
+
props: {
|
|
185
|
+
style: { color: "transparent" },
|
|
186
|
+
children: '"',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
type: "span",
|
|
191
|
+
props: {
|
|
192
|
+
style: {
|
|
193
|
+
overflow: "hidden",
|
|
194
|
+
fontWeight: "bold",
|
|
195
|
+
},
|
|
196
|
+
children: post.data.author,
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
type: "span",
|
|
204
|
+
props: {
|
|
205
|
+
style: { overflow: "hidden", fontWeight: "bold" },
|
|
206
|
+
children: SITE.title,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
],
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
width: 1200,
|
|
222
|
+
height: 630,
|
|
223
|
+
embedFont: true,
|
|
224
|
+
fonts: await loadGoogleFonts(
|
|
225
|
+
post.data.title + post.data.author + SITE.title + "by"
|
|
226
|
+
),
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import satori from "satori";
|
|
2
|
+
import { SITE } from "@/config";
|
|
3
|
+
import loadGoogleFonts from "../loadGoogleFont";
|
|
4
|
+
|
|
5
|
+
export default async () => {
|
|
6
|
+
return satori(
|
|
7
|
+
{
|
|
8
|
+
type: "div",
|
|
9
|
+
props: {
|
|
10
|
+
style: {
|
|
11
|
+
background: "#fefbfb",
|
|
12
|
+
width: "100%",
|
|
13
|
+
height: "100%",
|
|
14
|
+
display: "flex",
|
|
15
|
+
alignItems: "center",
|
|
16
|
+
justifyContent: "center",
|
|
17
|
+
},
|
|
18
|
+
children: [
|
|
19
|
+
{
|
|
20
|
+
type: "div",
|
|
21
|
+
props: {
|
|
22
|
+
style: {
|
|
23
|
+
position: "absolute",
|
|
24
|
+
top: "-1px",
|
|
25
|
+
right: "-1px",
|
|
26
|
+
border: "4px solid #000",
|
|
27
|
+
background: "#ecebeb",
|
|
28
|
+
opacity: "0.9",
|
|
29
|
+
borderRadius: "4px",
|
|
30
|
+
display: "flex",
|
|
31
|
+
justifyContent: "center",
|
|
32
|
+
margin: "2.5rem",
|
|
33
|
+
width: "88%",
|
|
34
|
+
height: "80%",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: "div",
|
|
40
|
+
props: {
|
|
41
|
+
style: {
|
|
42
|
+
border: "4px solid #000",
|
|
43
|
+
background: "#fefbfb",
|
|
44
|
+
borderRadius: "4px",
|
|
45
|
+
display: "flex",
|
|
46
|
+
justifyContent: "center",
|
|
47
|
+
margin: "2rem",
|
|
48
|
+
width: "88%",
|
|
49
|
+
height: "80%",
|
|
50
|
+
},
|
|
51
|
+
children: {
|
|
52
|
+
type: "div",
|
|
53
|
+
props: {
|
|
54
|
+
style: {
|
|
55
|
+
display: "flex",
|
|
56
|
+
flexDirection: "column",
|
|
57
|
+
justifyContent: "space-between",
|
|
58
|
+
margin: "20px",
|
|
59
|
+
width: "90%",
|
|
60
|
+
height: "90%",
|
|
61
|
+
},
|
|
62
|
+
children: [
|
|
63
|
+
{
|
|
64
|
+
type: "div",
|
|
65
|
+
props: {
|
|
66
|
+
style: {
|
|
67
|
+
display: "flex",
|
|
68
|
+
flexDirection: "column",
|
|
69
|
+
justifyContent: "center",
|
|
70
|
+
alignItems: "center",
|
|
71
|
+
height: "90%",
|
|
72
|
+
maxHeight: "90%",
|
|
73
|
+
overflow: "hidden",
|
|
74
|
+
textAlign: "center",
|
|
75
|
+
},
|
|
76
|
+
children: [
|
|
77
|
+
{
|
|
78
|
+
type: "p",
|
|
79
|
+
props: {
|
|
80
|
+
style: { fontSize: 72, fontWeight: "bold" },
|
|
81
|
+
children: SITE.title,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
type: "p",
|
|
86
|
+
props: {
|
|
87
|
+
style: { fontSize: 28 },
|
|
88
|
+
children: SITE.desc,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
type: "div",
|
|
96
|
+
props: {
|
|
97
|
+
style: {
|
|
98
|
+
display: "flex",
|
|
99
|
+
justifyContent: "flex-end",
|
|
100
|
+
width: "100%",
|
|
101
|
+
marginBottom: "8px",
|
|
102
|
+
fontSize: 28,
|
|
103
|
+
},
|
|
104
|
+
children: {
|
|
105
|
+
type: "span",
|
|
106
|
+
props: {
|
|
107
|
+
style: { overflow: "hidden", fontWeight: "bold" },
|
|
108
|
+
children: new URL(SITE.website).hostname,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
width: 1200,
|
|
123
|
+
height: 630,
|
|
124
|
+
embedFont: true,
|
|
125
|
+
fonts: await loadGoogleFonts(SITE.title + SITE.desc + SITE.website),
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a path is active (current) relative to the given pathname.
|
|
3
|
+
* Handles trailing slashes and partial path matching for nested routes.
|
|
4
|
+
*/
|
|
5
|
+
export function isPathActive(path: string, pathname: string): boolean {
|
|
6
|
+
const currentPath =
|
|
7
|
+
pathname.endsWith("/") && pathname !== "/"
|
|
8
|
+
? pathname.slice(0, -1)
|
|
9
|
+
: pathname;
|
|
10
|
+
|
|
11
|
+
if (currentPath === path) return true;
|
|
12
|
+
|
|
13
|
+
const currentParts = currentPath.split("/").filter(Boolean);
|
|
14
|
+
const pathParts = path.split("/").filter(Boolean);
|
|
15
|
+
|
|
16
|
+
return currentParts[0] === pathParts[0];
|
|
17
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CollectionEntry } from "astro:content";
|
|
2
|
+
import { SITE } from "@/config";
|
|
3
|
+
|
|
4
|
+
const postFilter = ({ data }: CollectionEntry<"blog">) => {
|
|
5
|
+
const isPublishTimePassed =
|
|
6
|
+
Date.now() >
|
|
7
|
+
new Date(data.pubDatetime).getTime() - SITE.scheduledPostMargin;
|
|
8
|
+
return !data.draft && (import.meta.env.DEV || isPublishTimePassed);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default postFilter;
|