use PrimeVue carousel in place of custom one

This commit is contained in:
lightling 2025-01-29 18:29:48 -05:00
parent a89afae23c
commit 04463b3083
Signed by: lightling
GPG key ID: F1F29650D537C773
5 changed files with 140 additions and 56 deletions

79
package-lock.json generated
View file

@ -1956,6 +1956,68 @@
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@primeuix/styled": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.3.2.tgz",
"integrity": "sha512-ColZes0+/WKqH4ob2x8DyNYf1NENpe5ZguOvx5yCLxaP8EIMVhLjWLO/3umJiDnQU4XXMLkn2mMHHw+fhTX/mw==",
"dev": true,
"dependencies": {
"@primeuix/utils": "^0.3.2"
},
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/@primeuix/utils": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.3.2.tgz",
"integrity": "sha512-B+nphqTQeq+i6JuICLdVWnDMjONome2sNz0xI65qIOyeB4EF12CoKRiCsxuZ5uKAkHi/0d1LqlQ9mIWRSdkavw==",
"dev": true,
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/@primevue/core": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.2.5.tgz",
"integrity": "sha512-+oWBIQs5dLd2Ini4KEVOlvPILk989EHAskiFS3R/dz3jeOllJDMZFcSp8V9ddV0R3yDaPdLVkfHm2Q5t42kU2Q==",
"dev": true,
"dependencies": {
"@primeuix/styled": "^0.3.2",
"@primeuix/utils": "^0.3.2"
},
"engines": {
"node": ">=12.11.0"
},
"peerDependencies": {
"vue": "^3.3.0"
}
},
"node_modules/@primevue/icons": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.2.5.tgz",
"integrity": "sha512-WFbUMZhQkXf/KmwcytkjGVeJ9aGEDXjP3uweOjQZMmRdEIxFnqYYpd90wE90JE1teZn3+TVnT4ZT7ejGyEXnFQ==",
"dev": true,
"dependencies": {
"@primeuix/utils": "^0.3.2",
"@primevue/core": "4.2.5"
},
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/@primevue/themes": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/@primevue/themes/-/themes-4.2.5.tgz",
"integrity": "sha512-8F7yA36xYIKtNuAuyBdZZEks/bKDwlhH5WjpqGGB0FdwfAEoBYsynQ5sdqcT2Lb/NsajHmS5lc++Ttlvr1g1Lw==",
"dev": true,
"dependencies": {
"@primeuix/styled": "^0.3.2"
},
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/@radix-ui/number": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
@ -17499,6 +17561,21 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"license": "MIT"
},
"node_modules/primevue": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/primevue/-/primevue-4.2.5.tgz",
"integrity": "sha512-7UMOIJvdFz4jQyhC76yhNdSlHtXvVpmE2JSo2ndUTBWjWJOkYyT562rQ4ayO+bMdJLtzBGqgY64I9ZfEvNd7vQ==",
"dev": true,
"dependencies": {
"@primeuix/styled": "^0.3.2",
"@primeuix/utils": "^0.3.2",
"@primevue/core": "4.2.5",
"@primevue/icons": "4.2.5"
},
"engines": {
"node": ">=12.11.0"
}
},
"node_modules/prismjs": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
@ -22627,6 +22704,7 @@
"devDependencies": {
"@goldenwere/mackenzii-embeds": "*",
"@goldenwere/mackenzii-types": "*",
"@primevue/themes": "4.2.5",
"@types/dompurify": "3.2.0",
"@types/js-yaml": "4.0.9",
"@types/node": "22.12.0",
@ -22640,6 +22718,7 @@
"marked-highlight": "2.2.1",
"normalize.css": "8.0.1",
"pinia": "2.3.1",
"primevue": "4.2.5",
"pug": "3.0.3",
"rfdc": "1.4.1",
"sass": "1.83.4",

View file

@ -11,6 +11,7 @@
"devDependencies": {
"@goldenwere/mackenzii-types": "*",
"@goldenwere/mackenzii-embeds": "*",
"@primevue/themes": "4.2.5",
"@types/dompurify": "3.2.0",
"@types/js-yaml": "4.0.9",
"@types/node": "22.12.0",
@ -24,6 +25,7 @@
"marked-highlight": "2.2.1",
"normalize.css": "8.0.1",
"pinia": "2.3.1",
"primevue": "4.2.5",
"pug": "3.0.3",
"rfdc": "1.4.1",
"sass": "1.83.4",

View file

@ -4,6 +4,7 @@ const hljs = import('highlight.js')
import type { HLJSApi } from 'highlight.js'
const marked = import('marked')
import { markedHighlight } from 'marked-highlight'
import PrimeVue from 'primevue/config'
import type { RoutedWindow, SiteGlobals } from '@goldenwere/mackenzii-types'
@ -43,7 +44,9 @@ export const createApp = ViteSSG(
window.router = router
}
app.use(createPinia())
app
.use(createPinia())
.use(PrimeVue, { theme: 'none' })
initializeRouteStore(routes, globals as unknown as SiteGlobals)
},
)

