add documents editor
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<div class="relative">
|
||||
<div
|
||||
class="relative"
|
||||
:style="boxStyle"
|
||||
>
|
||||
<img
|
||||
:src="imageUrl"
|
||||
:width="metadata.width"
|
||||
:height="metadata.height"
|
||||
class="rounded border pointer-events-none outline outline-1 -outline-offset-1 transition-[outline-color] duration-75"
|
||||
:class="[
|
||||
page.rotate % 180 ? 'absolute inset-0 m-auto w-full' : 'w-full',
|
||||
selected ? 'outline-neutral-400' : 'outline-transparent'
|
||||
]"
|
||||
:style="imageStyle"
|
||||
:loading="lazy ? 'lazy' : 'eager'"
|
||||
>
|
||||
<div
|
||||
v-if="areas.length || page.redact.length"
|
||||
class="absolute pointer-events-none"
|
||||
:style="overlayStyle"
|
||||
>
|
||||
<div
|
||||
v-for="(item, areaIndex) in areas"
|
||||
:key="areaIndex"
|
||||
class="absolute border rounded-sm opacity-70"
|
||||
:class="[areaBorderColor(item.submitterIndex), areaBgColor(item.submitterIndex)]"
|
||||
:style="{
|
||||
left: `${item.area.x * 100}%`,
|
||||
top: `${item.area.y * 100}%`,
|
||||
width: `${item.area.w * 100}%`,
|
||||
height: `${item.area.h * 100}%`
|
||||
}"
|
||||
/>
|
||||
<div
|
||||
v-for="(rect, rectIndex) in page.redact"
|
||||
:key="`redact-${rectIndex}`"
|
||||
class="absolute bg-black"
|
||||
:style="{
|
||||
left: `${rect.x * 100}%`,
|
||||
top: `${rect.y * 100}%`,
|
||||
width: `${rect.w * 100}%`,
|
||||
height: `${rect.h * 100}%`
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="withActions"
|
||||
class="absolute top-1 right-1 flex space-x-1 group-hover:opacity-100"
|
||||
:class="selected ? 'opacity-100' : 'opacity-0'"
|
||||
>
|
||||
<span
|
||||
v-if="extraAction"
|
||||
class="tooltip tooltip-bottom"
|
||||
:data-tip="t(extraAction)"
|
||||
>
|
||||
<button
|
||||
class="btn border-gray-300 bg-white text-base-content btn-xs rounded hover:text-base-100 hover:bg-base-content hover:border-base-content transition-colors p-0"
|
||||
style="width: 22px; height: 22px; min-height: 22px"
|
||||
@click.stop.prevent="$emit(extraAction)"
|
||||
>
|
||||
<IconEraser
|
||||
v-if="extraAction === 'redact'"
|
||||
:width="14"
|
||||
:height="14"
|
||||
:stroke-width="1.6"
|
||||
/>
|
||||
<IconCrop
|
||||
v-else
|
||||
:width="20"
|
||||
:height="20"
|
||||
:stroke-width="1.2"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
<span
|
||||
class="tooltip tooltip-bottom"
|
||||
:data-tip="t('rotate')"
|
||||
>
|
||||
<button
|
||||
class="btn border-gray-300 bg-white text-base-content btn-xs rounded hover:text-base-100 hover:bg-base-content hover:border-base-content transition-colors p-0"
|
||||
style="width: 22px; height: 22px; min-height: 22px"
|
||||
@click.stop.prevent="$emit('rotate')"
|
||||
>
|
||||
<IconRotateClockwise
|
||||
:width="14"
|
||||
:height="14"
|
||||
:stroke-width="1.6"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
<span
|
||||
class="tooltip tooltip-bottom"
|
||||
:data-tip="t('remove')"
|
||||
>
|
||||
<button
|
||||
class="btn border-gray-300 bg-white text-base-content btn-xs rounded hover:text-base-100 hover:bg-base-content hover:border-base-content transition-colors p-0"
|
||||
style="width: 22px; height: 22px; min-height: 22px"
|
||||
@click.stop.prevent="$emit('remove')"
|
||||
>
|
||||
<IconX
|
||||
:width="14"
|
||||
:height="14"
|
||||
:stroke-width="1.6"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="pageNumber"
|
||||
class="text-center text-sm pt-1 pointer-events-none"
|
||||
>
|
||||
{{ t('page') }} {{ pageNumber }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { IconRotateClockwise, IconX, IconEraser, IconCrop } from '@tabler/icons-vue'
|
||||
import Area from './area.vue'
|
||||
|
||||
export default {
|
||||
name: 'DocumentsEditorPage',
|
||||
components: {
|
||||
IconRotateClockwise,
|
||||
IconX,
|
||||
IconEraser,
|
||||
IconCrop
|
||||
},
|
||||
inject: ['t'],
|
||||
props: {
|
||||
page: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
imageUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
metadata: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
areas: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => []
|
||||
},
|
||||
selected: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
withActions: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
pageNumber: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
lazy: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
extraAction: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
emits: ['rotate', 'remove', 'redact', 'crop'],
|
||||
computed: {
|
||||
borderColors: Area.computed.borderColors,
|
||||
bgColors: Area.computed.bgColors,
|
||||
boxStyle () {
|
||||
if (!this.page.rotate || !(this.page.rotate % 180)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return { aspectRatio: `${this.metadata.height} / ${this.metadata.width}` }
|
||||
},
|
||||
imageStyle () {
|
||||
if (!this.page.rotate) {
|
||||
return null
|
||||
}
|
||||
|
||||
let transform = `rotate(${this.page.rotate}deg)`
|
||||
|
||||
if (this.page.rotate % 180) {
|
||||
transform += ` scale(${this.metadata.width / this.metadata.height})`
|
||||
}
|
||||
|
||||
return { transform }
|
||||
},
|
||||
overlayStyle () {
|
||||
if (!this.page.rotate || !(this.page.rotate % 180)) {
|
||||
return { inset: '0', transform: this.page.rotate ? `rotate(${this.page.rotate}deg)` : undefined }
|
||||
}
|
||||
|
||||
return {
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
width: '100%',
|
||||
aspectRatio: `${this.metadata.width} / ${this.metadata.height}`,
|
||||
transform: `translate(-50%, -50%) rotate(${this.page.rotate}deg) scale(${this.metadata.width / this.metadata.height})`
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
areaBorderColor (submitterIndex) {
|
||||
return this.borderColors[Math.max(submitterIndex, 0) % this.borderColors.length]
|
||||
},
|
||||
areaBgColor (submitterIndex) {
|
||||
return this.bgColors[Math.max(submitterIndex, 0) % this.bgColors.length]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user