master
  1---
  2import { navbarConfig, siteConfig } from '@/config';
  3import { t } from '@utils/i18n';
  4import { Icon } from 'astro-icon/components';
  5import Button from './widgets/Button.astro';
  6import DarkModeButton from './widgets/DarkModeButton.astro';
  7
  8interface Props {
  9  title?: string;
 10  lang?: string;
 11}
 12let { title } = Astro.props;
 13if (!title) title = 'Astral Halo';
 14
 15const drawerItemClass =
 16  'is-drawer-open:opacity-100 is-drawer-open:translate-x-0 translate-x-5 opacity-0 duration-150';
 17---
 18
 19<div class="drawer drawer-end">
 20  <input id="sidebar-drawer" type="checkbox" class="drawer-toggle" />
 21  <div class="drawer-content flex flex-col">
 22    <!-- Navbar -->
 23    <div
 24      id="navbar"
 25      class="navbar bg-base-200/50 fixed z-20 flex h-16 w-full items-center backdrop-blur-md"
 26    >
 27      <div class="navbar-start">
 28        <Button
 29          id="site-name"
 30          href="/"
 31          class="group btn-ghost btn-accent not-hover:text-base-content"
 32        >
 33          <span class="text-xl font-bold duration-300 group-hover:opacity-0">{title}</span>
 34          <Icon
 35            name="material-symbols:home-rounded"
 36            class="absolute text-3xl opacity-0 duration-300 group-hover:opacity-100"
 37          />
 38        </Button>
 39      </div>
 40      <nav class="join navbar-center max-md:hidden">
 41        {
 42          navbarConfig.navbarCenterItems.map((item) => {
 43            if ('items' in item) {
 44              return (
 45                <div class="dropdown dropdown-center dropdown-hover">
 46                  <Button
 47                    title={item.title}
 48                    class="btn-ghost join-item btn-primary not-hover:text-base-content"
 49                  >
 50                    <span class="text-xl tracking-wide">{item.title}</span>
 51                  </Button>
 52                  <ul class="menu bg-base-200/50 dropdown-content absolute rounded-xl shadow">
 53                    {item.items.map((subItem) => (
 54                      <Button
 55                        {...('href' in subItem &&
 56                          subItem.href && {
 57                            href: subItem.href,
 58                            target: subItem.blank ? '_blank' : undefined,
 59                          })}
 60                        {...('onclick' in subItem &&
 61                          subItem.onclick &&
 62                          (typeof subItem.onclick === 'string'
 63                            ? { onclick: subItem.onclick }
 64                            : { id: 'nav-' + subItem.onclick.id }))}
 65                        {...(subItem.extraAttr || {})}
 66                        title={subItem.text}
 67                        aria-label={subItem.text}
 68                        class="btn-ghost btn-primary not-hover:text-base-content rounded-field"
 69                      >
 70                        <span class="text-xl tracking-wide text-nowrap">{subItem.text}</span>
 71                      </Button>
 72                    ))}
 73                  </ul>
 74                </div>
 75              );
 76            } else {
 77              return (
 78                <Button
 79                  {...('href' in item &&
 80                    item.href && {
 81                      href: item.href,
 82                      target: item.blank ? '_blank' : undefined,
 83                    })}
 84                  {...('onclick' in item &&
 85                    item.onclick &&
 86                    (typeof item.onclick === 'string'
 87                      ? { onclick: item.onclick }
 88                      : { id: 'nav-' + item.onclick.id }))}
 89                  {...(item.extraAttr || {})}
 90                  title={item.text}
 91                  aria-label={item.text}
 92                  class="btn-ghost join-item btn-primary not-hover:text-base-content"
 93                >
 94                  <span class="text-xl tracking-wide">{item.text}</span>
 95                </Button>
 96              );
 97            }
 98          })
 99        }
