ContentSurround

GitHub
一对上一页和下一页链接,用于在页面之间导航。
此组件仅在安装@nuxt/content模块时可用。

用法

使用surround prop和surround值来获取页面环绕。

<script setup lang="ts">
const route = useRoute()

const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {
  return queryCollectionItemSurroundings('docs', route.path, {
    fields: ['description']
  })
})
</script>

<template>
  <UContentSurround :surround="(surround as any)" />
</template>

上一页/下一页

使用prev-icon和next-icon道具自定义按钮Icon。

<script setup lang="ts">
import type { ContentSurroundLink } from '@nuxt/ui'

const surround = ref<ContentSurroundLink[]>([
  {
    title: 'ContentSearchButton',
    path: '/docs/components/content-search-button',
    stem: 'docs/2.components/content-search-button',
    description: 'A pre-styled Button to open the ContentSearch modal.'
  },
  {
    title: 'ContentToc',
    path: '/docs/components/content-toc',
    stem: 'docs/2.components/content-toc',
    description: 'A sticky Table of Contents with customizable slots.'
  }
])
</script>

<template>
  <UContentSurround
    prev-icon="i-lucide-chevron-left"
    next-icon="i-lucide-chevron-right"
    :surround="surround"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentSurroundLink } from '@nuxt/ui'

const surround = ref<ContentSurroundLink[]>([
  {
    title: 'ContentSearchButton',
    path: '/docs/components/content-search-button',
    stem: 'docs/2.components/content-search-button',
    description: 'A pre-styled Button to open the ContentSearch modal.'
  },
  {
    title: 'ContentToc',
    path: '/docs/components/content-toc',
    stem: 'docs/2.components/content-toc',
    description: 'A sticky Table of Contents with customizable slots.'
  }
])
</script>

<template>
  <UContentSurround
    prev-icon="i-lucide-chevron-left"
    next-icon="i-lucide-chevron-right"
    :surround="surround"
  />
</template>

示例

页面内

在页面中使用ContentSurround组件可以显示上一个和下一个链接:

pages/[...slug].vue
<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>
  <UPage v-if="page">
    <UPageHeader :title="page.title" />

    <UPageBody>
      <ContentRenderer v-if="page.body" :value="page" />

      <USeparator v-if="surround?.filter(Boolean).length" />

      <UContentSurround :surround="(surround as any)" />
    </UPageBody>

    <template v-if="page?.body?.toc?.links?.length" #right>
      <UContentToc :links="page.body.toc.links" />
    </template>
  </UPage>
</template>

API

Props

Prop Default Type
as
'div'
any

The element or component this component should render as.

prevIcon
appConfig.ui.icons.arrowLeft
any

The icon displayed in the prev link.

nextIcon
appConfig.ui.icons.arrowRight
any

The icon displayed in the next link.

surround
T[]
ui
{ root?: SlotClass; link?: SlotClass; linkLeading?: SlotClass; linkLeadingIcon?: SlotClass; linkTitle?: SlotClass; linkDescription?: SlotClass; }

Slots

Slot Type
link
{ link: T; ui: object; }
link-leading
{ link: T; ui: object; }
link-title
{ link: T; ui: object; }
link-description
{ link: T; ui: object; }

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    contentSurround: {
      slots: {
        root: 'grid grid-cols-1 sm:grid-cols-2 gap-8',
        link: [
          'group block px-6 py-8 rounded-lg border border-default hover:bg-elevated/50 outline-primary/25 focus-visible:outline-3 focus-visible:border-primary',
          'transition-colors'
        ],
        linkLeading: [
          'inline-flex items-center rounded-full p-1.5 bg-elevated group-hover:bg-primary/10 ring ring-accented mb-4 group-hover:ring-primary/50',
          'transition'
        ],
        linkLeadingIcon: [
          'size-5 shrink-0 text-highlighted group-hover:text-primary',
          'transition-[color,translate] ease-out motion-reduce:transition-none'
        ],
        linkTitle: 'font-medium text-[15px] text-highlighted mb-1 truncate',
        linkDescription: 'text-sm text-muted line-clamp-2'
      },
      variants: {
        direction: {
          left: {
            linkLeadingIcon: 'group-active:-translate-x-0.5 rtl:group-active:translate-x-0.5'
          },
          right: {
            link: 'text-end',
            linkLeadingIcon: 'group-active:translate-x-0.5 rtl:group-active:-translate-x-0.5'
          }
        }
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        contentSurround: {
          slots: {
            root: 'grid grid-cols-1 sm:grid-cols-2 gap-8',
            link: [
              'group block px-6 py-8 rounded-lg border border-default hover:bg-elevated/50 outline-primary/25 focus-visible:outline-3 focus-visible:border-primary',
              'transition-colors'
            ],
            linkLeading: [
              'inline-flex items-center rounded-full p-1.5 bg-elevated group-hover:bg-primary/10 ring ring-accented mb-4 group-hover:ring-primary/50',
              'transition'
            ],
            linkLeadingIcon: [
              'size-5 shrink-0 text-highlighted group-hover:text-primary',
              'transition-[color,translate] ease-out motion-reduce:transition-none'
            ],
            linkTitle: 'font-medium text-[15px] text-highlighted mb-1 truncate',
            linkDescription: 'text-sm text-muted line-clamp-2'
          },
          variants: {
            direction: {
              left: {
                linkLeadingIcon: 'group-active:-translate-x-0.5 rtl:group-active:translate-x-0.5'
              },
              right: {
                link: 'text-end',
                linkLeadingIcon: 'group-active:translate-x-0.5 rtl:group-active:-translate-x-0.5'
              }
            }
          }
        }
      }
    })
  ]
})

Changelog

No recent changes