Commit 2675458
Changed files (7)
src
components
i18n
pages
archives
categories
tags
types
utils
src/components/Sidebar.astro
@@ -24,7 +24,11 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
<div id="sidebar-menu-text-items">
{
navbarConfig.navbarCenterItems.map((item) => (
- <Button id="sidebar-menu-item" href={item.href} title={i18n(item.text)}>
+ <Button
+ id="sidebar-menu-item"
+ {...('href' in item && item.href && { href: item.href })}
+ title={i18n(item.text)}
+ >
<span class="text-xl">{i18n(item.text)}</span>
</Button>
))
@@ -35,9 +39,10 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
navbarConfig.navbarRightItems.onlyWide.map((item) => (
<Button
id="sidebar-menu-item"
- href={item.href}
+ {...('href' in item && item.href && { href: item.href })}
title={i18n(item.text)}
- {...(item.onclick &&
+ {...('onclick' in item &&
+ item.onclick &&
(typeof item.onclick === 'string'
? { onclick: item.onclick }
: { id: 'side-' + item.onclick.id }))}
@@ -87,7 +92,7 @@ import DarkModeButton from './widgets/DarkModeButton.astro';
document.addEventListener('astro:page-load', () => {
rightItems.forEach((item) => {
- if (item.onclick && typeof item.onclick !== 'string') {
+ if ('onclick' in item && item.onclick && typeof item.onclick !== 'string') {
const element = document.getElementById('side-' + item.onclick.id);
if (element) element.addEventListener('click', item.onclick.function);
}
src/i18n/translation.ts
@@ -23,7 +23,8 @@ export function getTranslation(lang: string): Translation {
return map[lang.toLowerCase()] || defaultTranslation;
}
-export function i18n(key: I18nKey | string): string {
+export function i18n(key: I18nKey | string | undefined): string | undefined {
+ if (typeof key === 'undefined') return undefined;
const lang = siteConfig.lang || 'en';
const translate = getTranslation(lang);
return key in I18nKey ? translate[key as I18nKey] : key;
src/pages/archives/categories/index.astro
@@ -19,7 +19,7 @@ categories.forEach((category) => {
});
const uncategorizedPosts = allPosts.filter((post) => !post.data.category).slice(0, 3);
if (uncategorizedPosts.length > 0)
- categoryPosts.set(i18n(I18nKey.uncategorized), uncategorizedPosts);
+ categoryPosts.set(i18n(I18nKey.uncategorized) as string, uncategorizedPosts);
---
<MainLayout title={i18n(I18nKey.categories)}>
src/types/config.ts
@@ -1,52 +1,74 @@
import type I18nKey from '@i18n/I18nKey';
-export type ButtonSubConfig = (
- | {
- /**
- * The icon of the button. Should be a name of iconify icon.
- *
- * 按钮的图标。应该是一个 iconify 图标的名称。
- */
- icon: string;
- /**
- * The text of the button.
- *
- * 按钮的文本。
- */
- text?: string | I18nKey;
- }
- | {
+export type ButtonSubConfig<T extends string> = T extends 'text'
+ ? {
/**
* The text of the button.
*
* 按钮的文本。
*/
text: string | I18nKey;
- }
-) &
- (
- | {
+ } & (
+ | {
+ /**
+ * The URL of the button.
+ *
+ * 按钮的 URL。
+ */
+ href?: string;
+ }
+ | {
+ /**
+ * The function to be called when the button is clicked.
+ *
+ * 当按钮被点击时要调用的函数。
+ */
+ onclick?:
+ | string
+ | {
+ id: string;
+ function: (this: HTMLElement, ev: MouseEvent) => unknown;
+ };
+ }
+ )
+ : T extends 'icon'
+ ? {
/**
- * The URL of the button.
+ * The icon of the button. Should be a name of iconify icon.
*
- * 按钮的 URL。
+ * 按钮的图标。应该是一个 iconify 图标的名称。
*/
- href?: string;
- }
- | {
+ icon: string;
/**
- * The function to be called when the button is clicked.
+ * The text of the button.
*
- * 当按钮被点击时要调用的函数。
+ * 按钮的文本。
*/
- onclick?:
- | string
- | {
- id: string;
- function: (this: HTMLElement, ev: MouseEvent) => unknown;
- };
- }
- );
+ text?: string | I18nKey;
+ } & (
+ | {
+ /**
+ * The URL of the button.
+ *
+ * 按钮的 URL。
+ */
+ href?: string;
+ }
+ | {
+ /**
+ * The function to be called when the button is clicked.
+ *
+ * 当按钮被点击时要调用的函数。
+ */
+ onclick?:
+ | string
+ | {
+ id: string;
+ function: (this: HTMLElement, ev: MouseEvent) => unknown;
+ };
+ }
+ )
+ : never;
export type SiteConfig = {
/**
@@ -133,7 +155,7 @@ export type NavbarConfig = {
*
* 在导航栏中间显示的项目。
*/
- navbarCenterItems: { text: string | I18nKey; href?: string }[];
+ navbarCenterItems: ButtonSubConfig<'text'>[];
/**
* The items displayed in the right of the navbar.
*
@@ -145,13 +167,13 @@ export type NavbarConfig = {
*
* 仅在宽屏幕(大于 768px)显示的项目。
*/
- onlyWide: ButtonSubConfig[];
+ onlyWide: ButtonSubConfig<'icon'>[];
/**
* The items displayed always.
*
* 总是显示的项目。
*/
- always: ButtonSubConfig[];
+ always: ButtonSubConfig<'icon'>[];
};
};
@@ -167,7 +189,7 @@ export type ToolBarConfig = {
*
* 在侧边工具栏中显示的项目。
*/
- items: ButtonSubConfig[];
+ items: ButtonSubConfig<'icon'>[];
};
export type LicenseConfig = {
@@ -254,12 +276,14 @@ export type ArticleConfig = {
};
export type SearchConfig = {
- /** Whether to enable search.
+ /**
+ * Whether to enable search.
*
* 是否启用搜索。
*/
enable: boolean;
- /** `'pagefind'` | `'algolia'`.
+ /**
+ * `'pagefind'` | `'algolia'`.
*
* Algolia is not implemented yet, just a placeholder. Please use Pagefind.
*
src/utils/content-utils.ts
@@ -21,7 +21,9 @@ export async function getSortedPosts(): Promise<{ body: string; data: BlogPostDa
export async function getCategories(): Promise<string[]> {
const allBlogPosts = await getSortedPosts();
const categories = [
- ...new Set(allBlogPosts.map((post) => post.data.category || i18n(I18nKey.uncategorized))),
+ ...new Set(
+ allBlogPosts.map((post) => post.data.category || (i18n(I18nKey.uncategorized) as string))
+ ),
];
return categories;
}
@@ -48,7 +50,6 @@ export async function getTimeArchives() {
monthPosts = [];
monthMap.set(month, monthPosts);
}
-
monthPosts.push(post);
}
return Array.from(yearMap.entries())