100      </nav>
101      <div class="navbar-end">
102        <div class="flex max-md:hidden">
103          {
104            navbarConfig.navbarRightItems.onlyWide.map((item) => (
105              <Button
106                class="nav-menu-item btn-circle btn-ghost btn-primary not-hover:text-base-content"
107                {...('href' in item &&
108                  item.href && { href: item.href, target: item.blank ? '_blank' : undefined })}
109                title={item.text}
110                aria-label={item.text}
111                {...('onclick' in item &&
112                  item.onclick &&
113                  (typeof item.onclick === 'string'
114                    ? { onclick: item.onclick }
115                    : { id: 'nav-' + item.onclick.id }))}
116                {...(item.extraAttr || {})}
117              >
118                <Icon name={item.icon} height="1.5rem" width="1.5rem" />
119              </Button>
120            ))
121          }
122        </div>
123        <div class="flex">
124          {
125            navbarConfig.navbarRightItems.always.map((item) => (
126              <Button
127                class="nav-menu-item btn-circle btn-ghost btn-primary not-hover:text-base-content"
128                {...('href' in item &&
129                  item.href && { href: item.href, target: item.blank ? '_blank' : undefined })}
130                title={item.text}
131                aria-label={item.text}
132                {...('onclick' in item &&
133                  item.onclick &&
134                  (typeof item.onclick === 'string'
135                    ? { onclick: item.onclick }
136                    : { id: 'nav-' + item.onclick.id }))}
137                {...(item.extraAttr || {})}
138              >
139                <Icon name={item.icon} height="1.5rem" width="1.5rem" />
140              </Button>
141            ))
142          }
143        </div>
144        <div class="md:hidden">
145          <label
146            for="sidebar-drawer"
147            class="btn btn-circle btn-ghost btn-primary not-hover:text-base-content"
148            tabindex="0"
149            title={t.info.openMenu()}
150            aria-label={t.info.openMenu()}
151          >
152            <Icon name="material-symbols:menu-rounded" height="1.5rem" width="1.5rem" />
153          </label>
154        </div>
155      </div>
156    </div>
157    {siteConfig.banner === false && <div id="navbar-placeholder" class="pt-20" />}
158    <!-- Page Content -->
159    <slot />
160  </div>
161  <div class="drawer-side z-50">
162    <!-- Sidebar -->
163    <label
164      for="sidebar-drawer"
165      class="drawer-overlay"
166      title={t.info.closeMenu()}
167      aria-label={t.info.closeMenu()}></label>
168    <ul
169      role="navigation"
170      class="menu from-base-100 to-base-300 dark:from-base-300 dark:to-base-100 min-h-full w-[min(calc(100%-3rem),20rem)] bg-linear-150 p-4"
171    >
172      <li>
173        <DarkModeButton class="text-xl" showText={true} useDefaultBtnClass={false} />
174      </li>
175      <div class="divider text-lg font-bold">{t.navigation.menu()}</div>
176      {
177        navbarConfig.navbarCenterItems.map((item, index) => {
178          if ('items' in item) {
179            return (
180              <li class={drawerItemClass} style={`transition-delay: ${(index + 1) * 75}ms`}>
181                <details>
182                  <summary class="text-xl">{item.title}</summary>
183                  <ul>
184                    {item.items.map((subItem) => (
185                      <li>
186                        <Button
187                          {...('href' in subItem &&
188                            subItem.href && {
189                              href: subItem.href,
190                              target: subItem.blank ? '_blank' : undefined,
191                            })}
192                          {...('onclick' in subItem &&
193                            subItem.onclick &&
194                            (typeof subItem.onclick === 'string'
195                              ? { onclick: subItem.onclick }
196                              : { id: 'side-' + subItem.onclick.id }))}
197                          {...(subItem.extraAttr || {})}
198                          title={subItem.text}
199                          aria-label={subItem.text}
200                          useDefaultClass={false}
201                        >
202                          <span class="text-xl">{subItem.text}</span>
203                        </Button>
204                      </li>
205                    ))}
206                  </ul>
207                </details>
208              </li>
209            );
210          } else {
211            return (
212              <li class={drawerItemClass} style={`transition-delay: ${(index + 1) * 75}ms`}>
213                <Button
214                  {...('href' in item &&
215                    item.href && {
216                      href: item.href,
217                      target: item.blank ? '_blank' : undefined,
218                    })}
219                  {...('onclick' in item &&
220                    item.onclick &&
221                    (typeof item.onclick === 'string'
222                      ? { onclick: item.onclick }
223                      : { id: 'side-' + item.onclick.id }))}
224                  {...(item.extraAttr || {})}
225                  title={item.text}
226                  aria-label={item.text}
227                  useDefaultClass={false}
228                >
229                  <span class="text-xl">{item.text}</span>
230                </Button>
231              </li>
232            );
233          }
234        })
235      }
236      {
237        navbarConfig.navbarRightItems.onlyWide.map((item, index) => (
238          <li
239            class={drawerItemClass}
240            style={`transition-delay: ${(index + navbarConfig.navbarCenterItems.length + 1) * 75}ms`}
241          >
242            <Button
243              {...('href' in item &&
244                item.href && { href: item.href, target: item.blank ? '_blank' : undefined })}
245              title={item.text}
246              aria-label={item.text}
247              {...('onclick' in item &&
248                item.onclick &&
249                (typeof item.onclick === 'string'
250                  ? { onclick: item.onclick }
251                  : { id: 'side-' + item.onclick.id }))}
252              {...(item.extraAttr || {})}
253              useDefaultClass={false}
254            >
255              <Icon name={item.icon} height="1.5rem" width="1.5rem" />
256              <span class="text-xl">{item.text}</span>
257            </Button>
258          </li>
259        ))
260      }
261    </ul>
262  </div>
263</div>
264
265<script>
266  import { navbarConfig } from '@/config';
267  const rightItems = [
268    navbarConfig.navbarRightItems.onlyWide,
269    navbarConfig.navbarRightItems.always,
270  ].flat();
271
272  function setup() {
273    rightItems.forEach((item) => {
274      if ('onclick' in item && item.onclick && typeof item.onclick !== 'string') {
275        const navEl = document.getElementById('nav-' + item.onclick.id);
276        if (navEl) navEl.addEventListener('click', item.onclick.function);
277        const sideEl = document.getElementById('side-' + item.onclick.id);
278        if (sideEl) sideEl.addEventListener('click', item.onclick.function);
279      }
280    });
281  }
282
283  setup();
284  document.addEventListener('astro:page-load', setup);
285</script>