90 lines
2.2 KiB
Vue
90 lines
2.2 KiB
Vue
<template>
|
|
<div class="mosaic-scroll">
|
|
<infinite-scroll-container
|
|
:bufferSize="2"
|
|
:initialIndex="0"
|
|
:generateContent="generateMosaicContent"
|
|
ref="scrollContainer"
|
|
>
|
|
<template #viewport="{ viewport, content }">
|
|
<mosaic-viewport :viewport="viewport" :content="content" />
|
|
</template>
|
|
</infinite-scroll-container>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { nextTick, ref, watch } from 'vue'
|
|
import _shuffle from 'lodash/shuffle'
|
|
import { useMosaicLayout } from '@/composables/useMosaicLayout'
|
|
import { useRoute } from 'vue-router'
|
|
|
|
const props = defineProps({
|
|
items: Array,
|
|
})
|
|
|
|
const itemIndex = ref(0)
|
|
const shuffledItems = ref(_shuffle(props.items))
|
|
const scrollContainer = ref(null)
|
|
|
|
const { generateLayout, populateCells } = useMosaicLayout()
|
|
const route = useRoute()
|
|
|
|
const generateCellContent = () => {
|
|
if (itemIndex.value >= shuffledItems.value.length - 1) {
|
|
itemIndex.value = 0
|
|
shuffledItems.value = _shuffle(props.items)
|
|
return generateCellContent()
|
|
}
|
|
|
|
const item = shuffledItems.value[itemIndex.value]
|
|
|
|
itemIndex.value++
|
|
|
|
return item
|
|
}
|
|
|
|
// Generate mosaic content for each viewport
|
|
const generateMosaicContent = async (index) => {
|
|
// Calculate target number of cells based on viewport size and index
|
|
const baseCellCount = 6
|
|
const variance = Math.abs(index % 2) * 2
|
|
const targetCells = baseCellCount + variance
|
|
|
|
const layoutOptions = {
|
|
targetCells: targetCells,
|
|
}
|
|
|
|
// Generate the space-filling layout
|
|
const cells = generateLayout(layoutOptions)
|
|
|
|
// Populate cells with GIF content
|
|
const populatedCells = populateCells(cells.value, generateCellContent)
|
|
|
|
return {
|
|
cells: populatedCells,
|
|
}
|
|
}
|
|
|
|
// Start/stop scroll when page is open
|
|
watch(
|
|
() => route.name,
|
|
async () => {
|
|
if (route.name === 'mosaic-item') {
|
|
if (!scrollContainer.value) {
|
|
await nextTick()
|
|
}
|
|
scrollContainer.value?.stop?.()
|
|
} else {
|
|
scrollContainer.value?.start?.()
|
|
}
|
|
},
|
|
{ immediate: true },
|
|
)
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.mosaic-scroll {
|
|
position: relative;
|
|
}
|
|
</style>
|