b2in/resources/views/livewire/web/components/sections/portfolio.blade.php
2025-10-20 17:50:35 +02:00

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="{{ asset('img/assets/' . $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"> Ansehen</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">Keine Projekte gefunden</h3>
<p class="text-muted-foreground">Versuchen Sie einen anderen 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="{{ asset('img/assets/' . $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">Ausstattung</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">Projektdetails</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">Standort</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">Preis</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">Größe</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">
Kontakt aufnehmen
</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