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"