Navbar

Overview

This component provides a responsive navigation bar for a web application. It includes a logo and navigation links, which adapt for desktop and mobile views. On mobile devices, a burger menu icon allows toggling the visibility of the menu.

Features

  1. Responsive Design: Adapts seamlessly to different screen sizes, ensuring a great user experience across all devices.
  2. Dynamic Navigation Links: Easily configurable links that can be set to highlight the current page, improving user orientation.
  3. Toggleable Mobile Menu: A compact and user-friendly mobile menu that can be expanded or collapsed with a simple click.
  4. Customizable Icons: Leverage icons to represent the mobile menu state, providing a clear visual cue to users.

Usage

To integrate this component into your Nuxt 3 application:

  1. Copy the component code into a new Vue file within your project's components directory.
  2. Ensure you have Tailwind CSS and the required icon libraries configured in your project.
  3. Use the component in your application by importing it in your Nuxt pages.

Customization

  1. Modify the navigationLinks array to include your desired links and routes.
  2. Use custom icons by changing the mobileMenuIcon computed property.
  3. Style the component by adjusting the Tailwind CSS classes as per your design requirements.

Component Details

  • mobileMenuOpen: A reactive variable controlling the visibility of the mobile menu.
  • navigationLinks: An array of objects representing the navigation links. Each object should have name, label, and href properties.
  • navigation: A computed property that dynamically sets the current state of each navigation link based on the current route.
  • mobileMenuIcon: Determines the icon to display based on the mobile menu's state (open or closed).
  • toggleMobileMenu: A function to toggle the state of mobileMenuOpen.

Component Code

<script setup lang="ts">
const mobileMenuOpen = ref(false);

const navigationLinks = [
  { name: 'ui', label: 'UI', href: '' },
  { name: 'projects', label: 'Projects', href: '' },
  { name: 'blog', label: 'Blog', href: '' },
];

const route = useRoute();

const navigation = computed(() => {
  return navigationLinks.map((link) => ({
    ...link,
    current: (route.name as string).includes(link.name),
  }));
});

const mobileMenuIcon = computed(() => {
  return mobileMenuOpen.value
    ? 'solar:close-square-linear'
    : 'solar:menu-dots-square-bold';
});

function toggleMobileMenu() {
  mobileMenuOpen.value = !mobileMenuOpen.value;
}
</script>

<template>
  <div
    class="h-72 w-full overflow-hidden rounded-md border-4 border-black dark:border-primary"
  >
    <nav
      class="top-0 z-20 mx-auto w-full max-w-7xl bg-black duration-700 ease-out dark:bg-primary"
    >
      <div
        class="flex items-center justify-between px-sm py-2 md:px-lg md:py-4 lg:px-0"
      >
        <NuxtLink
          to="/"
          class="flex cursor-pointer items-center text-primary decoration-transparent dark:text-black dark:decoration-transparent"
        >
          <!-- Logo and brand name for all screen sizes -->
          <Icon
            name="mdi:skull-crossbones"
            size="2rem"
          />
          <span class="ml-2 text-3xl font-semibold tracking-tight"
            >Cool Project</span
          >
        </NuxtLink>
        <div class="hidden items-center space-x-4 md:flex">
          <!-- Links for desktop -->
          <div
            v-for="link in navigation"
            :key="link.name"
          >
            <NuxtLink
              :to="link.href"
              class="cursor-pointer rounded-md px-3 py-2 text-base font-normal text-primary decoration-transparent transition-colors duration-150 hover:bg-primary hover:text-black dark:text-black dark:decoration-transparent dark:hover:bg-black dark:hover:text-primary"
              :class="{
                ' border-4 border-primary dark:border-black ': link.current,
              }"
            >
              {{ link.label }}
            </NuxtLink>
          </div>
        </div>

        <!-- Burger icon for mobile -->
        <div class="flex items-center text-primary dark:text-black md:hidden">
          <button @click="toggleMobileMenu()">
            <Icon
              :name="mobileMenuIcon"
              size="2rem"
            />
          </button>
        </div>
      </div>
    </nav>

    <!-- Mobile menu -->
    <div class="flex overflow-hidden">
      <div
        class="left-0 top-0 z-10 w-full transform bg-black text-primary transition-all duration-300 ease-in-out md:hidden"
        :class="{
          '-translate-y-64': !mobileMenuOpen,
          '-translate-y-1': mobileMenuOpen,
        }"
      >
        <div
          v-for="link in navigation"
          :key="link.name"
          class="flex py-2 text-xl"
        >
          <NuxtLink
            :to="link.href"
            class="w-full rounded px-3 py-2 text-primary decoration-transparent dark:text-primary dark:decoration-transparent"
            :class="{ 'border-4 border-primary': link.current }"
          >
            {{ link.label }}
          </NuxtLink>
        </div>
      </div>
      <div
        class="inset-0 transform bg-black bg-opacity-50 transition-all duration-300 ease-in-out"
        :class="{
          '-translate-y-full': !mobileMenuOpen,
          'translate-y': mobileMenuOpen,
        }"
        @click="toggleMobileMenu()"
      ></div>
    </div>
  </div>
</template>