234 lines
5.7 KiB
Vue
234 lines
5.7 KiB
Vue
<script setup lang="ts">
|
|
import {Tour} from "@/types";
|
|
|
|
import { defineProps } from 'vue'
|
|
import EdgyButton from "@/components/dredgy/EdgyButton.vue";
|
|
const formatPrice = (price: number) => {
|
|
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(price)
|
|
}
|
|
|
|
const props = defineProps<{
|
|
tour: Tour
|
|
}>()
|
|
</script>
|
|
|
|
<template>
|
|
<div class="tour-card" data-index="0">
|
|
<div class="tour-image">
|
|
<img :src="`/img/tours/${tour.internal_name}.jpg`" alt="">
|
|
<div class="tour-overlay"></div>
|
|
<div :class="['tour-difficulty', tour.level.toLowerCase()]">{{tour.level}}</div>
|
|
<div class="tour-price">{{formatPrice(tour.price)}}</div>
|
|
</div>
|
|
<div class="tour-content">
|
|
<div class="tour-location">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
|
|
<circle cx="12" cy="10" r="3"></circle>
|
|
</svg>
|
|
{{ tour.countries.at(0)?.name }}, {{ tour.countries.at(0)?.continent.name }}
|
|
</div>
|
|
<h3 class="tour-title">{{tour.title}}</h3>
|
|
<p class="tour-description" v-if="tour.short_description">{{tour.short_description}}</p>
|
|
<div class="tour-details">
|
|
<div class="tour-detail">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="12" r="10"></circle>
|
|
<polyline points="12,6 12,12 16,14"></polyline>
|
|
</svg>
|
|
{{tour.length}} Days
|
|
</div>
|
|
<div class="tour-detail">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
|
|
<circle cx="9" cy="7" r="4"></circle>
|
|
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
|
|
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
|
|
</svg>
|
|
Maximum 6
|
|
</div>
|
|
</div>
|
|
<EdgyButton classes="btn-primary btn-full">Book Now</EdgyButton>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* Tour Cards */
|
|
.tour-card {
|
|
background: var(--card);
|
|
border: 1px solid var(--border);
|
|
border-radius: 0;
|
|
clip-path: polygon(0 0, calc(100% - 20px) 0, 100% 20px, 100% 100%, 20px 100%, 0 calc(100% - 20px));
|
|
cursor: pointer;
|
|
transition: all 1s cubic-bezier(0.4, 0, 0.2, 1);
|
|
transform: translateY(100px) rotate(-6deg) scale(0.9);
|
|
opacity: 0;
|
|
transform-origin: center bottom;
|
|
}
|
|
|
|
.tour-card:nth-child(2n) {
|
|
transform: translateY(100px) rotate(6deg) scale(0.9);
|
|
}
|
|
|
|
.tour-card.visible {
|
|
transform: translateY(0) rotate(0deg) scale(1);
|
|
opacity: 1;
|
|
}
|
|
|
|
.tour-card:hover {
|
|
box-shadow: var(--shadow-intense);
|
|
transform: translateY(-8px) rotate(0deg) scale(1.02);
|
|
}
|
|
|
|
.tour-image {
|
|
position: relative;
|
|
height: 256px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.tour-image img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: cover;
|
|
transition: transform 0.5s ease;
|
|
}
|
|
|
|
.tour-card:hover .tour-image img {
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.tour-overlay {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: linear-gradient(to top, rgba(0, 0, 0, 0.6), transparent);
|
|
}
|
|
|
|
.tour-difficulty {
|
|
position: absolute;
|
|
top: 1rem;
|
|
right: 1rem;
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 999px;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.tour-difficulty.expert {
|
|
background: var(--destructive);
|
|
color: var(--destructive-foreground);
|
|
}
|
|
|
|
.tour-difficulty.moderate {
|
|
background: var(--secondary);
|
|
color: var(--secondary-foreground);
|
|
}
|
|
|
|
.tour-difficulty.beginner {
|
|
background: var(--accent);
|
|
color: var(--background);
|
|
}
|
|
|
|
.tour-price {
|
|
position: absolute;
|
|
bottom: 1rem;
|
|
right: 1rem;
|
|
background: var(--primary);
|
|
color: white;
|
|
padding: 0.5rem 0.75rem;
|
|
border-radius: 4px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.tour-content {
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.tour-location {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
color: var(--muted-foreground);
|
|
font-size: 0.875rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.tour-title {
|
|
font-size: 1.25rem;
|
|
font-weight: bold;
|
|
color: var(--card-foreground);
|
|
margin-bottom: 0.75rem;
|
|
transition: var(--transition-smooth);
|
|
}
|
|
|
|
.tour-card:hover .tour-title {
|
|
color: var(--primary);
|
|
}
|
|
|
|
.tour-description {
|
|
color: var(--muted-foreground);
|
|
font-size: 0.875rem;
|
|
line-height: 1.6;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.tour-details {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.tour-detail {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
color: var(--muted-foreground);
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
/* Animations */
|
|
@keyframes bounce {
|
|
0%, 20%, 53%, 80%, 100% {
|
|
transform: translateX(-50%) translateY(0);
|
|
}
|
|
40%, 43% {
|
|
transform: translateX(-50%) translateY(-15px);
|
|
}
|
|
70% {
|
|
transform: translateX(-50%) translateY(-7px);
|
|
}
|
|
90% {
|
|
transform: translateX(-50%) translateY(-2px);
|
|
}
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%, 100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
|
|
.animate-fade {
|
|
animation: fadeInUp 1s ease-out;
|
|
}
|
|
|
|
.animate-slide {
|
|
animation: fadeInUp 1s ease-out 0.2s both;
|
|
}
|
|
|
|
@keyframes fadeInUp {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(30px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
</style>
|