Commit 2675458

HPCesia <me@hpcesia.com>
2025-02-01 11:02:22
fix: bug after add doc comment
1 parent 7e0340d
Changed files (7)
src/components/Navbar.astro
@@ -25,7 +25,11 @@ if (!title) title = 'Astral Halo';
   <div id="nav-center" class="m-auto flex w-fit max-md:hidden">
     {
       navbarConfig.navbarCenterItems.map((item) => (
-        <Button href={item.href} title={i18n(item.text)} class="!px-4">
+        <Button
+          {...('href' in item && item.href && { href: item.href })}
+          title={i18n(item.text)}
+          class="!px-4"
+        >
           <span class="text-xl tracking-wide">{i18n(item.text)}</span>
         </Button>
       ))
@@ -37,9 +41,10 @@ if (!title) title = 'Astral Halo';
         navbarConfig.navbarRightItems.onlyWide.map((item) => (
           <Button
             class="nav-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: 'nav-' + item.onclick.id }))}
@@ -54,9 +59,10 @@ if (!title) title = 'Astral Halo';
         navbarConfig.navbarRightItems.always.map((item) => (
           <Button
             class="nav-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: 'nav-' + item.onclick.id }))}
@@ -84,7 +90,7 @@ if (!title) title = 'Astral Halo';
 
   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('nav-' + item.onclick.id);
         if (element) element.addEventListener('click', item.onclick.function);
       }
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/pages/archives/tags/index.astro
@@ -20,7 +20,7 @@ tags.forEach((tag) => {
 const untaggedPosts = allPosts
   .filter((post) => !post.data.tags || post.data.tags.length === 0)
   .slice(0, 3);
-if (untaggedPosts.length > 0) tagPosts.set(i18n(I18nKey.untagged), untaggedPosts);
+if (untaggedPosts.length > 0) tagPosts.set(i18n(I18nKey.untagged) as string, untaggedPosts);
 ---
 
 <MainLayout title={i18n(I18nKey.tags)}>
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())