Skip to content
Snippets Groups Projects
nav.ts 3.66 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { RouteLocationNormalizedLoaded, RouteParams, RouteRecordName } from 'vue-router'
    
    import { useI18n } from '@/i18n'
    import { parseISO } from 'date-fns'
    import { ref, shallowReadonly, watch } from 'vue'
    
    import { Show, TimeSlot } from '@/types'
    import { useNavigationContext } from '@/stores/nav'
    
    
    type Route = {
      name: RouteRecordName
      params?: RouteParams
    }
    
    
    type BreadcrumbLabel = { title: string }
    type BreadcrumbLink = BreadcrumbLabel & ({ route: Route } | { link: string })
    export type Breadcrumb = string | BreadcrumbLabel | BreadcrumbLink
    export type BreadcrumbNormalized = { title: string; as: string; attrs: unknown }
    
    
    type MenuItem = {
      title: string
      route: Route
    
      testId?: string
    
      requiresAdmin?: boolean
    }
    
    export type MenuItemCollection = {
      title: string
      items: MenuItem[]
    }
    
    
    type MenuItemCollectionGeneratorOptions = Record<string, unknown> & {
    
      route: RouteLocationNormalizedLoaded
    }
    
    
    type MenuItemCollectionGenerator = (
    
      options: MenuItemCollectionGeneratorOptions,
    
    ) => AsyncGenerator<MenuItemCollection, void, unknown>
    
    async function* getMainNavigation() {
      const { t } = useI18n()
      yield {
    
        title: t('navigation._title'),
    
        items: [
          {
            title: t('navigation.shows'),
            route: { name: 'shows' },
    
            testId: 'nav:shows',
    
          },
          {
            title: t('navigation.filesPlaylists'),
            route: { name: 'files' },
          },
          {
            title: t('navigation.calendar'),
            route: { name: 'calendar' },
    
            testId: 'nav:calendar',
    
    async function* getEpisodeContextMenu(
      options: MenuItemCollectionGeneratorOptions,
    ): AsyncGenerator<MenuItemCollection, void, unknown> {
      if (!('episode' in options) || !options.episode) return
      const episode = options.episode as TimeSlot
    
      const { t, locale } = useI18n()
      const start = parseISO(episode.start).toLocaleString(locale.value, {
        dateStyle: 'short',
        timeStyle: 'short',
      })
    
    
      yield {
        title: t('navigation.episode._title', { start }),
        items: [
          {
    
            title: t('navigation.episode.details'),
    
            route: { name: 'show-episode-details', params: options.route.params },
    
    async function* getShowContextMenu(
      options: MenuItemCollectionGeneratorOptions,
    ): AsyncGenerator<MenuItemCollection, void, unknown> {
      if (!('show' in options) || !options.show) return
      const show = options.show as Show
    
      const { t } = useI18n()
    
      yield {
        title: show.name,
        items: [
          {
            title: t('navigation.show.episodes'),
    
            route: {
              name: 'show-episodes',
              params: { ...options.route.params, showId: show.id.toString() },
            },
    
          },
          {
            title: t('navigation.show.basicData'),
    
            route: {
              name: 'show-basic-data',
              params: { ...options.route.params, showId: show.id.toString() },
            },
    
          },
        ],
      }
    }
    
    function useNavigationData(...menuCollectionGenerators: MenuItemCollectionGenerator[]) {
      const menuItemCollections = ref<MenuItemCollection[]>([])
    
      const navigationContext = useNavigationContext()
    
        async () => {
          const result: MenuItemCollection[] = []
          for (const generator of menuCollectionGenerators) {
            try {
    
              const collections = generator(navigationContext.value)
    
              for await (const collection of collections) {
    
                result.push(collection)
              }
            } catch (e) {
              // pass
            }
          }
          menuItemCollections.value = result
        },
        { immediate: true },
      )
    
      return shallowReadonly(menuItemCollections)
    }
    
    export function useMainNavigationData() {
      return useNavigationData(getMainNavigation, getEpisodeContextMenu, getShowContextMenu)
    }