<template> <div class="tw-flex tw-items-center tw-gap-2 tw-text-gray-500 tw-select-none tw-bg-gray-50 tw-p-2" > <template v-for="(crumb, index) in normalizedBreadcrumbs" :key="index"> <icon-system-uicons-chevron-right v-if="index > 0" class="tw-text-gray-300 -tw-mx-1 tw-flex-none" /> <component :is="crumb.as" v-bind="crumb.attrs" class="tw-inline-flex tw-gap-2 tw-items-center tw-text-inherit tw-min-w-0 tw-shrink last:tw-shrink-0" :title="sanitizeHTML(crumb.title)" > <icon-system-uicons-home-alt v-if="index === 0" class="tw-flex-none" /> <SafeHTML :html="crumb.title" class="tw-truncate" /> </component> </template> </div> </template> <script lang="ts" setup> import { computed } from 'vue' import { sanitizeHTML } from '@/util' import { Breadcrumb, BreadcrumbNormalized } from '@/components/nav/nav' import SafeHTML from '@/components/generic/SafeHTML' const props = defineProps<{ breadcrumbs: Breadcrumb[] }>() const normalizedBreadcrumbs = computed<BreadcrumbNormalized[]>(() => { const defaultInteractiveAttrs = { class: 'tw-cursor-pointer' } return props.breadcrumbs.flatMap((crumb) => { if (typeof crumb === 'string') { return { title: crumb, as: 'span', attrs: { class: 'tw-cursor-default' } } } else if ('route' in crumb) { return { title: crumb.title, as: 'router-link', attrs: { ...defaultInteractiveAttrs, to: crumb.route }, } } else if ('link' in crumb) { return { title: crumb.title, as: 'a', attrs: { ...defaultInteractiveAttrs, href: crumb.link }, } } else { return [] } }) }) </script>