Add some delete animation
parent
e6ac64a240
commit
4abf300350
|
@ -1,6 +1,11 @@
|
|||
<template>
|
||||
<div class="photo-container"
|
||||
:class="{ 'selected': (data.flag & c.FLAG_SELECTED) }">
|
||||
:class="{
|
||||
'selected': (data.flag & c.FLAG_SELECTED),
|
||||
'leaving': (data.flag & c.FLAG_LEAVING),
|
||||
'exit-left': (data.flag & c.FLAG_EXIT_LEFT),
|
||||
'enter-right': (data.flag & c.FLAG_ENTER_RIGHT),
|
||||
}">
|
||||
|
||||
<div class="icon-checkmark select"
|
||||
v-if="!(data.flag & c.FLAG_PLACEHOLDER)"
|
||||
|
@ -184,6 +189,31 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Container and selection */
|
||||
.photo-container.leaving {
|
||||
transition: all 0.2s ease-in;
|
||||
transform: scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
.photo-container.exit-left {
|
||||
transition: all 0.2s ease-in;
|
||||
transform: translateX(-20%);
|
||||
opacity: 0.4;
|
||||
}
|
||||
@keyframes enter-right {
|
||||
from {
|
||||
transform: translateX(20%);
|
||||
opacity: 0.4;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.photo-container.enter-right {
|
||||
animation: enter-right 0.2s ease-out forwards;
|
||||
|
||||
}
|
||||
.photo-container:hover .icon-checkmark {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
@ -208,10 +238,13 @@ export default {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Extra icons */
|
||||
.icon-video-white {
|
||||
position: absolute;
|
||||
top: 8px; right: 8px;
|
||||
}
|
||||
|
||||
/* Actual image */
|
||||
.img-outer {
|
||||
padding: 2px;
|
||||
transition: all 0.1s ease-in-out;
|
||||
|
|
|
@ -724,6 +724,35 @@ export default {
|
|||
await Promise.allSettled(promises);
|
||||
this.loading = false;
|
||||
|
||||
// Animate the deletion
|
||||
for (const photo of this.selection) {
|
||||
if (delIds.has(photo.fileid)) {
|
||||
photo.flag |= constants.FLAG_LEAVING;
|
||||
}
|
||||
}
|
||||
|
||||
// wait for 250ms
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
|
||||
// Speculate day reflow for animation
|
||||
const exitedLeft = new Set();
|
||||
for (const day of updatedDays) {
|
||||
let nextExit = false;
|
||||
for (const row of day.rows) {
|
||||
for (const photo of row.photos) {
|
||||
if (photo.flag & constants.FLAG_LEAVING) {
|
||||
nextExit = true;
|
||||
} else if (nextExit) {
|
||||
photo.flag |= constants.FLAG_EXIT_LEFT;
|
||||
exitedLeft.add(photo.fileid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wait for 200ms
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
|
||||
// Reflow all touched days
|
||||
for (const day of updatedDays) {
|
||||
day.detail = day.detail.filter(p => !delIds.has(p.fileid));
|
||||
|
@ -731,6 +760,29 @@ export default {
|
|||
this.processDay(day);
|
||||
}
|
||||
|
||||
// Enter from right all photos that exited left
|
||||
for (const day of updatedDays) {
|
||||
for (const row of day.rows) {
|
||||
for (const photo of row.photos) {
|
||||
if (exitedLeft.has(photo.fileid)) {
|
||||
photo.flag |= constants.FLAG_ENTER_RIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wait for 200ms
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
|
||||
// Clear enter right flags
|
||||
for (const day of updatedDays) {
|
||||
for (const row of day.rows) {
|
||||
for (const photo of row.photos) {
|
||||
photo.flag &= ~constants.FLAG_ENTER_RIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.clearSelection();
|
||||
this.reflowTimeline();
|
||||
this.handleViewSizeChange();
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
export default {
|
||||
FLAG_PLACEHOLDER: 1,
|
||||
FLAG_SELECTED: 2,
|
||||
FLAG_PLACEHOLDER: 1 << 0,
|
||||
FLAG_SELECTED: 1 << 1,
|
||||
FLAG_LEAVING: 1 << 2,
|
||||
FLAG_EXIT_LEFT: 1 << 3,
|
||||
FLAG_ENTER_RIGHT: 1 << 4,
|
||||
};
|
Loading…
Reference in New Issue