forked from BRETT/BRETT
82 lines
2.0 KiB
Vue
82 lines
2.0 KiB
Vue
<script setup lang="ts">
|
|
import { onKeyStroke } from '@vueuse/core'
|
|
|
|
defineProps<{
|
|
src: string
|
|
alt?: string
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
close: []
|
|
}>()
|
|
|
|
const scale = ref(1)
|
|
const offset = ref({ x: 0, y: 0 })
|
|
const dragging = ref(false)
|
|
let last = { x: 0, y: 0 }
|
|
|
|
function onWheel(event: WheelEvent) {
|
|
const factor = event.deltaY < 0 ? 1.15 : 1 / 1.15
|
|
scale.value = Math.min(10, Math.max(0.2, scale.value * factor))
|
|
}
|
|
|
|
function onPointerDown(event: PointerEvent) {
|
|
dragging.value = true
|
|
last = { x: event.clientX, y: event.clientY }
|
|
;(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId)
|
|
}
|
|
|
|
function onPointerMove(event: PointerEvent) {
|
|
if (!dragging.value) return
|
|
offset.value = {
|
|
x: offset.value.x + event.clientX - last.x,
|
|
y: offset.value.y + event.clientY - last.y,
|
|
}
|
|
last = { x: event.clientX, y: event.clientY }
|
|
}
|
|
|
|
function onPointerUp() {
|
|
dragging.value = false
|
|
}
|
|
|
|
function reset() {
|
|
scale.value = 1
|
|
offset.value = { x: 0, y: 0 }
|
|
}
|
|
|
|
onKeyStroke('Escape', () => emit('close'))
|
|
</script>
|
|
|
|
<template>
|
|
<Teleport to="body">
|
|
<div
|
|
class="fixed inset-0 z-50 flex items-center justify-center overflow-hidden bg-black/90"
|
|
@wheel.prevent="onWheel"
|
|
@click="emit('close')"
|
|
>
|
|
<NuxtImg
|
|
:src="src"
|
|
:alt="alt"
|
|
draggable="false"
|
|
class="max-h-[95vh] max-w-[95vw] touch-none select-none"
|
|
:class="dragging ? 'cursor-grabbing' : 'cursor-grab'"
|
|
:style="{ transform: `translate(${offset.x}px, ${offset.y}px) scale(${scale})` }"
|
|
@click.stop
|
|
@dblclick="reset"
|
|
@pointerdown.prevent="onPointerDown"
|
|
@pointermove="onPointerMove"
|
|
@pointerup="onPointerUp"
|
|
@pointercancel="onPointerUp"
|
|
/>
|
|
<button
|
|
type="button"
|
|
class="absolute top-4 right-4 rounded-md bg-black/50 p-2 text-white hover:bg-black/70"
|
|
@click="emit('close')"
|
|
>
|
|
<Icon name="ph:x-fill" class="size-5" />
|
|
<span class="sr-only">Schließen</span>
|
|
</button>
|
|
</div>
|
|
</Teleport>
|
|
</template>
|