internal/dashboard/frontend/src/components/TopBar.vue

<script setup lang="ts">
import { IconLogout } from "@tabler/icons-vue";
import { icons } from "utils/icons";
import { useRouter } from "vue-router";
import { useAuthStore } from "../store";

const version = __APP_VERSION__;
const authStore = useAuthStore();
const router = useRouter();

const handleLogout = async () => {
  await authStore.logout();
  router.push("/login");
};
</script>

<template>
  <div class="topbar-grid">
    <div
      class="version-tag flex items-center gap-4 justify-self-end [grid-area:version]"
    >
      <button
        v-if="authStore.authenticated"
        @click="handleLogout"
        class="text-muted flex items-center gap-1 text-sm hover:text-stone-200"
        title="Logout"
      >
        <IconLogout size="1.2em" /> Logout
      </button>
      <span class="text-muted text-sm">v{{ version }}</span>
    </div>
    <router-link to="/">
      <h1
        class="dashboard-title from-primary-400 to-primary-600 bg-linear-to-br bg-clip-text pr-1 text-2xl font-medium tracking-tight text-transparent uppercase"
      >
        <strong class="font-sans">Honey</strong><em class="font-mono">pie</em>
      </h1>
    </router-link>
    <div
      class="links-row flex flex-wrap gap-4"
      v-if="!(authStore.authRequired && !authStore.authenticated)"
    >
      <RouterLink to="/" class="hidden md:flex">
        <component :is="icons.dashboard" size="1.25em" />
        Home
      </RouterLink>
      <RouterLink to="/events" class="flex">
        <component :is="icons.log" size="1.25em" />
        Events
      </RouterLink>
      <RouterLink to="/charts" class="flex">
        <component :is="icons.chart" size="1.25em" />
        Chart
      </RouterLink>
      <RouterLink to="/stats" class="flex">
        <component :is="icons.stat" size="1.25em" />
        Stats
      </RouterLink>
    </div>
  </div>
</template>

<style>
@reference "src/style.css";

.topbar-grid {
  @apply mt-4 mb-2 grid items-center gap-2 px-6;
  @apply grid-cols-[1fr_max-content] [grid-template-areas:'title_version'_'links_links'];
  @apply md:grid-cols-[max-content_1fr_max-content] md:gap-x-6 md:gap-y-0 md:[grid-template-areas:'title_links_version'];

  .version-tag {
    @apply justify-self-end [grid-area:version] md:items-center;
  }

  .dashboard-title {
    @apply [grid-area:title] md:items-center;
  }

  .links-row {
    @apply [grid-area:links] md:items-center md:justify-self-start;
  }

  a {
    @apply items-center gap-2 font-medium whitespace-nowrap text-stone-400 no-underline hover:text-stone-200;

    &.router-link-active {
      @apply text-stone-200;

      svg {
        @apply text-primary-300;
      }
    }
  }
}
</style>