View file

@ -0,0 +1,35 @@
.p-carousel
display: flex
flex-direction: column
.p-carousel-content-container
display: flex
flex-direction: column
overflow: auto
.p-carousel-content
display: flex
flex-direction: row
gap: var(--p-carousel-content-gap)
.p-carousel-prev-button, .p-carousel-next-button
align-self: center
flex-shrink: 0
.p-carousel-viewport
width: 100%
overflow: hidden
.p-carousel-item-list
display: flex
flex-direction: row
.p-carousel-indicator-list
display: flex
flex-direction: row
justify-content: center
flex-wrap: wrap
padding: 1rem
gap: 1rem
margin: 0
list-style: none

View file

@ -1,5 +1,10 @@
<script setup lang="ts">
import { computed, onMounted, ref, watchEffect } from 'vue'
import {
computed,
onMounted,
ref,
} from 'vue'
import PrimeVueCarousel from 'primevue/carousel'
import { marked } from 'marked'
import type {
GalleryEntry,
@ -42,35 +47,15 @@ const fields = computed(() => {
return toReturn
})
const variants = computed(() => (resolved.value as GalleryEntryWithVariants).variants)
const variantsCount = computed(() => Object.keys((resolved.value as GalleryEntryWithVariants).variants).length)
const currentSelection = defineModel('currentSelection', { type: Number, default: 0 })
const currentUrl = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value].url)
const currentAlt = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value].alternativeText)
const currentCaption = computed(() => (resolved.value as GalleryEntryWithVariants).variants[currentSelection.value].caption)
const carousel = ref(null! as HTMLElement)
const onVariantSelected = (event: Event, id: number) => {
currentSelection.value = id
}
const onButtonClicked = (event: Event | null, direction: number, override?: number) => {
let val = Number(carousel.value.dataset.index!)
if (!!override) {
val = override
} else {
val += direction
}
if (val >= variantsCount.value) {
val = 0
} else if (val < 0) {
val = variantsCount.value - 1
}
const offset = (carousel.value.children[0] as HTMLImageElement).offsetWidth
carousel.value.style.transform = `translateX(-${offset * val}px)`
carousel.value.dataset.index = `${val}`
}
onMounted(async () => {
let config = await fetchAndParseConfig<ListWithEntries<GalleryEntry>>(routeConfig.config)
resolved.value = await fetchConfigByIdFromList(config, currentRoute.query.id as string)
@ -97,27 +82,21 @@ onMounted(async () => {
:title='currentCaption || currentAlt || description'
:alt='currentAlt || currentCaption || description'
)
.view-carousel
button.left(
@click='onButtonClicked($event, -1)'
)
span &lt;
.carousel(
ref='carousel'
data-index=0
PrimeVueCarousel(
:value='variants'
:numVisible='5'
:numScroll='5'
)
template(
#item='slotProps'
)
img(
v-for='(variant, id) in variants'
:class='{ active: id === currentSelection }'
:alt='variant.alternativeText || variant.caption || description'
:src='variant.thumbnailUrl || variant.url'
:title='variant.caption || id'
@click='onVariantSelected($event, id)'
:class='{ active: slotProps.index === currentSelection }'
:alt='slotProps.data.alternativeText || slotProps.data.caption || description'
:src='slotProps.data.thumbnailUrl || slotProps.data.url'
:title='slotProps.data.caption || slotProps.index'
@click='onVariantSelected($event, slotProps.index)'
)
button.right(
@click='onButtonClicked($event, 1)'
)
span &gt;
.view-content
p.title(
v-html='title'
@ -134,20 +113,6 @@ onMounted(async () => {
)
</template>
<style scoped lang="sass">
.view-carousel
position: relative
button
bottom: 0
position: absolute
top: 0
z-index: 1
&.left
left: 0
&.right
right: 0
.carousel
display: flex
img
cursor: pointer
<style lang="sass">
@import 'src/styles/components/carousel.sass'
</style>