Newer
Older
bugtrail / packages / web / src / components / AppShell.vue
<script setup lang="ts">
import { computed } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { GnAvatar, GnButton, GnNavigationShell } from "gnexus-ui-kit/vue";
import { useAuth } from "../stores/auth";

const auth = useAuth();
const router = useRouter();
const route = useRoute();
const { t } = useI18n();

const items = computed(() => [
  { id: "projects", label: t("nav.projects"), icon: "ph-folders", to: "/" },
  { id: "settings", label: t("nav.settings"), icon: "ph-gear", to: "/settings" },
]);

async function onSelect(item: { to?: string }) {
  if (item.to) router.push(item.to);
}

async function logout() {
  await auth.logout();
  router.push("/login");
}
</script>

<template>
  <GnNavigationShell brand="Live Testing Tool" :items="items" @select="onSelect">
    <!-- the kit renders this slot in a chip in the topbar's right corner;
         an identity chip beats an empty "current section" box -->
    <template #current>
      <div v-if="auth.user.value" class="shell-user">
        <GnAvatar :name="auth.user.value.nickname" size="sm" />
        <span class="shell-user-name">{{ auth.user.value.nickname }}</span>
        <button
          type="button"
          class="shell-user-logout"
          :title="t('nav.logout')"
          @click="logout"
        >
          <i class="ph ph-sign-out" />
        </button>
      </div>
      <span v-else class="shell-user-name">{{ t("common.loading") }}</span>
    </template>
    <template #content>
      <div class="shell-body">
        <slot />
      </div>
    </template>
    <template #footer>
      <div class="shell-footer">
        <GnAvatar v-if="auth.user.value" :name="auth.user.value.nickname" size="sm" />
        <span class="shell-footer-user">{{ auth.user.value?.nickname }}</span>
        <GnButton variant="secondary" size="sm" icon="ph-sign-out" @click="logout">
          {{ t("nav.logout") }}
        </GnButton>
      </div>
    </template>
  </GnNavigationShell>
</template>

<style scoped>
.shell-body {
  max-width: 1100px;
  margin: 0 auto;
  padding: 20px 24px 60px;
  width: 100%;
}
.shell-user {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.shell-user-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.shell-user-logout {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--ltt-text-dim, #787c99);
  font-size: 16px;
  cursor: pointer;
  transition: color 0.15s ease;
}
.shell-user-logout:hover {
  color: var(--ltt-danger, #f7768e);
}
.shell-footer {
  display: flex;
  align-items: center;
  gap: 10px;
}
.shell-footer-user {
  font-size: 12px;
  opacity: 0.8;
  margin-right: auto;
}
</style>