:sparklesS: Post reaction
This commit is contained in:
@@ -1,33 +1,42 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="itemType == 'image'"
|
||||
class="relative rounded-md overflow-hidden"
|
||||
:style="`width: 100%; max-height: 800px; aspect-ratio: ${aspectRatio}`"
|
||||
>
|
||||
<!-- Blurhash placeholder -->
|
||||
<div
|
||||
v-if="blurhash"
|
||||
class="absolute inset-0 z-[-1]"
|
||||
:style="blurhashContainerStyle"
|
||||
>
|
||||
<canvas
|
||||
ref="blurCanvas"
|
||||
class="absolute top-0 left-0 w-full h-full"
|
||||
width="32"
|
||||
height="32"
|
||||
<div class="relative rounded-md overflow-hidden" :style="containerStyle">
|
||||
<template v-if="itemType == 'image'">
|
||||
<!-- Blurhash placeholder -->
|
||||
<div
|
||||
v-if="blurhash"
|
||||
class="absolute inset-0 z-[-1]"
|
||||
:style="blurhashContainerStyle"
|
||||
>
|
||||
<canvas
|
||||
ref="blurCanvas"
|
||||
class="absolute top-0 left-0 w-full h-full"
|
||||
width="32"
|
||||
height="32"
|
||||
/>
|
||||
</div>
|
||||
<!-- Main image -->
|
||||
<img
|
||||
:src="remoteSource"
|
||||
class="w-full h-auto rounded-md transition-opacity duration-500 object-cover cursor-pointer"
|
||||
:class="{ 'opacity-0': !imageLoaded && blurhash }"
|
||||
@load="imageLoaded = true"
|
||||
@error="imageLoaded = true"
|
||||
@click="openExternally"
|
||||
/>
|
||||
</div>
|
||||
<!-- Main image -->
|
||||
<img
|
||||
</template>
|
||||
<audio
|
||||
v-else-if="itemType == 'audio'"
|
||||
class="w-full h-auto"
|
||||
:src="remoteSource"
|
||||
class="w-full h-auto rounded-md transition-opacity duration-500"
|
||||
:class="{ 'opacity-0': !imageLoaded && blurhash }"
|
||||
@load="imageLoaded = true"
|
||||
@error="imageLoaded = true"
|
||||
controls
|
||||
/>
|
||||
<video
|
||||
v-else-if="itemType == 'video'"
|
||||
class="w-full h-auto"
|
||||
:src="remoteSource"
|
||||
controls
|
||||
/>
|
||||
</div>
|
||||
<audio v-else-if="itemType == 'audio'" :src="remoteSource" controls />
|
||||
<video v-else-if="itemType == 'video'" :src="remoteSource" controls />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -35,7 +44,7 @@ import { computed, ref, onMounted, watch } from "vue"
|
||||
import { decode } from "blurhash"
|
||||
import type { SnAttachment } from "~/types/api"
|
||||
|
||||
const props = defineProps<{ item: SnAttachment }>()
|
||||
const props = defineProps<{ item: SnAttachment; maxHeight?: string }>()
|
||||
|
||||
const itemType = computed(() => props.item.mimeType.split("/")[0] ?? "unknown")
|
||||
const blurhash = computed(() => props.item.fileMeta?.blur)
|
||||
@@ -50,6 +59,10 @@ const aspectRatio = computed(
|
||||
)
|
||||
const imageLoaded = ref(false)
|
||||
|
||||
function openExternally() {
|
||||
window.open(remoteSource.value + "?original=true", "_blank")
|
||||
}
|
||||
|
||||
const blurCanvas = ref<HTMLCanvasElement | null>(null)
|
||||
|
||||
const apiBase = useSolarNetworkUrl()
|
||||
@@ -61,6 +74,13 @@ const blurhashContainerStyle = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const containerStyle = computed(() => {
|
||||
return {
|
||||
"max-height": props.maxHeight ?? "720px",
|
||||
"aspect-ratio": aspectRatio.value
|
||||
}
|
||||
})
|
||||
|
||||
const decodeBlurhash = () => {
|
||||
if (!blurhash.value || !blurCanvas.value) return
|
||||
|
||||
|
Reference in New Issue
Block a user