mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-25 17:30:37 +01:00
feat(Pagination): add first and last page buttons (#842)
Co-authored-by: Benjamin Canac <canacb1@gmail.com> Co-authored-by: Max Steinwand <msteinwand@kues.de>
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
<script setup>
|
||||||
|
const page = ref(1)
|
||||||
|
const items = ref(Array(55))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UPagination v-model="page" :total="items.length" :ui="{ rounded: 'first-of-type:rounded-s-md last-of-type:rounded-e-md' }">
|
||||||
|
<template #first="{ onClick }">
|
||||||
|
<UTooltip text="First page">
|
||||||
|
<UButton icon="i-heroicons-arrow-uturn-left" color="primary" :ui="{ rounded: 'rounded-full' }" class="rtl:[&_span:first-child]:rotate-180 me-2" @click="onClick" />
|
||||||
|
</UTooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #last="{ onClick }">
|
||||||
|
<UTooltip text="Last page">
|
||||||
|
<UButton icon="i-heroicons-arrow-uturn-right-20-solid" color="primary" :ui="{ rounded: 'rounded-full' }" class="rtl:[&_span:last-child]:rotate-180 ms-2" @click="onClick" />
|
||||||
|
</UTooltip>
|
||||||
|
</template>
|
||||||
|
</UPagination>
|
||||||
|
</template>
|
||||||
@@ -39,6 +39,8 @@ Use the `size` prop to change the size of the buttons.
|
|||||||
baseProps:
|
baseProps:
|
||||||
modelValue: 1
|
modelValue: 1
|
||||||
total: 100
|
total: 100
|
||||||
|
showLast: true
|
||||||
|
showFirst: true
|
||||||
props:
|
props:
|
||||||
size: 'sm'
|
size: 'sm'
|
||||||
---
|
---
|
||||||
@@ -89,6 +91,33 @@ excludedProps:
|
|||||||
---
|
---
|
||||||
::
|
::
|
||||||
|
|
||||||
|
### First / Last :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
|
||||||
|
|
||||||
|
Use the `first-button` and `last-button` props to customize the first and last buttons of the Pagination.
|
||||||
|
|
||||||
|
::component-card
|
||||||
|
---
|
||||||
|
baseProps:
|
||||||
|
modelValue: 1
|
||||||
|
total: 100
|
||||||
|
showFirst: true
|
||||||
|
showLast: true
|
||||||
|
props:
|
||||||
|
firstButton:
|
||||||
|
icon: 'i-heroicons-arrow-small-left-20-solid'
|
||||||
|
label: First
|
||||||
|
color: 'gray'
|
||||||
|
lastButton:
|
||||||
|
icon: 'i-heroicons-arrow-small-right-20-solid'
|
||||||
|
trailing: true
|
||||||
|
label: Last
|
||||||
|
color: 'gray'
|
||||||
|
excludedProps:
|
||||||
|
- firstButton
|
||||||
|
- lastButton
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
## Slots
|
## Slots
|
||||||
|
|
||||||
### `prev` / `next`
|
### `prev` / `next`
|
||||||
@@ -97,6 +126,12 @@ Use the `#prev` and `#next` slots to set the content of the previous and next bu
|
|||||||
|
|
||||||
:component-example{component="pagination-example-prev-next-slots"}
|
:component-example{component="pagination-example-prev-next-slots"}
|
||||||
|
|
||||||
|
### `first` / `last` :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
|
||||||
|
|
||||||
|
Use the `#first` and `#last` slots to set the content of the first and last buttons.
|
||||||
|
|
||||||
|
:component-example{component="pagination-example-first-last-slots"}
|
||||||
|
|
||||||
## Props
|
## Props
|
||||||
|
|
||||||
:component-props
|
:component-props
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="ui.wrapper" v-bind="attrs">
|
<div :class="ui.wrapper" v-bind="attrs">
|
||||||
|
<slot name="first" :on-click="onClickFirst">
|
||||||
|
<UButton
|
||||||
|
v-if="firstButton && showFirst"
|
||||||
|
:size="size"
|
||||||
|
:disabled="!canGoFirstOrPrev"
|
||||||
|
:class="[ui.base, ui.rounded]"
|
||||||
|
v-bind="{ ...ui.default.firstButton, ...firstButton }"
|
||||||
|
:ui="{ rounded: '' }"
|
||||||
|
aria-label="First"
|
||||||
|
@click="onClickFirst"
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
|
|
||||||
<slot name="prev" :on-click="onClickPrev">
|
<slot name="prev" :on-click="onClickPrev">
|
||||||
<UButton
|
<UButton
|
||||||
v-if="prevButton"
|
v-if="prevButton"
|
||||||
:size="size"
|
:size="size"
|
||||||
:disabled="!canGoPrev"
|
:disabled="!canGoFirstOrPrev"
|
||||||
:class="[ui.base, ui.rounded]"
|
:class="[ui.base, ui.rounded]"
|
||||||
v-bind="{ ...ui.default.prevButton, ...prevButton }"
|
v-bind="{ ...ui.default.prevButton, ...prevButton }"
|
||||||
:ui="{ rounded: '' }"
|
:ui="{ rounded: '' }"
|
||||||
@@ -28,7 +41,7 @@
|
|||||||
<UButton
|
<UButton
|
||||||
v-if="nextButton"
|
v-if="nextButton"
|
||||||
:size="size"
|
:size="size"
|
||||||
:disabled="!canGoNext"
|
:disabled="!canGoLastOrNext"
|
||||||
:class="[ui.base, ui.rounded]"
|
:class="[ui.base, ui.rounded]"
|
||||||
v-bind="{ ...ui.default.nextButton, ...nextButton }"
|
v-bind="{ ...ui.default.nextButton, ...nextButton }"
|
||||||
:ui="{ rounded: '' }"
|
:ui="{ rounded: '' }"
|
||||||
@@ -36,6 +49,19 @@
|
|||||||
@click="onClickNext"
|
@click="onClickNext"
|
||||||
/>
|
/>
|
||||||
</slot>
|
</slot>
|
||||||
|
|
||||||
|
<slot name="last" :on-click="onClickLast">
|
||||||
|
<UButton
|
||||||
|
v-if="lastButton && showLast"
|
||||||
|
:size="size"
|
||||||
|
:disabled="!canGoLastOrNext"
|
||||||
|
:class="[ui.base, ui.rounded]"
|
||||||
|
v-bind="{ ...ui.default.lastButton, ...lastButton }"
|
||||||
|
:ui="{ rounded: '' }"
|
||||||
|
aria-label="Last"
|
||||||
|
@click="onClickLast"
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -94,6 +120,22 @@ export default defineComponent({
|
|||||||
type: Object as PropType<Button>,
|
type: Object as PropType<Button>,
|
||||||
default: () => config.default.inactiveButton as Button
|
default: () => config.default.inactiveButton as Button
|
||||||
},
|
},
|
||||||
|
showFirst: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
showLast: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
firstButton: {
|
||||||
|
type: Object as PropType<Button>,
|
||||||
|
default: () => config.default.firstButton as Button
|
||||||
|
},
|
||||||
|
lastButton: {
|
||||||
|
type: Object as PropType<Button>,
|
||||||
|
default: () => config.default.lastButton as Button
|
||||||
|
},
|
||||||
prevButton: {
|
prevButton: {
|
||||||
type: Object as PropType<Button>,
|
type: Object as PropType<Button>,
|
||||||
default: () => config.default.prevButton as Button
|
default: () => config.default.prevButton as Button
|
||||||
@@ -192,8 +234,24 @@ export default defineComponent({
|
|||||||
return items
|
return items
|
||||||
})
|
})
|
||||||
|
|
||||||
const canGoPrev = computed(() => currentPage.value > 1)
|
const canGoFirstOrPrev = computed(() => currentPage.value > 1)
|
||||||
const canGoNext = computed(() => currentPage.value < pages.value.length)
|
const canGoLastOrNext = computed(() => currentPage.value < pages.value.length)
|
||||||
|
|
||||||
|
function onClickFirst () {
|
||||||
|
if (!canGoFirstOrPrev.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage.value = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClickLast () {
|
||||||
|
if (!canGoLastOrNext.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage.value = pages.value.length
|
||||||
|
}
|
||||||
|
|
||||||
function onClickPage (page: number | string) {
|
function onClickPage (page: number | string) {
|
||||||
if (typeof page === 'string') {
|
if (typeof page === 'string') {
|
||||||
@@ -204,7 +262,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onClickPrev () {
|
function onClickPrev () {
|
||||||
if (!canGoPrev.value) {
|
if (!canGoFirstOrPrev.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +270,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onClickNext () {
|
function onClickNext () {
|
||||||
if (!canGoNext.value) {
|
if (!canGoLastOrNext.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,11 +284,13 @@ export default defineComponent({
|
|||||||
currentPage,
|
currentPage,
|
||||||
pages,
|
pages,
|
||||||
displayedPages,
|
displayedPages,
|
||||||
canGoPrev,
|
canGoLastOrNext,
|
||||||
canGoNext,
|
canGoFirstOrPrev,
|
||||||
onClickPrev,
|
onClickPrev,
|
||||||
onClickNext,
|
onClickNext,
|
||||||
onClickPage
|
onClickPage,
|
||||||
|
onClickFirst,
|
||||||
|
onClickLast
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -861,6 +861,16 @@ export const pagination = {
|
|||||||
inactiveButton: {
|
inactiveButton: {
|
||||||
color: 'white'
|
color: 'white'
|
||||||
},
|
},
|
||||||
|
firstButton: {
|
||||||
|
color: 'white',
|
||||||
|
class: 'rtl:[&_span:first-child]:rotate-180',
|
||||||
|
icon: 'i-heroicons-chevron-double-left-20-solid'
|
||||||
|
},
|
||||||
|
lastButton: {
|
||||||
|
color: 'white',
|
||||||
|
class: 'rtl:[&_span:last-child]:rotate-180',
|
||||||
|
icon: 'i-heroicons-chevron-double-right-20-solid'
|
||||||
|
},
|
||||||
prevButton: {
|
prevButton: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
class: 'rtl:[&_span:first-child]:rotate-180',
|
class: 'rtl:[&_span:first-child]:rotate-180',
|
||||||
|
|||||||
Reference in New Issue
Block a user