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
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script setup lang="ts">
const props = defineProps<{
postCount?: number
laneWidth?: number
}>()

const posts = computed(() => Array.from({ length: props.postCount || 100 }, (_, i) => ({
title: `Nuxt Blog Post ${i + 1}`,
description: `This is an example blog post description for post number ${i + 1}. It demonstrates how virtualization efficiently handles large lists.`,
image: `https://picsum.photos/seed/${i + 1}/800/400`,
date: new Date(2024, 0, 1 + i).toISOString().split('T')[0],
authors: [{
name: `Author ${(i % 5) + 1}`,
avatar: { src: `https://i.pravatar.cc/150?img=${(i % 70) + 1}` }
}]
})))

const virtualizeOptions = computed(() => ({
estimateSize: 400,
gap: 16,
paddingStart: 16,
paddingEnd: 16,
laneWidth: props.laneWidth,
minLanes: 1,
maxLanes: 3
}))
</script>

<template>
<UBlogPosts
:posts="posts"
:virtualize="virtualizeOptions"
class="h-96 w-full"
/>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
defineProps<{
orientation?: 'vertical' | 'horizontal'
virtualize?: boolean
lanes?: number
gap?: number
padding?: number
}>()

const items = Array.from({ length: 50 }, (_, i) => ({
id: i + 1,
title: `Item ${i + 1}`,
description: `Description for item ${i + 1}`
}))
</script>

<template>
<UScrollArea
:items="items"
:orientation="orientation"
:virtualize="virtualize ? {
lanes: lanes && lanes > 1 ? lanes : undefined,
gap,
paddingStart: padding,
paddingEnd: padding
} : false"
class="h-96 w-full border border-default rounded-lg"
>
<template #default="{ item }">
<UCard class="h-full overflow-hidden">
<template #header>
<h3 class="font-semibold">
{{ item.title }}
</h3>
</template>
<p class="text-sm text-muted">
{{ item.description }}
</p>
</UCard>
</template>
</UScrollArea>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<template>
<UScrollArea class="h-64 border border-default rounded-lg p-4">
<div class="space-y-4">
<UCard>
<template #header>
<h3 class="font-semibold">
Section 1
</h3>
</template>
<p>Custom content without using the items prop.</p>
</UCard>
<UCard>
<template #header>
<h3 class="font-semibold">
Section 2
</h3>
</template>
<p>Any content can be placed here and it will be scrollable.</p>
</UCard>
<UCard>
<template #header>
<h3 class="font-semibold">
Section 3
</h3>
</template>
<p>You can mix different components and layouts as needed.</p>
</UCard>
</div>
</UScrollArea>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script setup lang="ts">
const images = Array.from({ length: 20 }, (_, i) => ({
id: i + 1,
url: `https://picsum.photos/300/200?random=${i}`,
title: `Image ${i + 1}`
}))
</script>

<template>
<UScrollArea
:items="images"
orientation="horizontal"
class="w-full border border-default rounded-lg p-4"
>
<template #default="{ item }">
<div class="grid grid-rows-[1fr_min-content] h-full">
<img
:src="item.url"
:alt="item.title"
class="w-[300px] h-[200px] rounded-lg object-cover"
>
<p class="mt-2 text-sm text-center">
{{ item.title }}
</p>
</div>
</template>
</UScrollArea>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<script setup lang="ts">
defineProps<{
lanes?: number
gap?: number
padding?: number
}>()

const items = Array.from({ length: 30 }, (_, i) => {
const heights = [300, 400, 200, 450]
return {
id: i + 1,
url: `https://picsum.photos/300/${heights[i % heights.length]}?random=${i}`,
title: `Image ${i + 1}`
}
})
</script>

<template>
<UScrollArea
:items="items"
:virtualize="{
estimateSize: 300,
gap,
paddingStart: padding,
paddingEnd: padding,
lanes
}"
class="h-[600px] w-full border border-default rounded-lg"
>
<template #default="{ item }">
<UCard :ui="{ body: 'p-0 sm:p-0' }">
<template #header>
<h3 class="font-semibold text-sm">
{{ item.title }}
</h3>
</template>
<div class="bg-elevated overflow-hidden">
<img
:src="item.url"
:alt="item.title"
class="w-full h-full object-cover"
>
</div>
</UCard>
</template>
</UScrollArea>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script setup lang="ts">
defineProps<{
orientation?: 'vertical' | 'horizontal'
}>()

const items = Array.from({ length: 30 }, (_, i) => ({
id: i + 1,
title: `Item ${i + 1}`,
description: `Description for item ${i + 1}`
}))
</script>

