mirror of
https://github.com/MarcZierle/photo-log-frontend.git
synced 2025-04-16 17:04:38 +00:00
298 lines
6.1 KiB
Vue
298 lines
6.1 KiB
Vue
<template>
|
|
<n-spin :show="loading">
|
|
<div
|
|
class="card"
|
|
:style="card_styles"
|
|
@mouseover="setHoverIfLoaded"
|
|
@mouseleave="hover=false"
|
|
>
|
|
<div
|
|
class="cover"
|
|
:style="cover_styles"
|
|
ref="cover"
|
|
@click="toggleSelection"
|
|
>
|
|
<n-skeleton v-if="!isImgLoaded" :height="height" :width="width" />
|
|
<div v-if="isImgLoaded" class="selection" :style="selection_styles">
|
|
<n-icon size="4em" color="rgba(255,255,255,0.75)"><Check /></n-icon>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="options"
|
|
:style="options_styles"
|
|
>
|
|
<div class="content">
|
|
<div class="options-item" v-if="can_change_group">
|
|
<n-button text @click="$emit('update:group')">
|
|
<template #icon><n-icon><SortFilled /></n-icon></template>
|
|
Move Group
|
|
</n-button>
|
|
</div>
|
|
|
|
<div class="options-item" v-if="can_crop">
|
|
<n-button text @click="$emit('update:crop')">
|
|
<template #icon><n-icon><CropRotateFilled /></n-icon></template>
|
|
Crop Photo
|
|
</n-button>
|
|
</div>
|
|
|
|
<div class="options-item" v-if="can_change_ocr">
|
|
<n-button text @click="$emit('update:ocr')">
|
|
<template #icon><n-icon><TextAnnotationToggle /></n-icon></template>
|
|
Change OCR
|
|
</n-button>
|
|
</div>
|
|
|
|
<div class="options-item" v-if="can_change_tag">
|
|
<n-button text @click="$emit('update:tag')">
|
|
<template #icon><n-icon><MdPricetag /></n-icon></template>
|
|
Change Tag
|
|
</n-button>
|
|
</div>
|
|
|
|
<div class="options-item" v-if="can_delete">
|
|
<n-button text type="error" @click="$emit('update:delete')">
|
|
<template #icon><n-icon><TrashBinSharp /></n-icon></template>
|
|
Delete Photo
|
|
</n-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</n-spin>
|
|
</template>
|
|
|
|
<script>
|
|
import TextAnnotationToggle from '@vicons/carbon/TextAnnotationToggle'
|
|
import TrashBinSharp from '@vicons/ionicons5/TrashBinSharp'
|
|
import SortFilled from '@vicons/material/SortFilled'
|
|
import CropRotateFilled from '@vicons/material/CropRotateFilled'
|
|
import Check from '@vicons/fa/Check'
|
|
import MdPricetag from '@vicons/ionicons4/MdPricetag'
|
|
|
|
|
|
export default {
|
|
components: {
|
|
TextAnnotationToggle,
|
|
TrashBinSharp,
|
|
SortFilled,
|
|
CropRotateFilled,
|
|
Check,
|
|
MdPricetag,
|
|
},
|
|
props: {
|
|
src: {
|
|
type: String,
|
|
required: false,
|
|
default: '',
|
|
},
|
|
can_change_group: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
can_select: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
can_change_ocr: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
can_change_tag: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
can_crop: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
can_delete: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
width: {
|
|
type: Number,
|
|
required: false,
|
|
default: 150,
|
|
},
|
|
init_selection: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
loading: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
},
|
|
emits: [
|
|
'update:select',
|
|
'update:delete',
|
|
'update:crop',
|
|
'update:ocr',
|
|
'update:tag',
|
|
'update:group',
|
|
],
|
|
data() {
|
|
return {
|
|
hover: false,
|
|
selected: false,
|
|
|
|
isImgLoaded: true,
|
|
imgSrcObj: null,
|
|
}
|
|
},
|
|
beforeMount() {
|
|
this.imgSrcObj = new Image()
|
|
this.imgSrcObj.src = this.src
|
|
if (this.can_select && this.init_selection) {
|
|
this.selected = true
|
|
}
|
|
},
|
|
watch: {
|
|
imgSrcObj: {
|
|
handler: function () {
|
|
if (this.imgSrcObj.complete) {
|
|
URL.revokeObjectURL(this.imgSrcObj.src)
|
|
this.isImgLoaded = true
|
|
}
|
|
},
|
|
deep: true,
|
|
}
|
|
},
|
|
computed: {
|
|
height() { return this.width * 1.41421356 },
|
|
options_height() {
|
|
return [
|
|
this.can_change_group,
|
|
this.can_crop,
|
|
this.can_change_ocr,
|
|
this.can_change_tag,
|
|
this.can_delete
|
|
].filter(Boolean).length * 35
|
|
},
|
|
card_styles() {
|
|
if (this.hover) {
|
|
return `
|
|
z-index: 90;
|
|
box-shadow: 0px 0px 13px 5px rgba(0,0,0,0.05);
|
|
${/*transform: translateY(-10px);*/{}}
|
|
`
|
|
}
|
|
return ''
|
|
},
|
|
cover_styles() {
|
|
let styles = `
|
|
background-image: url(${this.src});
|
|
width: ${this.width}px;`
|
|
|
|
|
|
if (this.hover) {
|
|
styles += `height: ${this.height - this.options_height + 5}px;`
|
|
} else {
|
|
styles += `height: ${this.height}px;`
|
|
}
|
|
|
|
return styles
|
|
},
|
|
selection_styles() {
|
|
if (this.selected) {
|
|
return 'opacity: 100%;'
|
|
}
|
|
return 'opacity: 0;'
|
|
},
|
|
options_styles() {
|
|
const base_height = 5
|
|
const expand_height = this.options_height
|
|
|
|
if (!this.hover) {
|
|
return `
|
|
height: ${base_height}px;
|
|
`
|
|
} else {
|
|
return `
|
|
height: ${expand_height}px;
|
|
`
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
setHoverIfLoaded() {
|
|
if (this.isImgLoaded) {
|
|
this.hover = true
|
|
}
|
|
},
|
|
toggleSelection() {
|
|
if (this.can_select) {
|
|
this.selected = !this.selected
|
|
this.$emit('update:select', this.selected)
|
|
}
|
|
}
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.card{
|
|
transition: all 0.25s;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.cover {
|
|
background-repeat: no-repeat;
|
|
background-position: center;
|
|
background-size: cover;
|
|
cursor: pointer;
|
|
transition: all 0.25s;
|
|
padding: 0;
|
|
}
|
|
|
|
.options {
|
|
transition: all 0.25s;
|
|
border: 1px solid rgb(238, 238, 238);
|
|
border-top: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.options .content {
|
|
padding: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.options .options-item {
|
|
vertical-align: middle;
|
|
cursor: pointer;
|
|
width: 100%;
|
|
padding: 0.125em 1em 0.125em 1em;
|
|
margin: 0;
|
|
}
|
|
|
|
.options .options-item:hover {
|
|
background-color: rgb(245, 245, 245);
|
|
}
|
|
|
|
.selection {
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: rgba(0, 162, 255, 0.432);
|
|
text-align: center;
|
|
vertical-align: middle;
|
|
transition: all 0.15s;
|
|
}
|
|
|
|
.selection .n-icon {
|
|
transform: translateY(50%);
|
|
}
|
|
</style> |