Initial commit
This commit is contained in:
154
resources/views/livewire/main-page/call-card-carousel.blade.php
Normal file
154
resources/views/livewire/main-page/call-card-carousel.blade.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<div>
|
||||
@if (count($calls) > 0)
|
||||
<div x-data="{
|
||||
navigate: true,
|
||||
atStart: true,
|
||||
atEnd: false,
|
||||
init() {
|
||||
this.$nextTick(() => this.updateState());
|
||||
this.$refs.track.addEventListener('scroll', () => this.updateState());
|
||||
},
|
||||
updateState() {
|
||||
const t = this.$refs.track;
|
||||
this.atStart = t.scrollLeft <= 0;
|
||||
this.atEnd = t.scrollLeft + t.offsetWidth >= t.scrollWidth - 1;
|
||||
},
|
||||
scrollLeft() {
|
||||
this.navigate = false;
|
||||
this.$refs.track.scrollBy({ left: -this.$refs.track.offsetWidth, behavior: 'smooth' });
|
||||
setTimeout(() => { this.navigate = true }, 600);
|
||||
},
|
||||
scrollRight() {
|
||||
this.navigate = false;
|
||||
this.$refs.track.scrollBy({ left: this.$refs.track.offsetWidth, behavior: 'smooth' });
|
||||
setTimeout(() => { this.navigate = true }, 600);
|
||||
},
|
||||
}" class="relative group">
|
||||
|
||||
{{-- Scrollable track --}}
|
||||
<div x-ref="track"
|
||||
class="overflow-x-auto"
|
||||
style="scrollbar-width: none; -ms-overflow-style: none;">
|
||||
<div class="flex gap-3" style="width: max-content;">
|
||||
<div class="w-2 flex-shrink-0"></div>
|
||||
@foreach ($calls as $index => $result)
|
||||
<div @click="if (navigate) window.location='{{ route('call.show', ['id' => $result['id']]) }}'"
|
||||
class="relative flex flex-col justify-end overflow-hidden rounded-lg shadow-lg flex-shrink-0 cursor-pointer"
|
||||
style="width: calc((100vw - 3rem) / 3); min-width: 200px; max-width: 320px; height: 170px;">
|
||||
|
||||
{{-- Tag color background + overlay --}}
|
||||
<div class="absolute inset-0 z-0 bg-{{ $result['tag_color'] ?? 'gray' }}-400"></div>
|
||||
<div class="absolute inset-0 z-10 bg-black/50"></div>
|
||||
|
||||
{{-- Card content --}}
|
||||
<div class="relative z-20 flex h-full flex-col justify-between p-4 text-white">
|
||||
<div class="flex-1 min-w-0">
|
||||
{{-- Deepest tag category badge --}}
|
||||
@php $leafCat = !empty($result['tag_categories']) ? end($result['tag_categories']) : null; @endphp
|
||||
@if ($leafCat)
|
||||
<div class="mb-2">
|
||||
<span class="bg-{{ $leafCat['color'] ?? 'gray' }}-400 inline-flex items-center rounded px-1.5 py-0.5 text-xs font-normal text-black">
|
||||
{{ $leafCat['name'] }}
|
||||
</span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Title --}}
|
||||
<h3 class="text-lg font-semibold leading-tight truncate">
|
||||
{{ $result['title'] }}
|
||||
</h3>
|
||||
|
||||
{{-- Location + expiry badges --}}
|
||||
@if (!empty($result['location']) || !empty($result['expiry_badge_text']))
|
||||
<div class="mt-2 flex items-center gap-1 overflow-hidden">
|
||||
@if (!empty($result['location']))
|
||||
<span class="inline-block flex-shrink-0 rounded-sm bg-black px-1.5 pb-0.5 pt-0.5 text-xs font-normal uppercase text-white truncate max-w-[50%]">
|
||||
{{ $result['location'] }}
|
||||
</span>
|
||||
@endif
|
||||
@if (!empty($result['expiry_badge_text']))
|
||||
<span class="inline-block flex-shrink-0 rounded-sm bg-black px-1.5 pb-0.5 pt-0.5 text-xs font-normal uppercase text-white truncate max-w-[50%]">
|
||||
{{ $result['expiry_badge_text'] }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Callable avatar + name --}}
|
||||
@if (!empty($result['callable_name']))
|
||||
<div class="flex items-center gap-2 mt-3">
|
||||
@if (!empty($result['photo']))
|
||||
<div class="h-8 w-8 flex-shrink-0 rounded-full outline outline-1 outline-offset-1 outline-white/50 overflow-hidden">
|
||||
<img src="{{ $result['photo'] }}"
|
||||
alt="{{ $result['callable_name'] }}"
|
||||
class="h-full w-full object-cover" />
|
||||
</div>
|
||||
@endif
|
||||
<div class="flex flex-col min-w-0">
|
||||
<span class="text-xs font-medium truncate">{{ $result['callable_name'] }}</span>
|
||||
@if (!empty($result['callable_location']))
|
||||
<span class="text-xs text-white/70 truncate">{{ $result['callable_location'] }}</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- Prioritisation score --}}
|
||||
@if ($showScore)
|
||||
<div class="absolute bottom-3 right-3 z-30 text-xs text-white/70">
|
||||
{{ round($result['score'], 2) }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Reaction button --}}
|
||||
@if ($showReactions ?? true)
|
||||
<div class="absolute top-3 right-3 z-30">
|
||||
@livewire('reaction-button', [
|
||||
'typeName' => 'like',
|
||||
'showCounter' => true,
|
||||
'reactionCounter' => $result['like_count'],
|
||||
'modelClass' => $result['model'],
|
||||
'modelId' => $result['id'],
|
||||
'size' => 'w-5 h-5',
|
||||
'inverseColors' => true,
|
||||
], key('like-carousel-' . $result['id'] . '-' . $index))
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endforeach
|
||||
<div class="w-2 flex-shrink-0"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Left button — hidden at start --}}
|
||||
<button type="button"
|
||||
@mousedown.prevent.stop
|
||||
@click.prevent.stop="scrollLeft()"
|
||||
x-show="!atStart"
|
||||
x-cloak
|
||||
class="absolute left-2 top-1/2 -translate-y-1/2 z-20 flex h-9 w-9 items-center justify-center rounded-full bg-black text-white transition-all opacity-0 group-hover:opacity-100 group-hover:outline group-hover:outline-2 group-hover:outline-white group-hover:shadow-lg hover:outline-1"
|
||||
aria-label="{{ __('Scroll left') }}">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
{{-- Right button — hidden at end --}}
|
||||
<button type="button"
|
||||
@mousedown.prevent.stop
|
||||
@click.prevent.stop="scrollRight()"
|
||||
x-show="!atEnd"
|
||||
x-cloak
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 z-20 flex h-9 w-9 items-center justify-center rounded-full bg-black text-white transition-all opacity-0 group-hover:opacity-100 group-hover:outline group-hover:outline-2 group-hover:outline-white group-hover:shadow-lg hover:outline-1"
|
||||
aria-label="{{ __('Scroll right') }}">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
Reference in New Issue
Block a user