<template>
<UScrollArea
:items="items"
:orientation="orientation"
:class="orientation === 'vertical' ? 'h-96 flex flex-col' : 'w-full'"
class="border border-default rounded-lg p-4"
:ui="{ root: 'gap-4' }"
>
<template #default="{ item }">
<UCard>
<template #header>
<h3 class="font-semibold">
{{ item.title }}
</h3>
</template>
<p class="text-sm text-muted">
{{ item.description }}
</p>
</UCard>
</template>
</UScrollArea>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script setup lang="ts">
defineProps<{
laneWidth?: number
minLanes?: number
maxLanes?: number
}>()

const items = Array.from({ length: 30 }, (_, i) => {
const heights = [300, 400, 200, 450]
return {
id: i + 1,
url: `https://picsum.photos/300/${heights[i % heights.length]}?random=${i}`,
title: `Image ${i + 1}`
}
})
</script>

<template>
<UScrollArea
:items="items"
:virtualize="{
estimateSize: 300,
gap: 12,
paddingStart: 12,
paddingEnd: 12,
laneWidth,
minLanes,
maxLanes
}"
class="h-[600px] border border-default rounded-lg"
style="resize: both; overflow: auto; min-width: 300px; min-height: 300px;"
>
<template #default="{ item }">
<UCard :ui="{ body: 'p-0 sm:p-0' }">
<template #header>
<h3 class="font-semibold text-sm">
{{ item.title }}
</h3>
</template>
<div class="bg-elevated overflow-hidden">
<img
:src="item.url"
:alt="item.title"
class="w-full h-full object-cover"
>
</div>
</UCard>
</template>
</UScrollArea>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<script setup lang="ts">
const props = defineProps<{
targetIndex?: number
itemCount?: number
}>()

const items = computed(() => Array.from({ length: props.itemCount || 1000 }, (_, i) => ({
id: i + 1,
title: `Item ${i + 1}`
})))

const scrollArea = useTemplateRef('scrollArea')

function scrollToTop() {
scrollArea.value?.scrollToIndex(0, { align: 'start', behavior: 'smooth' })
}

function scrollToBottom() {
scrollArea.value?.scrollToIndex(items.value.length - 1, { align: 'end', behavior: 'smooth' })
}

function scrollToItem(index: number) {
scrollArea.value?.scrollToIndex(index - 1, { align: 'center', behavior: 'smooth' })
}
</script>

<template>
<div class="space-y-4 w-full">
<UScrollArea
ref="scrollArea"
:items="items"
:virtualize="{ estimateSize: 58 }"
class="h-96 w-full border border-default rounded-lg p-4"
>
<template #default="{ item, index }">
<div
class="p-3 mb-2 rounded-lg border border-default"
:class="index === (targetIndex || 500) - 1 ? 'bg-primary-500/10 border-primary-500/20' : 'bg-elevated'"
>
<span class="font-medium">{{ item.title }}</span>
</div>
</template>
</UScrollArea>

<div class="flex items-center gap-2">
<UButton icon="i-lucide-arrow-up-to-line" size="sm" @click="scrollToTop">
Top
</UButton>
<UButton icon="i-lucide-arrow-down-to-line" size="sm" @click="scrollToBottom">
Bottom
</UButton>
<UButton icon="i-lucide-navigation" size="sm" @click="scrollToItem(targetIndex || 500)">
Go to {{ targetIndex || 500 }}
</UButton>
</div>
</div>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script setup lang="ts">
const items = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
title: `Card ${i + 1}`,
description: i % 3 === 0
? `This is a longer description with more text to demonstrate variable height handling in virtualized lists. Item ${i + 1} has significantly more content than others.`
: `Short description for item ${i + 1}.`
}))
</script>

<template>
<UScrollArea
:items="items"
:virtualize="{ estimateSize: 120, lanes: 3, gap: 12, paddingStart: 12, paddingEnd: 12 }"
class="h-96 w-full border border-default rounded-lg"
>
<template #default="{ item }">
<UCard>
<template #header>
<h3 class="font-semibold">
{{ item.title }}
</h3>
</template>
<p class="text-sm text-muted">
{{ item.description }}
</p>
</UCard>
</template>
</UScrollArea>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script setup lang="ts">
const props = defineProps<{
itemCount?: number
}>()

const items = computed(() => Array.from({ length: props.itemCount || 10000 }, (_, i) => ({
id: i + 1,
title: `Item ${i + 1}`,
description: `Description for item ${i + 1}`
})))
</script>

<template>
<UScrollArea
:items="items"
virtualize
class="h-96 w-full border border-default rounded-lg p-4"
>
<template #default="{ item }">
<UCard class="mb-4">
<template #header>
<h3 class="font-semibold">
{{ item.title }}
</h3>
</template>
<p class="text-sm text-muted">
{{ item.description }}
</p>
</UCard>
</template>
</UScrollArea>
</template>
Loading