Skip to content
This repository was archived by the owner on May 1, 2025. It is now read-only.

Commit b8a8ee7

Browse files
committed
feat: breadcrumbs
1 parent 1708e26 commit b8a8ee7

File tree

3 files changed

+75
-32
lines changed

3 files changed

+75
-32
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ The development server will be running at [http://localhost:3000](http://localho
4949
- [ ] Search button
5050
- [ ] Navigation
5151
- [x] Dropdown for guide outlines
52-
- [ ] Breadcrumbs
52+
- [x] Breadcrumbs
5353
- [x] Previous/Next buttons
5454
- [x] Embedded Nuxt Docs (update CORS headers)
5555
- [x] Only make necessary changes when navigating between guides

components/ContentNavCard.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<script setup lang="ts">
22
defineProps<{
3-
to: string
3+
to?: string
44
icon?: string
5-
title: string
5+
title?: string
66
subheader: string
77
description: string
88
}>()

components/PanelDocs.vue

Lines changed: 72 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,86 @@
11
<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+
357
const ui = useUiState()
458
559
const sourceUrl = computed(() => page.value?._file
660
? `https://github.com/nuxt/learn.nuxt.com/edit/main/content/${page.value._file}`
761
: 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()
2662
</script>
2763

2864
<template>
2965
<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>
3467
<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>
4184
<div relative h-full of-hidden>
4285
<article class="max-w-none prose" h-full of-auto p6>
4386
<ContentDoc />

0 commit comments

Comments
 (0)