|
1 | 1 | <script setup lang="ts">
|
2 |
| -const { page } = useContent() |
| 2 | +import type { NavItem, ParsedContent } from '@nuxt/content/dist/runtime/types' |
| 3 | +
|
| 4 | +const { |
| 5 | + navigation, |
| 6 | + page, |
| 7 | + next, |
| 8 | + prev, |
| 9 | +} = useContent() as { |
| 10 | + navigation: Ref<NavItem[]> |
| 11 | + page: Ref<ParsedContent> |
| 12 | + next: Ref<ParsedContent | undefined> |
| 13 | + prev: Ref<ParsedContent | undefined> |
| 14 | +} |
| 15 | +
|
| 16 | +interface BreadcrumbItem { |
| 17 | + title: string |
| 18 | + path?: string |
| 19 | +} |
| 20 | +
|
| 21 | +function findNavItemFromPath(path: string, items = navigation.value): NavItem | undefined { |
| 22 | + const item = items.find(i => i._path === path) |
| 23 | + if (item) |
| 24 | + return item |
| 25 | +
|
| 26 | + const parts = path.split('/').filter(Boolean) |
| 27 | + for (let i = parts.length - 1; i > 0; i--) { |
| 28 | + const parentPath = `/${parts.slice(0, i).join('/')}` |
| 29 | + const parent = items.find(i => i._path === parentPath) |
| 30 | + if (parent) |
| 31 | + return findNavItemFromPath(path, parent.children || []) |
| 32 | + } |
| 33 | +} |
| 34 | +
|
| 35 | +const contentPath = computed(() => page.value?._path as string | undefined) |
| 36 | +const breadcrumbs = computed(() => { |
| 37 | + const parts = contentPath.value?.split('/').filter(Boolean) || [] |
| 38 | + const breadcrumbs = parts |
| 39 | + .map((part, idx): BreadcrumbItem => { |
| 40 | + const path = `/${parts.slice(0, idx + 1).join('/')}` |
| 41 | + const item = findNavItemFromPath(path) |
| 42 | + return { |
| 43 | + title: item?.title || 'Not found', |
| 44 | + path: item ? path : undefined, |
| 45 | + } |
| 46 | + }) |
| 47 | +
|
| 48 | + if (!breadcrumbs.find(i => i.path === '/')) { |
| 49 | + breadcrumbs.unshift({ |
| 50 | + title: 'Guide', |
| 51 | + path: '/', |
| 52 | + }) |
| 53 | + } |
| 54 | + return breadcrumbs |
| 55 | +}) |
| 56 | +
|
3 | 57 | const ui = useUiState()
|
4 | 58 |
|
5 | 59 | const sourceUrl = computed(() => page.value?._file
|
6 | 60 | ? `https://github.com/nuxt/learn.nuxt.com/edit/main/content/${page.value._file}`
|
7 | 61 | : undefined)
|
8 |
| -
|
9 |
| -const { data: navigation } = await useAsyncData('navigation', () => fetchContentNavigation()) |
10 |
| -
|
11 |
| -const { |
12 |
| - // // Global references |
13 |
| - // globals, |
14 |
| - // navigation, |
15 |
| - // surround, |
16 |
| - // page, |
17 |
| - // // Computed properties from `page` key |
18 |
| - // excerpt, |
19 |
| - // toc, |
20 |
| - // type, |
21 |
| - // layout, |
22 |
| - // Computed properties from `surround` key |
23 |
| - next, |
24 |
| - prev, |
25 |
| -} = useContent() |
26 | 62 | </script>
|
27 | 63 |
|
28 | 64 | <template>
|
29 | 65 | <div grid="~ rows-[min-content_1fr_min-content]" relative h-full>
|
30 |
| - <button |
31 |
| - flex="~ gap-2 items-center" border="b base dashed" bg-faded px4 py2 |
32 |
| - @click="ui.isContentDropdownShown = !ui.isContentDropdownShown" |
33 |
| - > |
| 66 | + <div flex="~ gap-2 items-center" border="b base dashed" bg-faded px4 py2> |
34 | 67 | <div i-ph-book-duotone />
|
35 |
| - <NuxtLink to="/" text-sm> |
36 |
| - Guide |
37 |
| - </NuxtLink> |
38 |
| - <div flex-auto /> |
39 |
| - <div i-ph-caret-down-duotone text-sm op50 transition duration-400 :class="ui.isContentDropdownShown ? 'rotate-180' : ''" /> |
40 |
| - </button> |
| 68 | + <template v-for="bc, idx of breadcrumbs" :key="bc.path"> |
| 69 | + <div v-if="idx !== 0" i-ph-caret-right mx--1 text-sm op50 /> |
| 70 | + <NuxtLink :to="bc.path" text-sm hover="underline underline-dashed text-primary"> |
| 71 | + {{ bc.title }} |
| 72 | + </NuxtLink> |
| 73 | + </template> |
| 74 | + <button |
| 75 | + h-full flex-auto |
| 76 | + @click="ui.isContentDropdownShown = !ui.isContentDropdownShown" |
| 77 | + /> |
| 78 | + <button |
| 79 | + i-ph-caret-down-duotone text-sm op50 transition duration-400 |
| 80 | + :class="ui.isContentDropdownShown ? 'rotate-180' : ''" |
| 81 | + @click="ui.isContentDropdownShown = !ui.isContentDropdownShown" |
| 82 | + /> |
| 83 | + </div> |
41 | 84 | <div relative h-full of-hidden>
|
42 | 85 | <article class="max-w-none prose" h-full of-auto p6>
|
43 | 86 | <ContentDoc />
|
|
0 commit comments