primitives

Pagination

Pagination — базовый примитив RevueUI (Reka UI + shadcn-совместимый API).

Загрузка превью…

src/ui/pagination/Pagination.vue

<!-- Presentational: обычный HTML nav, Radix-примитива нет. -->
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"

const props = defineProps<{
  /** Доп. классы. Имя `class` — соглашение shadcn-vue (не `className`). */
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <nav
    role="navigation"
    aria-label="pagination"
    data-slot="pagination"
    :class="cn('cn-pagination mx-auto flex w-full justify-center', props.class)"
  >
    <slot />
  </nav>
</template>

src/ui/pagination/PaginationContent.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <ul data-slot="pagination-content" :class="cn('cn-pagination-content flex items-center', props.class)">
    <slot />
  </ul>
</template>

src/ui/pagination/PaginationEllipsis.vue

<!--
  Оригинал рендерит иконку через `IconPlaceholder`, заменена инлайновым
  `<svg>` (путь lucide "more-horizontal"/"ellipsis" — совпадают).
-->
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <span
    aria-hidden="true"
    data-slot="pagination-ellipsis"
    :class="cn('cn-pagination-ellipsis flex items-center justify-center', props.class)"
  >
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    ><circle cx="12" cy="12" r="1" /><circle cx="19" cy="12" r="1" /><circle cx="5" cy="12" r="1" /></svg>
    <span class="sr-only">More pages</span>
  </span>
</template>

src/ui/pagination/PaginationItem.vue

<script setup lang="ts"></script>

<template>
  <li data-slot="pagination-item">
    <slot />
  </li>
</template>

src/ui/pagination/PaginationLink.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { computed } from "vue"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import type { ButtonVariants } from "@/components/ui/button"

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes["class"]
    isActive?: boolean
    size?: ButtonVariants["size"]
    href?: string
  }>(),
  {
    size: "icon",
  }
)

const variant = computed<ButtonVariants["variant"]>(() => (props.isActive ? "outline" : "ghost"))
</script>

<template>
  <Button as-child :variant="variant" :size="props.size" :class="cn('cn-pagination-link', props.class)">
    <a
      :aria-current="props.isActive ? 'page' : undefined"
      data-slot="pagination-link"
      :data-active="props.isActive"
      :href="props.href"
    >
      <slot />
    </a>
  </Button>
</template>

src/ui/pagination/PaginationNext.vue

<!--
  Оригинал рендерит иконку через `IconPlaceholder`, заменена инлайновым
  `<svg>` (путь lucide "chevron-right") — тем же, что и в Vue-порте.
-->
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
import PaginationLink from "./PaginationLink.vue"

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes["class"]
    text?: string
    href?: string
  }>(),
  {
    text: "Next",
  }
)
</script>

<template>
  <PaginationLink
    aria-label="Go to next page"
    size="default"
    :href="props.href"
    :class="cn('cn-pagination-next', props.class)"
  >
    <span class="cn-pagination-next-text hidden sm:block">{{ props.text }}</span>
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      data-icon="inline-end"
      class="cn-rtl-flip"
    ><path d="m9 18 6-6-6-6" /></svg>
  </PaginationLink>
</template>

src/ui/pagination/PaginationPrevious.vue

<!--
  Оригинал рендерит иконку через `IconPlaceholder`, заменена инлайновым
  `<svg>` (путь lucide "chevron-left") — тем же, что и в Vue-порте.
-->
<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
import PaginationLink from "./PaginationLink.vue"

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes["class"]
    text?: string
    href?: string
  }>(),
  {
    text: "Previous",
  }
)
</script>

<template>
  <PaginationLink
    aria-label="Go to previous page"
    size="default"
    :href="props.href"
    :class="cn('cn-pagination-previous', props.class)"
  >
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
      data-icon="inline-start"
      class="cn-rtl-flip"
    ><path d="m15 18-6-6 6-6" /></svg>
    <span class="cn-pagination-previous-text hidden sm:block">{{ props.text }}</span>
  </PaginationLink>
</template>

src/ui/pagination/index.ts

export { default as Pagination } from "./Pagination.vue"
export { default as PaginationContent } from "./PaginationContent.vue"
export { default as PaginationEllipsis } from "./PaginationEllipsis.vue"
export { default as PaginationItem } from "./PaginationItem.vue"
export { default as PaginationLink } from "./PaginationLink.vue"
export { default as PaginationNext } from "./PaginationNext.vue"
export { default as PaginationPrevious } from "./PaginationPrevious.vue"

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/pagination.json

Зависимости реестра

Источник: порт из ReUI (Keenthemes, MIT)