Commit 04f98cf

HPCesia <me@hpcesia.com>
2025-02-15 13:11:46
feat: nav group
Add a new feature to the nav group, which is a collection of nav items. In wide viewports, the nav group is displayed as a dropdown menu when the user hover over the nav group title. In narrow viewports, the nav group is displayed as a submenu in drawer menu when the user click on the nav group title.
1 parent 18ec32c
Changed files (2)
src
src/components/Navbar.astro
@@ -32,15 +32,41 @@ if (!title) title = 'Astral Halo';
       </div>
       <nav class="join navbar-center max-md:hidden">
         {
-          navbarConfig.navbarCenterItems.map((item) => (
-            <Button
-              {...('href' in item && item.href && { href: item.href })}
-              title={i18n(item.text)}
-              class="btn-ghost join-item btn-primary"
-            >
-              <span class="text-xl tracking-wide">{i18n(item.text)}</span>
-            </Button>
-          ))
+          navbarConfig.navbarCenterItems.map((item) => {
+            if ('items' in item) {
+              return (
+                <Button
+                  title={i18n(item.title)}
+                  class="btn-ghost join-item btn-primary group flex flex-col gap-0"
+                >
+                  <span class="text-xl tracking-wide">{i18n(item.title)}</span>
+                  <div class="hidden h-0 w-0 self-center group-hover:block">
+                    <ul class="menu bg-base-200/50 absolute -translate-x-[50%] translate-y-1.5 rounded-xl shadow backdrop-blur-md">
+                      {item.items.map((subItem) => (
+                        <Button
+                          {...('href' in subItem && subItem.href && { href: subItem.href })}
+                          title={i18n(subItem.text)}
+                          class="btn-ghost"
+                        >
+                          <span class="text-xl tracking-wide">{i18n(subItem.text)}</span>
+                        </Button>
+                      ))}
+                    </ul>
+                  </div>
+                </Button>
+              );
+            } else {
+              return (
+                <Button
+                  {...('href' in item && item.href && { href: item.href })}
+                  title={i18n(item.text)}
+                  class="btn-ghost join-item btn-primary"
+                >
+                  <span class="text-xl tracking-wide">{i18n(item.text)}</span>
+                </Button>
+              );
+            }
+          })
         }
       </nav>
       <div class="navbar-end">
@@ -97,17 +123,42 @@ if (!title) title = 'Astral Halo';
     <ul class="menu bg-base-200 min-h-full w-[min(calc(100%-3rem),20rem)] p-4">
       <li><DarkModeButton class="btn-ghost text-xl" showText={true} /></li>
       {
-        navbarConfig.navbarCenterItems.map((item) => (
-          <li>
-            <Button
-              {...('href' in item && item.href && { href: item.href })}
-              title={i18n(item.text)}
-              class="btn-ghost"
-            >
-              <span class="text-xl">{i18n(item.text)}</span>
-            </Button>
-          </li>
-        ))
+        navbarConfig.navbarCenterItems.map((item) => {
+          if ('items' in item) {
+            return (
+              <li>
+                <details>
+                  <summary class="justify-center text-xl font-bold">{item.title}</summary>
+                  <ul>
+                    {item.items.map((subItem) => (
+                      <li>
+                        <Button
+                          {...('href' in subItem && subItem.href && { href: subItem.href })}
+                          title={i18n(subItem.text)}
+                          class="btn-ghost"
+                        >
+                          <span class="text-xl">{i18n(subItem.text)}</span>
+                        </Button>
+                      </li>
+                    ))}
+                  </ul>
+                </details>
+              </li>
+            );
+          } else {
+            return (
+              <li>
+                <Button
+                  {...('href' in item && item.href && { href: item.href })}
+                  title={i18n(item.text)}
+                  class="btn-ghost"
+                >
+                  <span class="text-xl">{i18n(item.text)}</span>
+                </Button>
+              </li>
+            );
+          }
+        })
       }
       {
         navbarConfig.navbarRightItems.onlyWide.map((item) => (
src/types/config.ts
@@ -231,7 +231,23 @@ export type NavbarConfig = {
    *
    * 在导航栏中间显示的项目。
    */
-  navbarCenterItems: ButtonSubConfig<'text'>[];
+  navbarCenterItems: (
+    | ButtonSubConfig<'text'>
+    | {
+        /**
+         * The title of the group.
+         *
+         * 组的标题。
+         */
+        title: string | I18nKey;
+        /**
+         * The items displayed in the group.
+         *
+         * 在组中显示的项目。
+         */
+        items: ButtonSubConfig<'text'>[];
+      }
+  )[];
   /**
    * The items displayed in the right of the navbar.
    *