image embed now uses primevue for modal

This commit is contained in:
lightling 2025-04-18 00:44:41 -04:00
parent 477259d85c
commit 37e7fd3416
Signed by: lightling
GPG key ID: F1F29650D537C773
6 changed files with 34 additions and 71 deletions

8
package-lock.json generated
View file

@ -14016,6 +14016,13 @@
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/mount-vue-component": {
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/mount-vue-component/-/mount-vue-component-0.10.2.tgz",
"integrity": "sha512-oighx0My03ArLOoTV/kLTJnrBwKdQMvn8uRP+u02rGkgkLiX1LycaHzFGib7mUwkyjp3q3uzVgwHjLZqM6rxyA==",
"dev": true,
"license": "MIT"
},
"node_modules/mrmime": { "node_modules/mrmime": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
@ -21080,6 +21087,7 @@
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"marked": "15.0.8", "marked": "15.0.8",
"marked-highlight": "2.2.1", "marked-highlight": "2.2.1",
"mount-vue-component": "0.10.2",
"normalize.css": "8.0.1", "normalize.css": "8.0.1",
"pinia": "3.0.2", "pinia": "3.0.2",
"primevue": "4.3.3", "primevue": "4.3.3",

View file

@ -24,6 +24,7 @@
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"marked": "15.0.8", "marked": "15.0.8",
"marked-highlight": "2.2.1", "marked-highlight": "2.2.1",
"mount-vue-component": "0.10.2",
"normalize.css": "8.0.1", "normalize.css": "8.0.1",
"pinia": "3.0.2", "pinia": "3.0.2",
"primevue": "4.3.3", "primevue": "4.3.3",

View file

@ -1,5 +1,4 @@
import { inflateDetailsElements } from './details' import { inflateDetailsElements } from './details'
import { inflateImageEmbeds } from './image'
import { inflateVideoEmbeds } from './video' import { inflateVideoEmbeds } from './video'
/** /**
@ -7,6 +6,5 @@ import { inflateVideoEmbeds } from './video'
*/ */
export const inflateEmbeds = () => { export const inflateEmbeds = () => {
inflateDetailsElements() inflateDetailsElements()
inflateImageEmbeds()
inflateVideoEmbeds() inflateVideoEmbeds()
} }

View file

@ -1,53 +0,0 @@
import { useModalStore } from 'src/modal'
/**
* Queries for HTMLImageElement nodes and inflates them with extra functionality
* @param _window the reference to the window
*/
export const inflateImageEmbeds = () => {
document.querySelectorAll('.content img:not(.no-inflate)').forEach((_element) => {
new ImageElement(_element as HTMLImageElement)
})
}
/**
* Inflates HTMLImageElement with extra functionality,
* namely previewing images in the modal service and displaying captions from titles
*/
export class ImageElement {
element: HTMLImageElement
caption: HTMLParagraphElement | null = null
wrapper: HTMLDivElement
constructor(_element: HTMLImageElement) {
this.element = _element
const parent = this.element.parentElement!
this.wrapper = document.createElement('div')
this.wrapper.classList.add('embed', 'image')
const subWrapper = document.createElement('div')
subWrapper.classList.add('image-wrapper')
parent.appendChild(this.wrapper)
this.wrapper.appendChild(subWrapper)
subWrapper.appendChild(this.element)
if (!!this.element.title) {
this.caption = document.createElement('p')
this.wrapper.appendChild(this.caption)
this.caption.innerHTML = this.element.title
}
this.element.addEventListener('click', this.onClick)
}
/**
* Handler for when the image is clicked
* @param event the click event
*/
onClick = (event: Event) => {
event.preventDefault()
let cloned = this.wrapper.cloneNode(true) as HTMLElement
let image = cloned.firstChild as HTMLElement
image.removeEventListener('click', this.onClick)
const store = useModalStore()
store.content = cloned.outerHTML
store.isOpen = true
}
}

View file

@ -1,5 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted } from 'vue' import { onMounted, createApp, getCurrentInstance } from 'vue'
import { mount } from 'mount-vue-component'
import PrimeVueImage from 'primevue/image'
import { inflateEmbeds } from 'src/components/inflators/embed' import { inflateEmbeds } from 'src/components/inflators/embed'
@ -7,8 +10,28 @@ const props = defineProps<{
content: string content: string
}>() }>()
const instance = getCurrentInstance()
const inflateComponents = () => {
// replace images with primevue/image
document.querySelectorAll('.content img:not(.no-inflate)').forEach((_element) => {
const inflated = mount(PrimeVueImage, {
props: {
alt: _element.getAttribute('alt'),
title: _element.getAttribute('title'),
src: _element.getAttribute('src'),
preview: true,
},
app: instance!.appContext.app,
})
_element.parentElement!.appendChild(inflated.el)
inflated.el.classList.add('embed', 'image')
_element.remove()
})
}
onMounted(() => { onMounted(() => {
inflateEmbeds() inflateEmbeds()
inflateComponents()
}) })
</script> </script>
@ -18,6 +41,6 @@ onMounted(() => {
) )
</template> </template>
<style scope lang="sass"> <style lang="sass">
</style> </style>

View file

@ -5,25 +5,11 @@ input[type="checkbox"],
label:has(+ input[type="checkbox"]) label:has(+ input[type="checkbox"])
cursor: pointer cursor: pointer
.modal-outlet
.embed
img
cursor: default
.embed .embed
video, video,
iframe, iframe,
object object
border: none border: none
.image-wrapper
display: grid
grid-template-columns: 1fr
grid-template-rows: 1fr
img
cursor: pointer
max-width: 100%
max-height: 100%
margin: auto
details details
summary summary