Newer
Older
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
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 {
items: [
{
title: t('navigation.shows'),
route: { name: 'shows' },
},
{
title: t('navigation.filesPlaylists'),
route: { name: 'files' },
},
{
title: t('navigation.calendar'),
route: { name: '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)
}