Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 23 additions & 146 deletions documentation/src/views/code/PaginationCode.vue
Original file line number Diff line number Diff line change
@@ -1,155 +1,32 @@
<script setup lang="ts">
import { computed } from 'vue'
import {
Button,
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationFirst,
PaginationLast,
PaginationList,
PaginationItem,
PaginationNext,
PaginationPrev,
PaginationDetails,
} from '@sethsharp/lumuix'
import { Link } from '@inertiajs/vue3'

const paginatedData = {
data: [],
current_page: 4,
first_page_url: '?page=1',
from: 1,
last_page: 6,
last_page_url: '?page=7',
links: [
{
active: false,
label: '1',
url: '?page=1',
},
{
active: false,
label: '2',
url: '?page=2',
},
{
active: false,
label: '3',
url: '?page=3',
},
{
active: true,
label: '4',
url: '?page=4',
},
{
active: false,
label: '5',
url: '?page=5',
},
{
active: false,
label: '6',
url: '?page=6',
},
{
active: false,
label: '7',
url: '?page=7',
},
],
next_page_url: '?page=6',
path: '#',
per_page: 2,
prev_page_url: '?page=5',
to: 2,
total: 10,
}

const getStartingNumber = () => {
if (paginatedData.current_page === 1) {
if (paginatedData.data.length === 0) {
return 0
}

return 1
}

if (paginatedData.current_page === paginatedData.last_page) {
return paginatedData.total - paginatedData.data.length
}

return paginatedData.current_page * paginatedData.per_page - paginatedData.per_page
}

const getTotalNumber = () => {
if (paginatedData.current_page === 1) {
return paginatedData.data.length
}

if (paginatedData.current_page === paginatedData.last_page) {
return paginatedData.total
}

return paginatedData.current_page * paginatedData.per_page
}

const currentActiveIndex = computed(() => paginatedData.links.findIndex((link) => link.active))
PaginationPrevious,
} from "@sethsharp/lumuix"
</script>

<template>
<div class="justify-between sm:flex">
<PaginationDetails
:min="getStartingNumber()"
:max="getTotalNumber()"
:total="paginatedData.total" />

<Pagination>
<PaginationList class="flex items-center gap-1">
<PaginationFirst v-slot="{ icon }">
<Link :href="paginatedData.first_page_url">
<component :is="icon"/>
</Link>
</PaginationFirst>

<PaginationPrev
v-slot="{ icon }"
v-if="paginatedData.prev_page_url">
<Link :href="paginatedData.prev_page_url">
<component :is="icon" />
</Link>
</PaginationPrev>

<template v-for="(item, index) in paginatedData.links">
<Button
v-if="index <= currentActiveIndex + 2 && index >= currentActiveIndex - 2"
:key="index"
as-child
class="size-10 p-0"
:variant="item.active ? 'primary' : 'outline'">
<Link :href="item.url">
{{ item.label }}
</Link>
</Button>
</template>

<PaginationEllipsis v-if="currentActiveIndex < paginatedData.links.length - 2" />

<PaginationNext
v-if="paginatedData.next_page_url"
v-slot="{ icon }">
<Link :href="paginatedData.next_page_url">
<component :is="icon" />
</Link>
</PaginationNext>

<PaginationLast v-slot="{ icon }">
<Link :href="paginatedData.last_page_url">
<component
:is="icon"
class="size-4" />
</Link>
</PaginationLast>
</PaginationList>
</Pagination>
</div>
<Pagination v-slot="{ page }" :items-per-page="10" :total="30" :default-page="2">
<PaginationContent v-slot="{ items }">
<PaginationPrevious />

<template v-for="(item, index) in items" :key="index">
<PaginationItem
v-if="item.type === 'page'"
:value="item.value"
:is-active="item.value === page"
>
{{ item.value }}
</PaginationItem>
</template>

<PaginationEllipsis :index="4" />

