default.vue 6.03 KB
<script setup lang="ts">
import type { CommandPaletteItem, NavigationMenuItem } from '@nuxt/ui'

const toast = useToast()
const { t } = useAppI18n()
const { canAccessPage } = usePermission()

const open = ref(false)

const settingsChildren = computed<NavigationMenuItem[]>(() => {
  return [{
    label: t('layout.nav.general'),
    to: '/settings',
    exact: true,
    onSelect: () => {
      open.value = false
    }
  }, {
    label: t('layout.nav.members'),
    to: '/settings/members',
    onSelect: () => {
      open.value = false
    }
  }, {
    label: t('layout.nav.notifications'),
    to: '/settings/notifications',
    onSelect: () => {
      open.value = false
    }
  }, {
    label: t('layout.nav.security'),
    to: '/settings/security',
    onSelect: () => {
      open.value = false
    }
  }].filter((item) => {
    return typeof item.to === 'string' ? canAccessPage(item.to) : true
  })
})

const baseInfoChildren = computed<NavigationMenuItem[]>(() => {
  return [{
    label: t('layout.nav.deviceTypes'),
    to: '/base-info/device-types',
    onSelect: () => {
      open.value = false
    }
  }].filter((item) => {
    return typeof item.to === 'string' ? canAccessPage(item.to) : true
  })
})

const productionChildren = computed<NavigationMenuItem[]>(() => {
  return [{
    label: t('layout.nav.workOrders'),
    to: '/work-orders',
    onSelect: () => {
      open.value = false
    }
  }, {
    label: t('layout.nav.snManagement'),
    to: '/sn-management',
    onSelect: () => {
      open.value = false
    }
  }, {
    label: t('layout.nav.operations'),
    to: '/operations',
    onSelect: () => {
      open.value = false
    }
  }].filter((item) => {
    return typeof item.to === 'string' ? canAccessPage(item.to) : true
  })
})

const links = computed<NavigationMenuItem[][]>(() => {
  const primary: NavigationMenuItem[] = []

  if (canAccessPage('/')) {
    primary.push({
      label: t('layout.nav.home'),
      icon: 'i-lucide-house',
      to: '/',
      onSelect: () => {
        open.value = false
      }
    })
  }

  if (productionChildren.value.length > 0) {
    primary.push({
      label: t('layout.nav.production'),
      to: canAccessPage('/work-orders')
        ? '/work-orders'
        : (productionChildren.value[0]?.to as string),
      icon: 'i-lucide-factory',
      defaultOpen: true,
      type: 'trigger',
      children: productionChildren.value
    })
  }

  if (canAccessPage('/customers')) {
    primary.push({
      label: t('layout.nav.customers'),
      icon: 'i-lucide-users',
      to: '/customers',
      onSelect: () => {
        open.value = false
      }
    })
  }

  if (baseInfoChildren.value.length > 0) {
    primary.push({
      label: t('layout.nav.baseInfo'),
      to: canAccessPage('/base-info/device-types') ? '/base-info/device-types' : (baseInfoChildren.value[0]?.to as string),
      icon: 'i-lucide-box',
      defaultOpen: true,
      type: 'trigger',
      children: baseInfoChildren.value
    })
  }

  if (settingsChildren.value.length > 0) {
    primary.push({
      label: t('layout.nav.settings'),
      to: canAccessPage('/settings') ? '/settings' : (settingsChildren.value[0]?.to as string),
      icon: 'i-lucide-settings',
      defaultOpen: true,
      type: 'trigger',
      children: settingsChildren.value
    })
  }

  return [primary, [
  // {
  //   label: t('layout.nav.feedback'),
  //   icon: 'i-lucide-message-circle',
  //   to: 'https://github.com/nuxt-ui-templates/dashboard',
  //   target: '_blank'
  // },
  // {
  //   label: t('layout.nav.helpSupport'),
  //   icon: 'i-lucide-info',
  //   to: 'https://github.com/nuxt-ui-templates/dashboard',
  //   target: '_blank'
  // }
  ]]
})

function collectSearchItems(items: NavigationMenuItem[]): CommandPaletteItem[] {
  return items.flatMap((item) => {
    const result: CommandPaletteItem[] = []

    if (typeof item.to === 'string') {
      result.push(item as CommandPaletteItem)
    }

    if (Array.isArray(item.children)) {
      result.push(...collectSearchItems(item.children))
    }

    return result
  })
}

const groups = computed(() => [{
  id: 'links',
  label: t('layout.search.goTo'),
  items: collectSearchItems(links.value.flat()) as CommandPaletteItem[]
}
// {
//   id: 'code',
//   label: t('layout.search.code'),
//   items: [{
//     id: 'source',
//     label: t('layout.search.viewPageSource'),
//     icon: 'i-simple-icons-github',
//     to: `https://github.com/nuxt-ui-templates/dashboard/blob/main/app/pages${route.path === '/' ? '/index' : route.path}.vue`,
//     target: '_blank'
//   }]
// }
])

onMounted(async () => {
  const cookie = useCookie('cookie-consent')
  if (cookie.value === 'accepted') {
    return
  }

  toast.add({
    title: t('layout.cookie.title'),
    duration: 0,
    close: false,
    actions: [{
      label: t('common.accept'),
      color: 'neutral',
      variant: 'outline',
      onClick: () => {
        cookie.value = 'accepted'
      }
    }, {
      label: t('common.optOut'),
      color: 'neutral',
      variant: 'ghost'
    }]
  })
})
</script>

<template>
  <UDashboardGroup unit="rem">
    <UDashboardSidebar
      id="default"
      v-model:open="open"
      collapsible
      resizable
      class="bg-elevated/25"
      :ui="{ footer: 'lg:border-t lg:border-default' }"
    >
      <template #header="{ collapsed }">
        <TeamsMenu :collapsed="collapsed" />
      </template>

      <template #default="{ collapsed }">
        <UDashboardSearchButton :collapsed="collapsed" class="bg-transparent ring-default" />

        <UNavigationMenu
          :collapsed="collapsed"
          :items="links[0]"
          orientation="vertical"
          tooltip
          popover
        />

        <UNavigationMenu
          :collapsed="collapsed"
          :items="links[1]"
          orientation="vertical"
          tooltip
          class="mt-auto"
        />
      </template>

      <template #footer="{ collapsed }">
        <UserMenu :collapsed="collapsed" />
      </template>
    </UDashboardSidebar>

    <UDashboardSearch :groups="groups" />

    <slot />

    <NotificationsSlideover />
  </UDashboardGroup>
</template>