Use a prop links com o page?.body?.toc?.links que você obtém ao buscar uma página.
Use a prop title para alterar o título do sumário.
<script setup lang="ts">
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
}
])
</script>
<template>
<NContentToc title="On this page" :links="links" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
}
])
</script>
<template>
<NContentToc title="On this page" :links="links" />
</template>
Use a prop color para alterar a cor dos links.
<script setup lang="ts">
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
}
])
</script>
<template>
<NContentToc color="neutral" :links="links" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
}
])
</script>
<template>
<NContentToc color="neutral" :links="links" />
</template>
Use a prop highlight para exibir uma borda destacada para o item ativo.
<script setup lang="ts">
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
}
])
</script>
<template>
<NContentToc highlight :links="links" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
}
])
</script>
<template>
<NContentToc highlight :links="links" />
</template>
Use a prop highlight-color para alterar a cor do destaque. O padrão é o valor da prop color.
<script setup lang="ts">
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
}
])
</script>
<template>
<NContentToc highlight highlight-color="neutral" :links="links" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
}
])
</script>
<template>
<NContentToc highlight highlight-color="neutral" :links="links" />
</template>
Use a prop highlight-variant para alterar o estilo do destaque. O padrão é straight.
<script setup lang="ts">
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
},
{
id: 'examples',
depth: 2,
text: 'Examples',
children: [
{
id: 'within-a-page',
depth: 3,
text: 'Within a Page'
}
]
},
{
id: 'api',
depth: 2,
text: 'API',
children: [
{
id: 'props',
depth: 3,
text: 'Props'
},
{
id: 'slots',
depth: 3,
text: 'Slots'
},
{
id: 'emits',
depth: 3,
text: 'Emits'
}
]
},
{
id: 'theme',
depth: 2,
text: 'Theme'
}
])
</script>
<template>
<NContentToc highlight highlight-color="primary" highlight-variant="circuit" :links="links" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentTocLink } from '@nitro/ui'
const links = ref<ContentTocLink[]>([
{
id: 'usage',
depth: 2,
text: 'Usage',
children: [
{
id: 'title',
depth: 3,
text: 'Title'
},
{
id: 'color',
depth: 3,
text: 'Color'
},
{
id: 'highlight',
depth: 3,
text: 'Highlight'
},
{
id: 'highlight-color',
depth: 3,
text: 'Highlight Color'
},
{
id: 'highlight-variant',
depth: 3,
text: 'Highlight Variant'
}
]
},
{
id: 'examples',
depth: 2,
text: 'Examples',
children: [
{
id: 'within-a-page',
depth: 3,
text: 'Within a Page'
}
]
},
{
id: 'api',
depth: 2,
text: 'API',
children: [
{
id: 'props',
depth: 3,
text: 'Props'
},
{
id: 'slots',
depth: 3,
text: 'Slots'
},
{
id: 'emits',
depth: 3,
text: 'Emits'
}
]
},
{
id: 'theme',
depth: 2,
text: 'Theme'
}
])
</script>
<template>
<NContentToc highlight highlight-color="primary" highlight-variant="circuit" :links="links" />
</template>
Use o componente ContentToc em uma página para exibir o sumário:
<script setup lang="ts">
const route = useRoute()
const { data: page } = await useAsyncData(route.path, () => queryCollection('docs').path(route.path).first())
if (!page.value) {
throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
}
</script>
<template>
<NPage v-if="page">
<NPageHeader :title="page.title" />
<NPageBody>
<ContentRenderer v-if="page.body" :value="page" />
<NSeparator v-if="surround?.filter(Boolean).length" />
<NContentSurround :surround="(surround as any)" />
</NPageBody>
<template v-if="page?.body?.toc?.links?.length" #right>
<NContentToc :links="page.body.toc.links" />
</template>
</NPage>
</template>
| Prop | Default | Type |
|---|---|---|
as | 'nav' | anyThe element or component this component should render as. |
trailingIcon | appConfig.ui.icons.chevronDown | anyThe icon displayed to collapse the content. |
title | t('contentToc.title') | stringThe title of the table of contents. |
color | 'primary' | "primary" | "secondary" | "accent" | "success" | "info" | "warning" | "error" | "neutral" |
highlight | false | boolean Display a line next to the active link. |
highlightColor | 'primary' | "primary" | "secondary" | "accent" | "success" | "info" | "warning" | "error" | "neutral" |
links | T[] | |
defaultOpen | boolean The open state of the collapsible when it is initially rendered. | |
open | boolean The controlled open state of the collapsible. Can be binded with | |
ui | { root?: SlotClass; container?: SlotClass; top?: SlotClass; bottom?: SlotClass; trigger?: SlotClass; title?: SlotClass; trailing?: SlotClass; trailingIcon?: SlotClass; content?: SlotClass; list?: SlotClass; listWithChildren?: SlotClass; item?: SlotClass; itemWithChildren?: SlotClass; link?: SlotClass; linkText?: SlotClass; indicator?: SlotClass; indicatorLine?: SlotClass; indicatorActive?: SlotClass; } |
| Slot | Type |
|---|---|
leading | { open: boolean; ui: object; } |
default | { open: boolean; } |
trailing | { open: boolean; ui: object; } |
content | { links: T[]; } |
link | { link: T; } |
top | { links?: T[] | undefined; } |
bottom | { links?: T[] | undefined; } |
| Event | Type |
|---|---|
update:open | [value: boolean] |
move | [id: string] |
export default defineAppConfig({
ui: {
contentToc: {
slots: {
root: 'sticky top-(--ui-header-height) z-10 bg-default/75 lg:bg-[initial] backdrop-blur -mx-4 px-4 sm:px-6 sm:-mx-6 lg:ms-0 flex flex-col overflow-y-auto lg:overflow-hidden max-h-[calc(100vh-var(--ui-header-height))]',
container: 'pt-4 sm:pt-6 pb-2.5 sm:pb-4.5 lg:py-8 border-b border-dashed border-default lg:border-0 flex flex-col lg:min-h-0',
top: 'lg:shrink-0',
bottom: 'hidden lg:flex lg:flex-col lg:shrink-0 gap-6',
trigger: 'group text-sm font-semibold flex-1 flex items-center gap-1.5 py-1.5 -mt-1.5 rounded-sm outline-primary/25 focus-visible:outline-3 lg:shrink-0',
title: 'truncate',
trailing: 'ms-auto inline-flex gap-1.5 items-center',
trailingIcon: 'size-5 transform transition-transform duration-200 shrink-0 group-data-[state=open]:rotate-180 lg:hidden',
content: 'relative data-[state=open]:animate-[collapsible-down_200ms_ease-out] data-[state=closed]:animate-[collapsible-up_200ms_ease-out] data-[state=closed]:overflow-hidden focus:outline-none lg:min-h-0 lg:overflow-y-auto lg:scrollbar-none',
list: 'min-w-0',
listWithChildren: 'ms-3',
item: 'min-w-0',
itemWithChildren: '',
link: 'group relative text-sm flex items-center rounded-sm outline-primary/25 focus-visible:outline-3 py-1',
linkText: 'truncate',
indicator: '',
indicatorLine: '',
indicatorActive: ''
},
variants: {
color: {
primary: '',
secondary: '',
accent: '',
success: '',
info: '',
warning: '',
error: '',
neutral: ''
},
highlightColor: {
primary: {
indicatorActive: 'bg-primary'
},
secondary: {
indicatorActive: 'bg-secondary'
},
accent: {
indicatorActive: 'bg-accent'
},
success: {
indicatorActive: 'bg-success'
},
info: {
indicatorActive: 'bg-info'
},
warning: {
indicatorActive: 'bg-warning'
},
error: {
indicatorActive: 'bg-error'
},
neutral: {
indicatorActive: 'bg-inverted'
}
},
active: {
false: {
link: [
'text-muted hover:text-default',
'transition-colors'
]
}
},
highlight: {
true: ''
},
highlightVariant: {
straight: '',
circuit: ''
},
body: {
true: {
bottom: 'mt-6'
}
}
},
compoundVariants: [
{
color: 'primary',
active: true,
class: {
link: 'text-primary'
}
},
{
color: 'neutral',
active: true,
class: {
link: 'text-highlighted'
}
},
{
highlight: true,
highlightVariant: 'straight',
class: {
list: 'ms-2.5 ps-4 border-s border-default',
item: '-ms-px',
indicator: 'absolute ms-2.5 transition-[translate,height] duration-200 h-(--indicator-size) translate-y-(--indicator-position) w-px rounded-full',
indicatorLine: 'hidden',
indicatorActive: 'w-full h-full'
}
},
{
highlight: true,
highlightVariant: 'circuit',
class: {
list: 'ps-6.5',
item: '-ms-px',
itemWithChildren: 'ps-px',
indicator: 'absolute ms-2.5 start-0 top-0 rtl:-scale-x-100',
indicatorLine: 'absolute inset-0 bg-(--ui-border)',
indicatorActive: 'absolute w-full h-(--indicator-size) translate-y-(--indicator-position) transition-[translate,height] duration-200 ease-out'
}
}
],
defaultVariants: {
color: 'primary',
highlightColor: 'primary',
highlightVariant: 'straight'
}
}
}
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nitro/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
contentToc: {
slots: {
root: 'sticky top-(--ui-header-height) z-10 bg-default/75 lg:bg-[initial] backdrop-blur -mx-4 px-4 sm:px-6 sm:-mx-6 lg:ms-0 flex flex-col overflow-y-auto lg:overflow-hidden max-h-[calc(100vh-var(--ui-header-height))]',
container: 'pt-4 sm:pt-6 pb-2.5 sm:pb-4.5 lg:py-8 border-b border-dashed border-default lg:border-0 flex flex-col lg:min-h-0',
top: 'lg:shrink-0',
bottom: 'hidden lg:flex lg:flex-col lg:shrink-0 gap-6',
trigger: 'group text-sm font-semibold flex-1 flex items-center gap-1.5 py-1.5 -mt-1.5 rounded-sm outline-primary/25 focus-visible:outline-3 lg:shrink-0',
title: 'truncate',
trailing: 'ms-auto inline-flex gap-1.5 items-center',
trailingIcon: 'size-5 transform transition-transform duration-200 shrink-0 group-data-[state=open]:rotate-180 lg:hidden',
content: 'relative data-[state=open]:animate-[collapsible-down_200ms_ease-out] data-[state=closed]:animate-[collapsible-up_200ms_ease-out] data-[state=closed]:overflow-hidden focus:outline-none lg:min-h-0 lg:overflow-y-auto lg:scrollbar-none',
list: 'min-w-0',
listWithChildren: 'ms-3',
item: 'min-w-0',
itemWithChildren: '',
link: 'group relative text-sm flex items-center rounded-sm outline-primary/25 focus-visible:outline-3 py-1',
linkText: 'truncate',
indicator: '',
indicatorLine: '',
indicatorActive: ''
},
variants: {
color: {
primary: '',
secondary: '',
accent: '',
success: '',
info: '',
warning: '',
error: '',
neutral: ''
},
highlightColor: {
primary: {
indicatorActive: 'bg-primary'
},
secondary: {
indicatorActive: 'bg-secondary'
},
accent: {
indicatorActive: 'bg-accent'
},
success: {
indicatorActive: 'bg-success'
},
info: {
indicatorActive: 'bg-info'
},
warning: {
indicatorActive: 'bg-warning'
},
error: {
indicatorActive: 'bg-error'
},
neutral: {
indicatorActive: 'bg-inverted'
}
},
active: {
false: {
link: [
'text-muted hover:text-default',
'transition-colors'
]
}
},
highlight: {
true: ''
},
highlightVariant: {
straight: '',
circuit: ''
},
body: {
true: {
bottom: 'mt-6'
}
}
},
compoundVariants: [
{
color: 'primary',
active: true,
class: {
link: 'text-primary'
}
},
{
color: 'neutral',
active: true,
class: {
link: 'text-highlighted'
}
},
{
highlight: true,
highlightVariant: 'straight',
class: {
list: 'ms-2.5 ps-4 border-s border-default',
item: '-ms-px',
indicator: 'absolute ms-2.5 transition-[translate,height] duration-200 h-(--indicator-size) translate-y-(--indicator-position) w-px rounded-full',
indicatorLine: 'hidden',
indicatorActive: 'w-full h-full'
}
},
{
highlight: true,
highlightVariant: 'circuit',
class: {
list: 'ps-6.5',
item: '-ms-px',
itemWithChildren: 'ps-px',
indicator: 'absolute ms-2.5 start-0 top-0 rtl:-scale-x-100',
indicatorLine: 'absolute inset-0 bg-(--ui-border)',
indicatorActive: 'absolute w-full h-(--indicator-size) translate-y-(--indicator-position) transition-[translate,height] duration-200 ease-out'
}
}
],
defaultVariants: {
color: 'primary',
highlightColor: 'primary',
highlightVariant: 'straight'
}
}
}
})
]
})