299 lines
16 KiB
PHP
299 lines
16 KiB
PHP
|
|
|
|
<section class="section-padding">
|
|
<div class="container-padding">
|
|
<!-- Header -->
|
|
<div class="text-center mb-16">
|
|
<h2 class="text-hero mb-6">
|
|
{!! $content['title'] !!}
|
|
</h2>
|
|
<p class="text-large text-muted-foreground max-w-2xl mx-auto">
|
|
{!! $content['subtitle'] !!}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Filter Navigation -->
|
|
<div class="flex flex-wrap justify-center gap-3 mb-12">
|
|
|
|
|
|
@foreach($this->filters as $filterKey => $filterLabel)
|
|
<button
|
|
wire:click="filterBy('{{ $filterKey }}')"
|
|
class="{{ $activeFilter === $filterKey
|
|
? 'btn-primary-accent'
|
|
: 'btn-secondary-accent' }}"
|
|
>
|
|
{{ $filterLabel }}
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
|
|
<!-- Portfolio Grid -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
|
|
x-data
|
|
x-init="$nextTick(() => {
|
|
// Smooth animation for grid changes
|
|
$el.style.opacity = '0';
|
|
setTimeout(() => { $el.style.opacity = '1'; }, 100);
|
|
})">
|
|
|
|
@foreach($this->getFilteredProjects() as $index => $project)
|
|
<div class="group card-elevated rounded-3xl overflow-hidden h-full hover:scale-[1.02] transition-all duration-300"
|
|
x-data="{ loaded: false }"
|
|
x-init="setTimeout(() => loaded = true, {{ $index * 100 }})"
|
|
x-show="loaded"
|
|
x-transition:enter="transition ease-out duration-700"
|
|
x-transition:enter-start="opacity-0 transform translate-y-8"
|
|
x-transition:enter-end="opacity-100 transform translate-y-0">
|
|
|
|
<!-- Image Container -->
|
|
<div class="relative aspect-[4/3] overflow-hidden cursor-pointer"
|
|
wire:click="openModal({{ json_encode($project) }})">
|
|
<img src="{{ theme_image_url($project['image']) }}"
|
|
alt="{{ $project['title'] }}"
|
|
class="w-full h-full object-cover transition-transform duration-500 group-hover:scale-110">
|
|
|
|
<!-- Overlay -->
|
|
<div class="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
|
|
<!-- View Button -->
|
|
<div class="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-all duration-300">
|
|
<button class="btn-primary-accent">
|
|
<div class="flex items-center justify-center">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
|
|
</svg>
|
|
<span class="font-medium"> {{ __('ui.view') }}</span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Category Badge -->
|
|
<div class="absolute top-4 left-4">
|
|
<span class="bg-primary text-white px-3 py-1 rounded-full text-xs font-medium">
|
|
{{ $project['category'] }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div class="p-6 lg:p-8 flex flex-col justify-between">
|
|
<div class="space-y-4">
|
|
<h3 class="text-2xl lg:text-3xl font-semibold text-foreground leading-tight group-hover:text-secondary transition-colors duration-200">
|
|
{{ $project['title'] }}
|
|
</h3>
|
|
|
|
<p class="text-muted-foreground leading-relaxed text-base line-clamp-2">
|
|
{{ $project['description'] }}
|
|
</p>
|
|
|
|
<!-- Features -->
|
|
<div class="flex flex-wrap gap-2">
|
|
@foreach($project['features'] as $feature)
|
|
<span class="text-xs bg-muted text-muted-foreground px-2 py-1 rounded">
|
|
{{ $feature }}
|
|
</span>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Location and Price -->
|
|
<div class="flex items-center justify-between mt-6">
|
|
<div class="flex items-center text-sm text-muted-foreground gap-4">
|
|
@if(isset($project['location']) && $project['location'] != '')
|
|
<div class="flex items-center gap-1">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path>
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
</svg>
|
|
{{ $project['location'] }}
|
|
</div>
|
|
@endif
|
|
@if(isset($project['price']) && $project['price'] != '')
|
|
<span class="w-1 h-1 bg-muted-foreground rounded-full"></span>
|
|
<span class="font-medium text-secondary">{{ $project['price'] }}</span>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
|
|
@if(empty($this->getFilteredProjects()))
|
|
<div class="text-center py-16">
|
|
<div class="w-24 h-24 mx-auto mb-4 bg-muted rounded-full flex items-center justify-center">
|
|
<svg class="w-12 h-12 text-muted-foreground" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
|
|
</svg>
|
|
</div>
|
|
<h3 class="text-lg font-medium text-foreground mb-2">{{ __('ui.portfolio.no_projects') }}</h3>
|
|
<p class="text-muted-foreground">{{ __('ui.portfolio.try_other_filter') }}</p>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- Modal -->
|
|
<div x-data="{ show: @entangle('showModal').live }"
|
|
x-show="show"
|
|
x-cloak
|
|
class="fixed inset-0 z-50 overflow-y-auto"
|
|
x-transition:enter="transition ease-out duration-300"
|
|
x-transition:enter-start="opacity-0"
|
|
x-transition:enter-end="opacity-100"
|
|
x-transition:leave="transition ease-in duration-200"
|
|
x-transition:leave-start="opacity-100"
|
|
x-transition:leave-end="opacity-0"
|
|
@click="$wire.closeModal()">
|
|
|
|
<!-- Backdrop -->
|
|
<div class="fixed inset-0 bg-black/70 backdrop-blur-sm"></div>
|
|
|
|
<!-- Modal Content -->
|
|
<div class="relative min-h-screen flex items-center justify-center p-4">
|
|
<div class="relative card-elevated rounded-3xl max-w-4xl w-full max-h-[90vh] overflow-hidden"
|
|
x-show="show"
|
|
x-transition:enter="transition ease-out duration-300 transform"
|
|
x-transition:enter-start="opacity-0 scale-95"
|
|
x-transition:enter-end="opacity-100 scale-100"
|
|
x-transition:leave="transition ease-in duration-200 transform"
|
|
x-transition:leave-start="opacity-100 scale-100"
|
|
x-transition:leave-end="opacity-0 scale-95"
|
|
@click.stop>
|
|
|
|
@if($selectedProject)
|
|
<!-- Close Button -->
|
|
<button @click="$wire.closeModal()"
|
|
class="absolute top-4 right-4 z-20 bg-secondary text-white rounded-full p-2 hover:bg-secondary/80 transition-colors duration-200">
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- Scrollable Content Area -->
|
|
<div class="h-full max-h-[90vh] overflow-y-auto">
|
|
<!-- Image -->
|
|
<div class="aspect-[16/10] relative overflow-hidden rounded-t-2xl">
|
|
<img src="{{ theme_image_url($selectedProject['image']) }}"
|
|
alt="{{ $selectedProject['title'] }}"
|
|
class="w-full h-full object-cover">
|
|
|
|
<!-- Category Badge -->
|
|
<div class="absolute top-6 left-6">
|
|
<span class="bg-primary text-white px-4 py-2 rounded-full text-sm font-medium">
|
|
{{ $selectedProject['category'] }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div class="p-8">
|
|
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
|
<div class="flex-1">
|
|
<h2 class="text-section-title mb-4">
|
|
{{ $selectedProject['title'] }}
|
|
</h2>
|
|
<p class="text-muted-foreground mb-6 leading-relaxed text-base lg:text-lg">
|
|
{{ $selectedProject['description'] }}
|
|
</p>
|
|
|
|
<!-- Features -->
|
|
<div class="mb-6">
|
|
<h4 class="font-semibold text-foreground mb-3">{{ __('ui.portfolio.amenities') }}</h4>
|
|
<div class="flex flex-wrap gap-2">
|
|
@foreach($selectedProject['features'] as $feature)
|
|
<span class="bg-muted text-muted-foreground px-3 py-1 rounded-full text-sm">
|
|
{{ $feature }}
|
|
</span>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Details Sidebar -->
|
|
<div class="lg:w-80 card-elevated rounded-lg p-6">
|
|
<h4 class="font-semibold text-foreground mb-4">{{ __('ui.portfolio.project_details') }}</h4>
|
|
|
|
<div class="space-y-4">
|
|
@if(isset($selectedProject['location']) && $selectedProject['location'] != '')
|
|
<div class="flex items-start gap-3">
|
|
<svg class="w-5 h-5 text-muted-foreground mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path>
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
|
</svg>
|
|
<div>
|
|
<span class="text-sm text-muted-foreground">{{ __('ui.portfolio.location') }}</span>
|
|
<div class="font-medium text-foreground">{{ $selectedProject['location'] }}</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
@if(isset($selectedProject['price']) && $selectedProject['price'] != '')
|
|
<div class="flex items-start gap-3">
|
|
<svg class="w-5 h-5 text-muted-foreground mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1"></path>
|
|
</svg>
|
|
<div>
|
|
<span class="text-sm text-muted-foreground">{{ __('ui.portfolio.price') }}</span>
|
|
<div class="font-bold text-lg text-secondary">{{ $selectedProject['price'] }}</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
@if(isset($selectedProject['size']) && $selectedProject['size'] != '')
|
|
<div class="flex items-start gap-3">
|
|
<svg class="w-5 h-5 text-muted-foreground mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4a1 1 0 011-1h4m0 0V4m0-1h6m0 1v3M4 8h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V8z"></path>
|
|
</svg>
|
|
<div>
|
|
<span class="text-sm text-muted-foreground">{{ __('ui.portfolio.size') }}</span>
|
|
<div class="font-medium text-foreground">{{ $selectedProject['size'] }}</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- CTA Button -->
|
|
<button class="btn-primary-accent w-full mt-6">
|
|
{{ __('ui.contact') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
@push('styles')
|
|
<style>
|
|
.line-clamp-2 {
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* Custom scrollbar for modal */
|
|
.overflow-y-auto::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
|
|
.overflow-y-auto::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
margin: 1rem 0;
|
|
}
|
|
|
|
.overflow-y-auto::-webkit-scrollbar-thumb {
|
|
background: hsl(var(--muted-foreground) / 0.3);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.overflow-y-auto::-webkit-scrollbar-thumb:hover {
|
|
background: hsl(var(--muted-foreground) / 0.5);
|
|
}
|
|
</style>
|
|
@endpush
|