54 lines
1.4 KiB
Vue
54 lines
1.4 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { NodeViewWrapper, nodeViewProps } from '@tiptap/vue-3'
|
|
import { articleImageId } from '@/lib/articleImage'
|
|
|
|
const props = defineProps(nodeViewProps)
|
|
|
|
const imageId = computed(() => articleImageId(props.node))
|
|
const showDeleteButton = computed(() => props.selected && imageId.value !== null)
|
|
interface ImageNodeAttrs {
|
|
src?: string
|
|
alt?: string
|
|
title?: string
|
|
width?: number | string
|
|
height?: number | string
|
|
}
|
|
|
|
const imageAttrs = computed(() => {
|
|
const { src, alt, title, width, height } = props.node.attrs as ImageNodeAttrs
|
|
return { src, alt, title, width, height, 'data-image-id': props.node.attrs['data-image-id'] }
|
|
})
|
|
|
|
function onDeleteClick() {
|
|
if (imageId.value === null) {
|
|
return
|
|
}
|
|
props.extension.options.onRequestRemove(imageId.value)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<NodeViewWrapper
|
|
as="div"
|
|
class="relative block w-fit"
|
|
:class="{ 'outline-2 outline-primary rounded-md': selected }"
|
|
data-testid="article-editor-image"
|
|
@dragstart.prevent
|
|
>
|
|
<img v-bind="imageAttrs" draggable="false" class="block max-w-full" />
|
|
<UButton
|
|
v-if="showDeleteButton"
|
|
data-testid="remove-image-button"
|
|
icon="i-lucide-trash-2"
|
|
color="error"
|
|
variant="ghost"
|
|
size="xs"
|
|
class="absolute top-1 right-1 bg-default"
|
|
aria-label="Remove image"
|
|
@mousedown.prevent
|
|
@click="onDeleteClick"
|
|
/>
|
|
</NodeViewWrapper>
|
|
</template>
|