<PaginationNext />
</PaginationContent>
</Pagination>
</template>
3 changes: 3 additions & 0 deletions documentation/src/views/components/Pagination.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import RenderPreviewCode from '../../components/RenderPreviewCode.vue'
</script>

<template>
<div>
The latest shadcn pagination api accepts multiple parameters to easily any set of paginated data.
</div>
<RenderPreviewCode :source-code="sourceCode">
<PaginationCode />
</RenderPreviewCode>
Expand Down
4 changes: 2 additions & 2 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@
"@tanstack/vue-table": "^8.21.3",
"@unovis/ts": "^1.5.2",
"@unovis/vue": "^1.5.2",
"@vueuse/core": "^13.5.0",
"@vueuse/core": "^13.9.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-vue-next": "^0.447.0",
"reka-ui": "^2.3.2",
"reka-ui": "^2.6.0",
"tailwind-merge": "^2.5.2",
"tailwindcss": "^4.1.7",
"tw-animate-css": "^1.3.4",
Expand Down
26 changes: 26 additions & 0 deletions ui/src/components/pagination/Pagination.vue
Original file line number Diff line number Diff line change
@@ -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 "@/lib/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>
22 changes: 22 additions & 0 deletions ui/src/components/pagination/PaginationContent.vue
Original file line number Diff line number Diff line change
@@ -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 "@/lib/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>
13 changes: 0 additions & 13 deletions ui/src/components/pagination/PaginationDetails.vue

This file was deleted.

25 changes: 13 additions & 12 deletions ui/src/components/pagination/PaginationEllipsis.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
<script setup lang="ts">
import { MoreHorizontal } from 'lucide-vue-next'
import { type HTMLAttributes, computed } from 'vue'
import { PaginationEllipsis, type PaginationEllipsisProps } from 'radix-vue'
import { cn } from '@/lib/utils'
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 "@/lib/utils"

const props = defineProps<PaginationEllipsisProps & { class?: HTMLAttributes['class'] }>()
const props = defineProps<PaginationEllipsisProps & { class?: HTMLAttributes["class"] }>()

const delegatedProps = computed(() => {
const { class: _, ...delegated } = props

return delegated
})
const delegatedProps = reactiveOmit(props, "class")
</script>

<template>
<PaginationEllipsis
data-slot="pagination-ellipsis"
v-bind="delegatedProps"
:class="cn('text-text flex size-9 items-center justify-center', props.class)">
:class="cn('flex size-9 items-center justify-center', props.class)"
>
<slot>
<MoreHorizontal />
<MoreHorizontal class="size-4" />
<span class="sr-only">More pages</span>
</slot>
</PaginationEllipsis>
</template>
50 changes: 25 additions & 25 deletions ui/src/components/pagination/PaginationFirst.vue
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
<script setup lang="ts">
import { ChevronsLeft } from 'lucide-vue-next'
import { type HTMLAttributes, computed } from 'vue'
import { PaginationFirst, type PaginationFirstProps } from 'radix-vue'
import { cn } from '@/lib/utils'
import { Button } from '@/components/button'
import type { PaginationFirstProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import type { ButtonVariants } from '@/components/button'
import { reactiveOmit } from "@vueuse/core"
import { ChevronLeftIcon } from "lucide-vue-next"
import { PaginationFirst, useForwardProps } from "reka-ui"
import { cn } from "@/lib/utils"
import { buttonVariants } from '@/components/button'

const props = withDefaults(
defineProps<
PaginationFirstProps & {
class?: HTMLAttributes['class']
}
>(),
{},
)

const delegatedProps = computed(() => {
const { class: _, ...delegated } = props

return delegated
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 v-bind="delegatedProps">
<Button
:class="cn('size-10 p-0', props.class)"
as-child
variant="outline">
<slot :icon="ChevronsLeft" />
</Button>
<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>
<ChevronLeftIcon />
<span class="hidden sm:block">First</span>
</slot>
</PaginationFirst>
</template>
Loading