Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Pagination): add first and last page buttons #842

Merged
merged 5 commits into from Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -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>
35 changes: 35 additions & 0 deletions docs/content/5.navigation/3.pagination.md
Expand Up @@ -39,6 +39,8 @@ Use the `size` prop to change the size of the buttons.
baseProps:
modelValue: 1
total: 100
showLast: true
showFirst: true
props:
size: 'sm'
---
Expand Down Expand Up @@ -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

### `prev` / `next`
Expand All @@ -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"}

### `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

:component-props
Expand Down
78 changes: 69 additions & 9 deletions src/runtime/components/navigation/Pagination.vue
@@ -1,10 +1,23 @@
<template>
<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">
<UButton
v-if="prevButton"
:size="size"
:disabled="!canGoPrev"
:disabled="!canGoFirstOrPrev"
:class="[ui.base, ui.rounded]"
v-bind="{ ...ui.default.prevButton, ...prevButton }"
:ui="{ rounded: '' }"
Expand All @@ -28,14 +41,27 @@
<UButton
v-if="nextButton"
:size="size"
:disabled="!canGoNext"
:disabled="!canGoLastOrNext"
:class="[ui.base, ui.rounded]"
v-bind="{ ...ui.default.nextButton, ...nextButton }"
:ui="{ rounded: '' }"
aria-label="Next"
@click="onClickNext"
/>
</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>
</template>

Expand Down Expand Up @@ -94,6 +120,22 @@ export default defineComponent({
type: Object as PropType<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: {
type: Object as PropType<Button>,
default: () => config.default.prevButton as Button
Expand Down Expand Up @@ -192,8 +234,24 @@ export default defineComponent({
return items
})

const canGoPrev = computed(() => currentPage.value > 1)
const canGoNext = computed(() => currentPage.value < pages.value.length)
const canGoFirstOrPrev = computed(() => currentPage.value > 1)
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) {
if (typeof page === 'string') {
Expand All @@ -204,15 +262,15 @@ export default defineComponent({
}

function onClickPrev () {
if (!canGoPrev.value) {
if (!canGoFirstOrPrev.value) {
return
}

currentPage.value--
}

function onClickNext () {
if (!canGoNext.value) {
if (!canGoLastOrNext.value) {
return
}

Expand All @@ -226,11 +284,13 @@ export default defineComponent({
currentPage,
pages,
displayedPages,
canGoPrev,
canGoNext,
canGoLastOrNext,
canGoFirstOrPrev,
onClickPrev,
onClickNext,
onClickPage
onClickPage,
onClickFirst,
onClickLast
}
}
})
Expand Down
10 changes: 10 additions & 0 deletions src/runtime/ui.config.ts
Expand Up @@ -861,6 +861,16 @@ export const pagination = {
inactiveButton: {
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: {
color: 'white',
class: 'rtl:[&_span:first-child]:rotate-180',
Expand Down