116 lines
3.3 KiB
Vue
116 lines
3.3 KiB
Vue
<template>
|
|
<div class="card"
|
|
:class="{ dragging: isDragging }"
|
|
ref="card"
|
|
:style="{ transform: `translate(${offsetX}px, ${offsetY}px)`, opacity: cardOpacity }"
|
|
@mousedown="handleMouseDown"
|
|
@touchstart="handleTouchStart"
|
|
@touchmove="handleTouchMove"
|
|
@touchend="handleTouchEnd">
|
|
<div class="content">
|
|
<h2 class="text-xl font-bold mb-2">{{ property.title }}</h2>
|
|
<img :src="property.pic" alt="Property Image" class="mb-4 w-full h-48 object-cover rounded-lg" />
|
|
<p class="text-gray-700 mb-2">{{ property.description }}</p>
|
|
<p class="text-gray-900 font-bold">Price: {{ property.price }}</p>
|
|
<p class="text-gray-700">Rooms: {{ property.rooms }} | Baths: {{ property.baths }} | Area: {{ property.area }} sqft</p>
|
|
<p class="text-gray-600 text-sm mt-2">Location: {{ property.neighborhood }}</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
props: {
|
|
property: {
|
|
type: Object,
|
|
required: true
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
startX: 0,
|
|
startY: 0,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
isDragging: false,
|
|
cardOpacity: 1
|
|
};
|
|
},
|
|
methods: {
|
|
handleMouseDown(event) {
|
|
this.isDragging = true;
|
|
this.startX = event.clientX;
|
|
this.startY = event.clientY;
|
|
document.addEventListener('mousemove', this.handleMouseMove);
|
|
document.addEventListener('mouseup', this.handleMouseUp);
|
|
},
|
|
handleMouseMove(event) {
|
|
if (this.isDragging) {
|
|
const moveX = event.clientX - this.startX;
|
|
const moveY = event.clientY - this.startY;
|
|
this.offsetX = moveX;
|
|
this.offsetY = moveY;
|
|
this.updateOpacity();
|
|
}
|
|
},
|
|
handleMouseUp() {
|
|
this.isDragging = false;
|
|
document.removeEventListener('mousemove', this.handleMouseMove);
|
|
document.removeEventListener('mouseup', this.handleMouseUp);
|
|
if (Math.abs(this.offsetX) > window.innerWidth / 3) {
|
|
this.cardOpacity = 0;
|
|
} else {
|
|
this.offsetX = 0;
|
|
this.offsetY = 0;
|
|
this.cardOpacity = 1;
|
|
}
|
|
},
|
|
handleTouchStart(event) {
|
|
this.startX = event.touches[0].clientX;
|
|
this.startY = event.touches[0].clientY;
|
|
},
|
|
handleTouchMove(event) {
|
|
const moveX = event.touches[0].clientX - this.startX;
|
|
const moveY = event.touches[0].clientY - this.startY;
|
|
this.offsetX = moveX;
|
|
this.offsetY = moveY;
|
|
this.updateOpacity();
|
|
},
|
|
handleTouchEnd() {
|
|
if (Math.abs(this.offsetX) > window.innerWidth / 2.5) {
|
|
this.cardOpacity = 0;
|
|
} else {
|
|
this.offsetX = 0;
|
|
this.offsetY = 0;
|
|
this.cardOpacity = 1;
|
|
}
|
|
},
|
|
updateOpacity() {
|
|
const windowWidth = window.innerWidth;
|
|
const cardWidth = this.$refs.card.clientWidth;
|
|
const distanceToEdge = Math.min(Math.abs(this.offsetX), windowWidth - cardWidth);
|
|
this.cardOpacity = 1 - (distanceToEdge / (windowWidth / 2));
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.card {
|
|
color: black;
|
|
position: relative;
|
|
width: 30%;
|
|
height: 80%;
|
|
background-color: #ffffff;
|
|
border-radius: 10px;
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
|
transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), opacity 0.3s;
|
|
user-select: none;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.content {
|
|
padding: 20px;
|
|
}
|
|
</style>
|