mirror of
https://github.com/fantastic-admin/basic.git
synced 2026-10-06 12:53:21 +08:00
feat: 增加 FaPagination 组件
This commit is contained in:
@@ -190,6 +190,14 @@ const routes: RouteRecordRaw = {
|
||||
title: '内容块',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'pagination',
|
||||
name: 'componentExamplePagination',
|
||||
component: () => import('@/views/component_example/pagination/index.vue'),
|
||||
meta: {
|
||||
title: '分页',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'password_strength',
|
||||
name: 'componentExamplePasswordStrength',
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const size = ref(10)
|
||||
const total = ref(100)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FaPagination :page="page" :size="size" :total="total" />
|
||||
</template>
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const size = ref(10)
|
||||
const total = ref(100)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FaPagination :page="page" :size="size" :total="total" layout="jumper, pager, ->, total, sizes" />
|
||||
<div class="my-4 border-t" />
|
||||
<FaPagination :page="page" :size="size" :total="total" layout="pager" />
|
||||
</template>
|
||||
@@ -0,0 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import Demo1 from './_demo1.vue'
|
||||
import Demo2 from './_demo2.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<FaPageHeader title="分页" description="FaPagination" />
|
||||
<FaPageMain main-class="p-0">
|
||||
<div class="p-4">
|
||||
<Demo1 />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
<FaPageMain title="布局" main-class="p-0">
|
||||
<div class="p-4">
|
||||
<Demo2 />
|
||||
</div>
|
||||
</FaPageMain>
|
||||
</div>
|
||||
</template>
|
||||
@@ -27,6 +27,7 @@ export { default as FaModal } from './src/modal/index.vue'
|
||||
export { default as FaNumberField } from './src/number-field/index.vue'
|
||||
export { default as FaPageHeader } from './src/page-header/index.vue'
|
||||
export { default as FaPageMain } from './src/page-main/index.vue'
|
||||
export { default as FaPagination } from './src/pagination/index.vue'
|
||||
export { default as FaPasswordStrength } from './src/password-strength/index.vue'
|
||||
export { default as FaPopover } from './src/popover/index.vue'
|
||||
export { default as FaProgress } from './src/progress/index.vue'
|
||||
|
||||
@@ -30,6 +30,7 @@ const COMPONENT_NAMES = [
|
||||
'FaNumberField',
|
||||
'FaPageHeader',
|
||||
'FaPageMain',
|
||||
'FaPagination',
|
||||
'FaPasswordStrength',
|
||||
'FaPopover',
|
||||
'FaProgress',
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
# FaPagination 分页组件
|
||||
|
||||
功能完整的分页组件,支持总条数显示、每页条数选择、页码跳转和自定义布局。
|
||||
|
||||
## 基础用法
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const size = ref(10)
|
||||
const total = ref(100)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FaPagination v-model:page="page" v-model:size="size" :total="total" />
|
||||
</template>
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| `total` | `number` | **必需** | 数据总条数 |
|
||||
| `sizes` | `number[]` | `[10, 20, 30, 40, 50, 100]` | 每页条数选项 |
|
||||
| `layout` | `string` | `'total, sizes, ->, pager, jumper'` | 布局配置 |
|
||||
| `page` | `number` | **必需** | 当前页码(支持 v-model) |
|
||||
| `size` | `number` | **必需** | 每页条数(支持 v-model) |
|
||||
|
||||
## Events
|
||||
|
||||
| 事件名 | 参数 | 说明 |
|
||||
|--------|------|------|
|
||||
| `pageChange` | `page: number` | 页码变化时触发 |
|
||||
| `sizeChange` | `size: number` | 每页条数变化时触发 |
|
||||
|
||||
## Slots
|
||||
|
||||
无
|
||||
|
||||
## 示例
|
||||
|
||||
### 基础分页
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const total = ref(100)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FaPagination v-model:page="page" :total="total" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### 带每页条数选择
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const size = ref(10)
|
||||
const total = ref(500)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FaPagination v-model:page="page" v-model:size="size" :total="total" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### 自定义每页条数选项
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const size = ref(20)
|
||||
const total = ref(500)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FaPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:total="total"
|
||||
:sizes="[20, 50, 100, 200]"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 自定义布局(仅页码)
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const total = ref(100)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FaPagination v-model:page="page" :total="total" layout="pager" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### 自定义布局(总条数 + 页码)
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<FaPagination
|
||||
v-model:page="page"
|
||||
:total="total"
|
||||
layout="total, ->, pager"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 完整布局
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const size = ref(10)
|
||||
const total = ref(1000)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FaPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:total="total"
|
||||
layout="total, sizes, ->, pager, jumper"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 监听分页变化
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const size = ref(10)
|
||||
const total = ref(100)
|
||||
|
||||
function onPageChange(newPage: number) {
|
||||
console.log('页码变为:', newPage)
|
||||
// 加载新页面数据
|
||||
}
|
||||
|
||||
function onSizeChange(newSize: number) {
|
||||
console.log('每页条数变为:', newSize)
|
||||
page.value = 1 // 重置页码
|
||||
// 加载新数据
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FaPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:total="total"
|
||||
@page-change="onPageChange"
|
||||
@size-change="onSizeChange"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 在表格中使用
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const page = ref(1)
|
||||
const size = ref(10)
|
||||
const total = ref(100)
|
||||
const data = ref([])
|
||||
|
||||
// 加载数据
|
||||
function loadData() {
|
||||
// API 调用获取数据
|
||||
}
|
||||
|
||||
watch([page, size], loadData)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>姓名</th>
|
||||
<th>邮箱</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in data" :key="item.id">
|
||||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.email }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<FaPagination v-model:page="page" v-model:size="size" :total="total" />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 布局配置说明
|
||||
|
||||
`layout` 属性控制分页组件的布局和元素顺序,支持以下元素:
|
||||
|
||||
| 元素 | 说明 |
|
||||
|------|------|
|
||||
| `total` | 显示总条数 |
|
||||
| `sizes` | 每页条数选择器 |
|
||||
| `pager` | 页码按钮组 |
|
||||
| `jumper` | 页码跳转输入框 |
|
||||
| `->` | 弹性占位符(将后续元素推到右侧) |
|
||||
|
||||
### 布局示例
|
||||
|
||||
```vue
|
||||
<!-- 左侧总条数,中间页码,右侧跳转 -->
|
||||
<FaPagination layout="total, ->, pager, jumper" />
|
||||
|
||||
<!-- 仅显示页码 -->
|
||||
<FaPagination layout="pager" />
|
||||
|
||||
<!-- 总条数 + 每页条数 + 分页器 -->
|
||||
<FaPagination layout="total, sizes, pager" />
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **必需属性**:`total`、`page`、`size` 为必需属性
|
||||
2. **双向绑定**:`page` 和 `size` 支持 `v-model` 双向绑定
|
||||
3. **页码范围**:跳转页码会自动限制在有效范围内
|
||||
4. **自动聚焦**:跳转输入框获得焦点时会自动选中文本
|
||||
5. **回车跳转**:在跳转输入框中按回车键可触发跳转
|
||||
|
||||
## 典型使用场景
|
||||
|
||||
- 数据列表分页
|
||||
- 表格分页
|
||||
- 搜索结果分页
|
||||
- 文章列表分页
|
||||
- 评论列表分页
|
||||
@@ -0,0 +1,120 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Pagination,
|
||||
PaginationContent,
|
||||
PaginationEllipsis,
|
||||
PaginationFirst,
|
||||
PaginationItem,
|
||||
PaginationLast,
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
} from './pagination'
|
||||
|
||||
defineOptions({
|
||||
name: 'FaPagination',
|
||||
})
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
total: number
|
||||
sizes?: number[]
|
||||
layout?: string
|
||||
}>(), {
|
||||
sizes: () => [10, 20, 30, 40, 50, 100],
|
||||
layout: 'total, sizes, ->, pager, jumper',
|
||||
})
|
||||
|
||||
const emits = defineEmits<{
|
||||
pageChange: [page: number]
|
||||
sizeChange: [size: number]
|
||||
}>()
|
||||
|
||||
const page = defineModel<number>('page', { required: true })
|
||||
const size = defineModel<number>('size', { required: true })
|
||||
|
||||
const jumpPage = ref<number | string>(page.value)
|
||||
const totalPages = computed(() => Math.ceil(props.total / size.value))
|
||||
|
||||
// Parse layout string to determine order and visibility
|
||||
const layoutConfig = computed(() => {
|
||||
const items = props.layout.split(',').map(item => item.trim())
|
||||
const config: Record<string, { show: boolean, order: number }> = {
|
||||
'pager': { show: false, order: 0 },
|
||||
'total': { show: false, order: 0 },
|
||||
'sizes': { show: false, order: 0 },
|
||||
'jumper': { show: false, order: 0 },
|
||||
'->': { show: false, order: 0 },
|
||||
}
|
||||
|
||||
items.forEach((item, index) => {
|
||||
if (config[item] !== undefined) {
|
||||
config[item] = { show: true, order: index + 1 }
|
||||
}
|
||||
})
|
||||
|
||||
return config
|
||||
})
|
||||
|
||||
// Sync jumpPage with page model and emit pageChange event
|
||||
watch(page, (newPage) => {
|
||||
jumpPage.value = newPage
|
||||
emits('pageChange', newPage)
|
||||
})
|
||||
|
||||
// Emit sizeChange event when size changes
|
||||
watch(size, (newSize) => {
|
||||
emits('sizeChange', newSize)
|
||||
})
|
||||
|
||||
function handleFocus(event: Event) {
|
||||
const input = event.target as HTMLInputElement
|
||||
input.select()
|
||||
}
|
||||
|
||||
function handleInput(event: Event) {
|
||||
const input = event.target as HTMLInputElement
|
||||
const value = input.value.replace(/\D/g, '') // Remove non-digit characters
|
||||
jumpPage.value = value
|
||||
}
|
||||
|
||||
function handleJump() {
|
||||
const pageNum = Number(jumpPage.value)
|
||||
if (pageNum && Number.isInteger(pageNum) && pageNum >= 1 && pageNum <= totalPages.value) {
|
||||
page.value = pageNum
|
||||
}
|
||||
else if (pageNum > totalPages.value) {
|
||||
jumpPage.value = totalPages.value
|
||||
}
|
||||
else {
|
||||
jumpPage.value = page.value
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Pagination v-slot="{ page: currentPage }" :total="props.total" :sibling-count="1" show-edges :page="page" class="gap-4 items-center" :items-per-page="size" @update:page="(val) => page = val">
|
||||
<PaginationContent v-if="layoutConfig.pager.show" v-slot="{ items }" class="flex-center gap-1" :style="{ order: layoutConfig.pager.order }">
|
||||
<PaginationFirst size="icon-sm" class="size-8 rtl:rotate-180" />
|
||||
<PaginationPrevious size="icon-sm" class="size-8 rtl:rotate-180" />
|
||||
<template v-for="(item, index) in items" :key="index">
|
||||
<PaginationItem v-if="item.type === 'page'" :value="item.value" :is-active="item.value === currentPage" size="icon-sm" class="size-8">
|
||||
{{ item.value }}
|
||||
</PaginationItem>
|
||||
<PaginationEllipsis v-else :key="item.type" :index="index" />
|
||||
</template>
|
||||
<PaginationNext size="icon-sm" class="size-8 rtl:rotate-180" />
|
||||
<PaginationLast size="icon-sm" class="size-8 rtl:rotate-180" />
|
||||
</PaginationContent>
|
||||
<div v-if="layoutConfig.total.show" class="text-sm text-muted-foreground" :style="{ order: layoutConfig.total.order }">
|
||||
共 {{ props.total }} 条
|
||||
</div>
|
||||
<div v-if="layoutConfig.sizes.show" :style="{ order: layoutConfig.sizes.order }">
|
||||
<FaSelect v-model="size" :options="props.sizes.map(size => ({ label: `${size} 条/页`, value: size }))" class="w-auto" />
|
||||
</div>
|
||||
<div v-if="layoutConfig.jumper.show" class="flex-center gap-2" :style="{ order: layoutConfig.jumper.order }">
|
||||
<span class="text-sm text-muted-foreground">前往</span>
|
||||
<FaInput v-model="jumpPage" class="h-8 w-16" input-class="text-center" @focus="handleFocus" @input="handleInput" @keyup.enter="handleJump" />
|
||||
<span class="text-sm text-muted-foreground">页</span>
|
||||
</div>
|
||||
<div v-if="layoutConfig['->'].show" class="flex-1" :style="{ order: layoutConfig['->'].order }" />
|
||||
</Pagination>
|
||||
</template>
|
||||
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationRootEmits, PaginationRootProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { PaginationRoot, useForwardPropsEmits } from 'reka-ui'
|
||||
import { cn } from '../../../utils'
|
||||
|
||||
const props = defineProps<PaginationRootProps & {
|
||||
class?: HTMLAttributes['class']
|
||||
}>()
|
||||
const emits = defineEmits<PaginationRootEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationRoot
|
||||
v-slot="slotProps"
|
||||
data-slot="pagination"
|
||||
v-bind="forwarded"
|
||||
:class="cn('mx-auto flex w-full justify-center', props.class)"
|
||||
>
|
||||
<slot v-bind="slotProps" />
|
||||
</PaginationRoot>
|
||||
</template>
|
||||
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationListProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { PaginationList } from 'reka-ui'
|
||||
import { cn } from '../../../utils'
|
||||
|
||||
const props = defineProps<PaginationListProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationList
|
||||
v-slot="slotProps"
|
||||
data-slot="pagination-content"
|
||||
v-bind="delegatedProps"
|
||||
:class="cn('flex flex-row items-center gap-1', props.class)"
|
||||
>
|
||||
<slot v-bind="slotProps" />
|
||||
</PaginationList>
|
||||
</template>
|
||||
@@ -0,0 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationEllipsisProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { MoreHorizontal } from 'lucide-vue-next'
|
||||
import { PaginationEllipsis } from 'reka-ui'
|
||||
import { cn } from '../../../utils'
|
||||
|
||||
const props = defineProps<PaginationEllipsisProps & { class?: HTMLAttributes['class'] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationEllipsis
|
||||
data-slot="pagination-ellipsis"
|
||||
v-bind="delegatedProps"
|
||||
:class="cn('flex size-9 items-center justify-center', props.class)"
|
||||
>
|
||||
<slot>
|
||||
<MoreHorizontal class="size-4" />
|
||||
<span class="sr-only">More pages</span>
|
||||
</slot>
|
||||
</PaginationEllipsis>
|
||||
</template>
|
||||
@@ -0,0 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationFirstProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import type { ButtonVariants } from '../../button/button'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ChevronsLeft } from 'lucide-vue-next'
|
||||
import { PaginationFirst, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '../../../utils'
|
||||
import { buttonVariants } from '../../button/button'
|
||||
|
||||
const props = withDefaults(defineProps<PaginationFirstProps & {
|
||||
size?: ButtonVariants['size']
|
||||
class?: HTMLAttributes['class']
|
||||
}>(), {
|
||||
size: 'default',
|
||||
})
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class', 'size')
|
||||
const forwarded = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationFirst
|
||||
data-slot="pagination-first"
|
||||
:class="cn(buttonVariants({ variant: 'ghost', size }), 'gap-1 px-2.5 sm:pr-2.5', props.class)"
|
||||
v-bind="forwarded"
|
||||
>
|
||||
<slot>
|
||||
<ChevronsLeft />
|
||||
</slot>
|
||||
</PaginationFirst>
|
||||
</template>
|
||||
@@ -0,0 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationListItemProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import type { ButtonVariants } from '../../button/button'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { PaginationListItem } from 'reka-ui'
|
||||
import { cn } from '../../../utils'
|
||||
import { buttonVariants } from '../../button/button'
|
||||
|
||||
const props = withDefaults(defineProps<PaginationListItemProps & {
|
||||
size?: ButtonVariants['size']
|
||||
class?: HTMLAttributes['class']
|
||||
isActive?: boolean
|
||||
}>(), {
|
||||
size: 'icon',
|
||||
})
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class', 'size', 'isActive')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationListItem
|
||||
data-slot="pagination-item"
|
||||
v-bind="delegatedProps"
|
||||
:class="cn(
|
||||
buttonVariants({
|
||||
variant: isActive ? 'outline' : 'ghost',
|
||||
size,
|
||||
}),
|
||||
props.class)"
|
||||
>
|
||||
<slot />
|
||||
</PaginationListItem>
|
||||
</template>
|
||||
@@ -0,0 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationLastProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import type { ButtonVariants } from '../../button/button'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ChevronsRight } from 'lucide-vue-next'
|
||||
import { PaginationLast, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '../../../utils'
|
||||
import { buttonVariants } from '../../button/button'
|
||||
|
||||
const props = withDefaults(defineProps<PaginationLastProps & {
|
||||
size?: ButtonVariants['size']
|
||||
class?: HTMLAttributes['class']
|
||||
}>(), {
|
||||
size: 'default',
|
||||
})
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class', 'size')
|
||||
const forwarded = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationLast
|
||||
data-slot="pagination-last"
|
||||
:class="cn(buttonVariants({ variant: 'ghost', size }), 'gap-1 px-2.5 sm:pr-2.5', props.class)"
|
||||
v-bind="forwarded"
|
||||
>
|
||||
<slot>
|
||||
<ChevronsRight />
|
||||
</slot>
|
||||
</PaginationLast>
|
||||
</template>
|
||||
@@ -0,0 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationNextProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import type { ButtonVariants } from '../../button/button'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ChevronRightIcon } from 'lucide-vue-next'
|
||||
import { PaginationNext, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '../../../utils'
|
||||
import { buttonVariants } from '../../button/button'
|
||||
|
||||
const props = withDefaults(defineProps<PaginationNextProps & {
|
||||
size?: ButtonVariants['size']
|
||||
class?: HTMLAttributes['class']
|
||||
}>(), {
|
||||
size: 'default',
|
||||
})
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class', 'size')
|
||||
const forwarded = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationNext
|
||||
data-slot="pagination-next"
|
||||
:class="cn(buttonVariants({ variant: 'ghost', size }), 'gap-1 px-2.5 sm:pr-2.5', props.class)"
|
||||
v-bind="forwarded"
|
||||
>
|
||||
<slot>
|
||||
<ChevronRightIcon />
|
||||
</slot>
|
||||
</PaginationNext>
|
||||
</template>
|
||||
@@ -0,0 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import type { PaginationPrevProps } from 'reka-ui'
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import type { ButtonVariants } from '../../button/button'
|
||||
import { reactiveOmit } from '@vueuse/core'
|
||||
import { ChevronLeftIcon } from 'lucide-vue-next'
|
||||
import { PaginationPrev, useForwardProps } from 'reka-ui'
|
||||
import { cn } from '../../../utils'
|
||||
import { buttonVariants } from '../../button/button'
|
||||
|
||||
const props = withDefaults(defineProps<PaginationPrevProps & {
|
||||
size?: ButtonVariants['size']
|
||||
class?: HTMLAttributes['class']
|
||||
}>(), {
|
||||
size: 'default',
|
||||
})
|
||||
|
||||
const delegatedProps = reactiveOmit(props, 'class', 'size')
|
||||
const forwarded = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PaginationPrev
|
||||
data-slot="pagination-previous"
|
||||
:class="cn(buttonVariants({ variant: 'ghost', size }), 'gap-1 px-2.5 sm:pr-2.5', props.class)"
|
||||
v-bind="forwarded"
|
||||
>
|
||||
<slot>
|
||||
<ChevronLeftIcon />
|
||||
</slot>
|
||||
</PaginationPrev>
|
||||
</template>
|
||||
@@ -0,0 +1,8 @@
|
||||
export { default as Pagination } from './Pagination.vue'
|
||||
export { default as PaginationContent } from './PaginationContent.vue'
|
||||
export { default as PaginationEllipsis } from './PaginationEllipsis.vue'
|
||||
export { default as PaginationFirst } from './PaginationFirst.vue'
|
||||
export { default as PaginationItem } from './PaginationItem.vue'
|
||||
export { default as PaginationLast } from './PaginationLast.vue'
|
||||
export { default as PaginationNext } from './PaginationNext.vue'
|
||||
export { default as PaginationPrevious } from './PaginationPrevious.vue'
|
||||
Reference in New Issue
Block a user