Initial commit

This commit is contained in:
Ronald Huynen
2026-03-23 21:37:59 +01:00
commit 2547717edb
2193 changed files with 972171 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
<div>
@if ($post != null)
<div class="relative flex flex-col justify-end overflow-hidden bg-theme-background max-h-[600px] lg:max-h-[800px] my-9">
<a class="relative flex cursor-pointer flex-col justify-end overflow-hidden bg-theme-background max-h-[600px] lg:max-h-[800px]"
href="{{ route('post.show_by_slug', [$post->slug]) }}">
<!-- Photo as background -->
@if ($media != null)
<div class="absolute inset-0 z-0 h-full w-full">
{{ $media('4_3', ['class' => 'absolute inset-0 z-0 h-full w-full object-cover blur-[1px]']) }}
</div>
@else
<!-- Default background if no image -->
<div class="absolute inset-0 z-0 h-full w-full bg-gradient-to-br from-primary-700 to-theme-brand"></div>
@endif
<!-- Optional overlay for contrast -->
<div class="absolute inset-0 z-10 bg-black bg-opacity-65"></div>
<!-- All card content on top of photo -->
<div class="relative z-20 flex h-full flex-col justify-between px-6 md:px-10 lg:px-14 py-14 md:py-14 lg:py-20 text-white">
<div class="space-y-3">
<div class="flex items-start gap-4">
<h2 class="text text-3xl lg:text-4xl font-semibold leading-tight pr-16 md:pr-20">
{{ $post->title }}
</h2>
</div>
<div>
<h4 class="inline-block items-center rounded-sm bg-theme-brand px-2 pb-1 pt-0.5 text-sm lg:text-base font-normal">
{{ $post->category }}
</h4>
</div>
</div>
<div class="mx-6 my-4 flex items-center justify-center">
@if (isset($post->excerpt))
<p class="w-full text-base md:text-xl font-normal leading-relaxed line-clamp-8">
{{ $post->excerpt }}
</p>
@endif
</div>
<!-- Bottom section: author info -->
<div class="flex flex-wrap items-end gap-4">
<h2 class="text-lg md:text-2xl ml-auto pt-3 font-semibold text-white">
{{ $post->author }}
</h2>
</div>
</div>
</a>
</div>
@endif
</div>

View 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>

View File

@@ -0,0 +1,95 @@
<div>
@if ($call !== null)
<div class="relative flex flex-col justify-end overflow-hidden bg-theme-background my-9">
<a class="relative flex cursor-pointer flex-col justify-end overflow-hidden bg-{{ $call['tag_color'] ?? 'gray' }}-400"
href="{{ route('call.show', ['id' => $call['id']]) }}">
<!-- Tag color background + overlay -->
<div class="absolute inset-0 z-0 bg-{{ $call['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 px-6 md:px-10 lg:px-14 py-14 md:py-14 lg:py-20 text-white">
<div class="space-y-3">
{{-- Deepest tag category badge only --}}
@php $deepestCat = !empty($call['tag_categories']) ? last($call['tag_categories']) : null; @endphp
@if ($deepestCat)
<div class="flex flex-wrap items-center gap-2 pr-16 md:pr-20">
<span class="bg-{{ $deepestCat['color'] ?? 'gray' }}-400 inline-flex items-center rounded-md px-2 py-1 text-sm font-normal text-black">
{{ $deepestCat['name'] }}
</span>
</div>
@endif
{{-- Title --}}
<h2 class="text text-3xl lg:text-4xl font-semibold leading-tight pr-16 md:pr-20 line-clamp-2">
{{ $call['title'] }}
</h2>
{{-- Location + expiry badges --}}
@if (!empty($call['location']) || !empty($call['expiry_badge_text']))
<div class="flex flex-wrap items-center gap-2">
@if (!empty($call['location']))
<h4 class="inline-block items-center rounded-sm bg-black px-2 pb-1 pt-0.5 text-sm lg:text-base font-normal uppercase text-white">
{{ $call['location'] }}
</h4>
@endif
@if (!empty($call['expiry_badge_text']))
<h4 class="inline-block items-center rounded-sm bg-black px-2 pb-1 pt-0.5 text-sm lg:text-base font-normal uppercase text-white">
{{ $call['expiry_badge_text'] }}
</h4>
@endif
</div>
@endif
</div>
{{-- Excerpt --}}
@if (!empty($call['excerpt']))
<div class="mx-6 my-4 flex items-center justify-center">
<p class="w-full text-base md:text-xl font-normal leading-relaxed line-clamp-2">
{{ $call['excerpt'] }}
</p>
</div>
@endif
{{-- Callable avatar + name + location --}}
@if (!empty($call['callable_name']))
<div class="flex flex-wrap items-end gap-4 mt-4">
<div class="flex items-center gap-3">
@if (!empty($call['photo']))
<div class="h-16 w-16 flex-shrink-0 rounded-full outline outline-1 outline-offset-1 outline-white/50 overflow-hidden">
<img src="{{ $call['photo'] }}"
alt="{{ $call['callable_name'] }}"
class="h-full w-full object-cover" />
</div>
@endif
<div class="flex flex-col gap-1 text-sm">
<span class="font-medium">{{ $call['callable_name'] }}</span>
@if (!empty($call['callable_location']))
<span class="text-white/80">{{ $call['callable_location'] }}</span>
@endif
</div>
</div>
</div>
@endif
</div>
</a>
<!-- Like button positioned absolutely outside anchor tag -->
<div class="absolute top-14 right-4 md:right-10 lg:right-14 z-30">
@livewire('reaction-button', [
'typeName' => 'like',
'showCounter' => true,
'reactionCounter' => $call['like_count'],
'modelClass' => $call['model'],
'modelId' => $call['id'],
'size' => 'w-10 h-10',
'inverseColors' => true,
], key('like-call-main-' . $call['id']))
</div>
</div>
@endif
</div>

View File

@@ -0,0 +1,25 @@
<div>
@if (!empty($calls))
<div class="flex flex-col gap-6 m-6">
@foreach (collect($calls)->chunk(2) as $row)
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
@foreach ($row as $index => $call)
<x-call-card
:result="$call"
:index="$index"
:show-score="$showScore"
:show-callable="true"
:show-reactions="$showReactions ?? true"
:photo-blur="$guestPhotoBlur ?? 0"
:photo-contrast="$guestPhotoContrast ?? 100"
:photo-saturate="$guestPhotoSaturate ?? 100"
:photo-brightness="$guestPhotoBrightness ?? 100"
height-class="h-[430px] md:h-[550px] lg:h-[430px]"
:truncate-excerpt="true"
/>
@endforeach
</div>
@endforeach
</div>
@endif
</div>

View File

@@ -0,0 +1,74 @@
<div>
@if ($post != null)
<div class="relative flex flex-col justify-end overflow-hidden bg-theme-background max-h-[600px] lg:max-h-[800px] my-9">
<a class="relative flex cursor-pointer flex-col justify-end overflow-hidden bg-theme-background max-h-[600px] lg:max-h-[800px]"
href="{{ route('post.show_by_slug', [$post->slug]) }}">
<!-- Photo as background -->
@if ($media != null)
<div class="absolute inset-0 z-0 h-full w-full">
{{ $media('4_3', ['class' => 'absolute inset-0 z-0 h-full w-full object-cover blur-[1px]']) }}
</div>
@else
<!-- Default background if no image -->
<div class="absolute inset-0 z-0 h-full w-full bg-gradient-to-br from-primary-700 to-theme-brand"></div>
@endif
<!-- Optional overlay for contrast -->
<div class="absolute inset-0 z-10 bg-black bg-opacity-65"></div>
<!-- All card content on top of photo -->
<div class="relative z-20 flex h-full flex-col justify-between px-6 md:px-10 lg:px-14 py-14 md:py-14 lg:py-20 text-white">
<div class="space-y-3">
<div class="flex items-start gap-4">
<h2 class="text text-3xl lg:text-4xl font-semibold leading-tight pr-16 md:pr-20">
{{ $post->title }}
</h2>
</div>
<div>
<h4 class="inline-block items-center rounded-sm bg-theme-brand px-2 pb-1 pt-0.5 text-sm lg:text-base font-normal">
{{ $post->category }}
</h4>
</div>
</div>
<div class="mx-6 my-4 flex items-center justify-center">
@if (isset($post->excerpt))
<p class="w-full text-base md:text-xl font-normal leading-relaxed line-clamp-8">
{{ $post->excerpt }}
</p>
@endif
</div>
<!-- Bottom section: author and address -->
<div class="flex flex-wrap items-end gap-4">
<h2 class="text-lg md:text-2xl ml-auto pt-3 font-semibold text-white">
@if (isset($post->venue))
{{ $post->venue . ' ' . $post->city}}
@endif
@if (isset($post->from))
<span class="text-center font-semibold">
&nbsp; {{ Illuminate\Support\Carbon::parse($post->from)->translatedFormat('d F') }}
&nbsp; {{ Illuminate\Support\Carbon::parse($post->from)->format('H:i') . ' ' . __('messages.hour_abbrevation') }}
</span>
@endif
</h2>
</div>
</div>
</a>
<!-- Like button positioned absolutely outside anchor tag -->
<div class="absolute top-14 right-4 md:right-10 lg:right-14 z-30">
@livewire('reaction-button', [
'typeName' => 'like',
'showCounter' => true,
'reactionCounter' => $post['like_count'],
'modelClass' => $post['model'],
'modelId' => $post['id'],
'size' => 'w-10 h-10',
'inverseColors' => true,
], key('like-' . $post['model'] . '-' . $post['id'] . '-' . $postNr))
</div>
</div>
@endif
</div>

View File

@@ -0,0 +1,135 @@
<div x-data="{
showFullscreen: false,
async toggleFullscreen() {
if (!this.showFullscreen) {
this.showFullscreen = true;
await this.$nextTick();
const elem = this.$refs.fullscreenModal;
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.webkitRequestFullscreen) {
elem.webkitRequestFullscreen();
} else if (elem.msRequestFullscreen) {
elem.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
this.showFullscreen = false;
}
}
}"
@fullscreenchange.window="if (!document.fullscreenElement) { showFullscreen = false }"
@webkitfullscreenchange.window="if (!document.webkitFullscreenElement) { showFullscreen = false }"
@msfullscreenchange.window="if (!document.msFullscreenElement) { showFullscreen = false }">
@if ($post != null)
<div class="relative flex flex-col bg-theme-background my-9">
<!-- Caption overlay calculation -->
@php
$bottomText = '';
$isLink = false;
$linkUrl = '';
$mediaOwner = isset($post->media_owner) && !empty($post->media_owner) ? $post->media_owner : '';
if (isset($post->author_id) && !empty($post->author_id)) {
$bottomText = $post->author;
$isLink = true;
$linkUrl = url('user/' . $post->author_id);
} elseif (isset($post->media_caption) && !empty($post->media_caption)) {
$bottomText = $post->media_caption;
} elseif (isset($post->content) && !empty($post->content)) {
$bottomText = strip_tags($post->content);
}
@endphp
<div class="relative flex flex-col justify-center overflow-hidden bg-theme-background {{ !$media ? 'pt-32 pb-32' : '' }}">
<!-- Photo - full width within container -->
@if ($media != null)
<div @click="toggleFullscreen()" class="w-full mx-auto max-w-7xl cursor-pointer">
{{ $media('hero', ['class' => 'w-full h-auto']) }}
</div>
<!-- Caption overlaid on image - positioned like author in article card -->
@if (!empty($bottomText) || !empty($mediaOwner))
<div class="absolute bottom-0 w-full">
<div class="w-full mx-auto max-w-7xl px-6 md:px-10 lg:px-14 py-4 md:py-6 lg:py-8">
<div class="flex flex-col items-end gap-1">
@if (!empty($bottomText))
<h4 class="inline-flex items-center gap-2 rounded-sm bg-theme-brand px-3 pb-1.5 pt-1 text-base lg:text-xl font-normal text-white">
@if ($isLink && isset($post->author_profile_photo_path) && $post->author_profile_photo_path)
<a href="{{ $linkUrl }}" @click.stop class="flex-shrink-0">
<img src="{{ Storage::url($post->author_profile_photo_path) }}"
alt="{{ $bottomText }}"
class="w-5 h-5 lg:w-6 lg:h-6 rounded-full profile-photo object-cover">
</a>
@endif
@if ($isLink)
<a href="{{ $linkUrl }}" @click.stop class="text-white hover:underline">
{{ $bottomText }}
</a>
@else
{{ $bottomText }}
@endif
</h4>
@endif
@if (!empty($mediaOwner))
<h6 class="inline-block items-center rounded-sm bg-theme-brand mt-1 px-2 pb-0.5 pt-0.5 text-xs lg:text-sm font-normal text-white">
{{ $mediaOwner }}
</h6>
@endif
</div>
</div>
</div>
@endif
<!-- Excerpt text centered - big like article title (only if no media) -->
@elseif (isset($post->excerpt) && !empty($post->excerpt))
<div class="flex items-center justify-center px-6 md:px-10 lg:px-14">
<h2 class="text-3xl lg:text-5xl font-semibold leading-tight text-center text-theme-text-background bg-theme-brand p-6 m-8">
{{ $post->excerpt }}
</h2>
</div>
@endif
</div>
</div>
<!-- Full-screen modal -->
<div x-show="showFullscreen"
x-ref="fullscreenModal"
@click="toggleFullscreen()"
class="fixed inset-0 z-50 flex items-center justify-center bg-black"
style="display: none;">
@if ($media != null)
<div class="relative w-full h-full flex items-center justify-center p-4">
<!-- Close button -->
{{-- <button @click="toggleFullscreen()"
class="absolute top-4 right-4 z-10 text-white hover:text-gray-300 transition-colors">
<svg class="w-8 h-8" 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> --}}
<!-- Full-screen image - use first (largest) responsive image -->
@php
// Get the largest responsive image URL (first in array = largest)
$responsiveImages = $media->getResponsiveImageUrls('hero');
$largestImageUrl = !empty($responsiveImages) ? reset($responsiveImages) : $media->getUrl('hero');
@endphp
<img src="{{ $largestImageUrl }}"
alt="{{ $post->title ?? '' }}"
class="max-w-full max-h-full object-contain"
loading="eager">
</div>
@endif
</div>
@endif
</div>

View File

@@ -0,0 +1,127 @@
<div x-data="{
showFullscreen: false,
async toggleFullscreen() {
if (!this.showFullscreen) {
this.showFullscreen = true;
await this.$nextTick();
const elem = this.$refs.fullscreenModal;
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.webkitRequestFullscreen) {
elem.webkitRequestFullscreen();
} else if (elem.msRequestFullscreen) {
elem.msRequestFullscreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
this.showFullscreen = false;
}
}
}"
@fullscreenchange.window="if (!document.fullscreenElement) { showFullscreen = false }"
@webkitfullscreenchange.window="if (!document.webkitFullscreenElement) { showFullscreen = false }"
@msfullscreenchange.window="if (!document.msFullscreenElement) { showFullscreen = false }">
@if ($post != null)
<div class="relative flex flex-col bg-theme-background">
<!-- Caption overlay calculation -->
@php
$bottomText = '';
$isLink = false;
$linkUrl = '';
$mediaOwner = isset($post->media_owner) && !empty($post->media_owner) ? $post->media_owner : '';
if (isset($post->author_id) && !empty($post->author_id)) {
$bottomText = $post->author;
$isLink = true;
$linkUrl = url('user/' . $post->author_id);
} elseif (isset($post->media_caption) && !empty($post->media_caption)) {
$bottomText = $post->media_caption;
} elseif (isset($post->content) && !empty($post->content)) {
$bottomText = strip_tags($post->content);
}
@endphp
<div class="relative flex flex-col justify-center overflow-hidden bg-theme-background {{ !$media ? 'pt-32 pb-32' : '' }}">
<!-- Photo - full width within container -->
@if ($media != null)
<div @click="toggleFullscreen()" class="w-full mx-auto max-w-7xl cursor-pointer">
{{ $media('hero', ['class' => 'w-full h-auto']) }}
</div>
<!-- Caption overlaid on image - positioned like author in article card -->
@if (!empty($bottomText) || !empty($mediaOwner))
<div class="absolute bottom-0 w-full">
<div class="w-full mx-auto max-w-7xl px-6 md:px-10 lg:px-14 py-4 md:py-6 lg:py-8">
<div class="flex flex-col items-end gap-1">
@if (!empty($bottomText))
<h4 class="inline-flex items-center gap-2 rounded-sm bg-theme-brand px-3 pb-1.5 pt-1 text-base lg:text-xl font-normal text-white">
@if ($isLink && isset($post->author_profile_photo_path) && $post->author_profile_photo_path)
<a href="{{ $linkUrl }}" @click.stop class="flex-shrink-0">
<img src="{{ Storage::url($post->author_profile_photo_path) }}"
alt="{{ $bottomText }}"
class="w-5 h-5 lg:w-6 lg:h-6 rounded-full profile-photo object-cover">
</a>
@endif
@if ($isLink)
<a href="{{ $linkUrl }}" @click.stop class="text-white hover:underline">
{{ $bottomText }}
</a>
@else
{{ $bottomText }}
@endif
</h4>
@endif
@if (!empty($mediaOwner))
<h6 class="inline-block items-center rounded-sm bg-theme-brand mt-1 px-2 pb-0.5 pt-0.5 text-xs lg:text-sm font-normal text-white">
{{ $mediaOwner }}
</h6>
@endif
</div>
</div>
</div>
@endif
<!-- Excerpt text centered - big like article title (only if no media) -->
@elseif (isset($post->excerpt) && !empty($post->excerpt))
<div class="flex items-center justify-center px-6 md:px-10 lg:px-14">
<h2 class="text-3xl lg:text-5xl font-semibold leading-tight text-center text-theme-text-background bg-theme-brand p-6 m-8">
{{ $post->excerpt }}
</h2>
</div>
@endif
</div>
</div>
<!-- Full-screen modal -->
<div x-show="showFullscreen"
x-ref="fullscreenModal"
@click="toggleFullscreen()"
class="fixed inset-0 z-50 flex items-center justify-center bg-black"
style="display: none;">
@if ($media != null)
<div class="relative w-full h-full flex items-center justify-center p-4">
<!-- Full-screen image - use first (largest) responsive image -->
@php
// Get the largest responsive image URL (first in array = largest)
$responsiveImages = $media->getResponsiveImageUrls('hero');
$largestImageUrl = !empty($responsiveImages) ? reset($responsiveImages) : $media->getUrl('hero');
@endphp
<img src="{{ $largestImageUrl }}"
alt="{{ $post->title ?? '' }}"
class="max-w-full max-h-full object-contain"
loading="eager">
</div>
@endif
</div>
@endif
</div>

View File

@@ -0,0 +1,60 @@
<div>
@if ($post != null)
<div class="relative flex flex-col justify-end overflow-hidden bg-theme-background max-h-[600px] lg:max-h-[800px] my-9">
<a class="relative flex cursor-pointer flex-col justify-end overflow-hidden bg-theme-background max-h-[600px] lg:max-h-[800px]"
href="{{ route('post.show_by_slug', [$post->slug]) }}">
<!-- Photo as background -->
@if ($media != null)
<div class="absolute inset-0 z-0 h-full w-full">
{{ $media('4_3', ['class' => 'absolute inset-0 z-0 h-full w-full object-cover blur-[1px]']) }}
</div>
@else
<!-- Default background if no image -->
<div class="absolute inset-0 z-0 h-full w-full bg-gradient-to-br from-primary-700 to-theme-brand"></div>
@endif
<!-- Optional overlay for contrast -->
<div class="absolute inset-0 z-10 bg-black bg-opacity-65"></div>
<!-- All card content on top of photo -->
<div class="relative z-20 flex h-full flex-col justify-between px-6 md:px-10 lg:px-14 py-14 md:py-14 lg:py-20 text-white">
<div class="space-y-3">
<div class="flex items-start gap-4">
<h2 class="text text-3xl lg:text-4xl font-semibold leading-tight pr-16 md:pr-20">
{{ $post->title }}
</h2>
</div>
<div>
<h4 class="inline-block items-center rounded-sm bg-theme-brand px-2 pb-1 pt-0.5 text-sm lg:text-base font-normal">
{{ $post->category }}
</h4>
<h4 class="inline-block items-center rounded-sm bg-theme-brand ml-3 px-2 pb-1 pt-0.5 text-sm lg:text-base font-normal">
@if (isset($post->from))
<span class="">
{{ Illuminate\Support\Carbon::parse($post->from)->translatedFormat('l, j F') }}
</span>
@endif
</h4>
</div>
</div>
<div class="mx-6 my-4 flex items-center justify-center">
@if (isset($post->excerpt))
<p class="w-full text-base md:text-xl font-normal leading-relaxed line-clamp-8">
{{ $post->excerpt }}
</p>
@endif
</div>
<!-- Bottom section: author info -->
<div class="flex flex-wrap items-end gap-4">
<h2 class="text-lg md:text-2xl ml-auto pt-3 font-semibold text-white">
{{ $post->author }}
</h2>
</div>
</div>
</a>
</div>
@endif
</div>

View File

@@ -0,0 +1,236 @@
<div class="col-span-6">
<div>
<!-- Skills -->
<x-jetstream.label for="tags" value="{{ $label }}"
wire:loading.remove />
<x-jetstream.label for="tags" value="{{ __('Loading...') }}" wire:loading />
<div wire:ignore>
<input class="w-full" data-suggestions='@json($suggestions)' id="tags"
placeholder="{{ __('Select or create a new tag title') }}" type="text"
value="{{ $tagsArray }}" x-data="{ input: @entangle('tagsArray').live }"
x-ref="input"
style="color: white;"
>
</div>
<div class="col-span-6 my-3 flex items-center justify-end px-0 pb-3 text-right">
<div class="grid grid-cols-1 gap-6" wire:loading wire:target="tagsArray">
<x-mini-button flat icon="" primary rounded spinner /> <span>
</span>
</div>
@if ($tagsArrayChanged)
<div class="text-sm text-theme-primary mr-3">
{{ __('You have unsaved changes')}}
</div>
@endif
<x-jetstream.action-message class="mr-3" on="saved">
{{ __('Saved') }}
</x-jetstream.action-message>
<x-jetstream.button
wire:click="saveDisabled === true ? $dispatch('updatedTagsArray') : $dispatch('save')"
wire:target="save"
wire:loading.attr="disabled"
wire:key="saveTagsArrayButton">
{{ __('Save') }}
</x-jetstream.button>
</div>
</div>
<!---- New Tag Modal ---->
@if ($newTag)
<form wire:submit.prevent="createTag">
<x-jetstream.dialog-modal wire:model.live="modalVisible">
<x-slot name="title">
{{ str_replace('@PLATFORM_NAME@', platform_name(), __('Add a new activity or skill to @PLATFORM_NAME@')) }}
</x-slot>
<x-slot name="content">
<div class='my-3 text-xl'>
<span
class="bg-{{ $categoryColor }}-300 inline-flex items-center rounded-md px-3 py-2 text-sm font-normal">
{{ $newTag['name'] }}
</span>
</div>
<div class="mt-6 grid grid-cols-1 gap-6">
<x-input label="{{ __('Activity tag (min. 2 words)') }}"
placeholder="{{ __('Accurate and unique name for this activity, avoid vague or general keywords') }}"
wire:model.live="newTag.name" />
</div>
@if (!$sessionLanguageOk)
<div class="mt-3 grid grid-cols-1 gap-6">
@php $locale = app()->getLocale();
$localeName = \Locale::getDisplayName($locale, $locale);
@endphp
<x-checkbox :disabled="$sessionLanguageOk" id="sessionLang-ignore-checkbox"
label="{{ __('This tag is in :locale.', [
'locale' => $localeName
]) }}"
wire:model.live="sessionLanguageIgnored" />
</div>
@endif
@if ($translationPossible && $translationAllowed)
<div class="mt-6 grid grid-cols-1 gap-6 ">
<x-checkbox id="checkbox"
label="{{ __('Attach a translation to this tag (recommended)') }}"
wire:model.live="translationVisible" />
</div>
<div class="mt-6 grid grid-cols-1 gap-6" wire:loading wire:target="translationVisible">
<x-mini-button flat icon="" primary rounded spinner /> <span>
{{ __('Loading...') }}
</span>
</div>
@endif
<!-- Tag Translation --->
<div>
@if ($translationVisible)
<div class="my-6 grid grid-cols-1 gap-6 pl-8 md:grid-cols-2"
id='select-translation-language'>
<x-select :options="$translationLanguages" class="placeholder-theme-light"
id="translation-language" label="{{__('Translation language')}}" option-label="name"
option-value="lang_code" placeholder="{{ __('Select a translation language') }}"
wire:model.live="selectTranslationLanguage"/>
</div>
<div class="grid grid-cols-1 gap-6 pl-8" wire:loading wire:target="selectTranslationLanguage">
<x-mini-button flat icon="" primary rounded spinner /> <span>
{{ __('Loading...') }}
</span>
</div>
@if ($selectTranslationLanguage)
@php
if ($selectTranslationLanguage) {
$translationLang = App\Models\Language::where('lang_code', $selectTranslationLanguage)->first()->name;
} else {
$translationLang = "...";
}
@endphp
<hr class="border-t border-theme-primary" py-12 />
<x-radio id="radio-select"
label="{{ str_replace('@LANGUAGE@', $translationLang, __('Select an existing, untranslated activity tag in @LANGUAGE@')) }}"
value="select" wire:model.live="translateRadioButton" />
<div class="my-6 grid grid-cols-1 gap-6 pl-8 md:grid-cols-2"
id='select-translation'>
@if (count($translationOptions) > 0)
<x-select
:disabled="$translateRadioButton === 'input'"
:options="$translationOptions"
class="placeholder-theme-light"
id="translation"
label=""
option-label="name"
option-value="tag_id"
placeholder="{{ __('Select a translation') }}"
wire:model.live="selectTagTranslation"
/>
@else
<x-select
:disabled="count($translationOptions) < 1 || $translateRadioButton === 'input'"
:options="count($translationOptions) > 0
? $translationOptions
: [['tag_id' => '', 'name' => __('No translations available'), 'disabled' => true]]"
class="placeholder-theme-light"
id="translation"
label=""
option-label="name"
option-value="tag_id"
placeholder="{{ __('No existing translation available') }}"
wire:model.live="selectTagTranslation"
/>
@endif
<div class="mt-6 grid grid-cols-1 gap-6" wire:loading
wire:target="translationOptions">
{{ __('Updating...') }}
</div>
</div>
<hr class="border-t border-theme-primary" py-12 />
<x-radio id="radio-input"
label="{{ str_replace('@LANGUAGE@', $translationLang, __('Or create a new Activity tag in @LANGUAGE@')) }}"
value="input" wire:model.live="translateRadioButton" />
<div id="input-translation">
<div class="mt-6 grid grid-cols-1 gap-6 pl-8">
<x-input :disabled="$translateRadioButton === 'select'"
label="{{ str_replace('@LANGUAGE@', $translationLang, __('Activity tag in @LANGUAGE@ (min. 2 words)')) }}"
placeholder="{{ !empty($newTag['name'])
? '\'' . $newTag['name'] . '\'' . ' ' . __('in') . ' ' . $translationLang
: __('Activity tag name in') . ' ' . $translationLang }}"
wire:key="nameInput" wire:model.live="inputTagTranslation.name" />
@if (!$transLanguageOk)
<div class="grid grid-cols-1 gap-6 transition-opacity duration-1500 ease-in-out opacity-100">
@php $localeTranslation = $selectTranslationLanguage ?? '';
$localeNameTranslation = \Locale::getDisplayName($localeTranslation, $localeTranslation);
@endphp
<x-checkbox :disabled="$translateRadioButton === 'select'" id="transLang-ignore-checkbox"
label="{{ __('This tag is in :localeTranslation.', [
'localeTranslation' => $localeNameTranslation
]) }}"
wire:model.live="transLanguageIgnored"
/>
</div>
@endif
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
<x-select :disabled="$translateRadioButton === 'select'" :options="$categoryOptions"
class="placeholder-theme-light" id="category"
label="{{ __('Category') }}" option-label="name"
option-value="category_id"
placeholder="{{ __('Select a category') }}"
wire:model.live="newTagCategory" />
</div>
</div>
</div>
@endif
</div>
@endif
@if (!$translationVisible || !$translationAllowed)
<div class="mt-3 grid grid-cols-1 gap-6 md:grid-cols-2">
<x-select :options="$categoryOptions" class="placeholder-theme-light" id="category"
label="{{ __('Category') }}" option-label="name" option-value="category_id"
placeholder="{{ __('Select a category') }}"
wire:model.live="newTagCategory" />
</div>
@endif
<div class="pt-10 my-3 grid grid-cols-1">
<x-skill-tag-warning />
</div>
{{-- <x-errors /> --}}
</x-slot>
<x-slot name="footer">
<x-jetstream.secondary-button wire:click="cancelCreateTag" wire:loading.attr="disabled">
{{ __('Cancel') }}
</x-jetstream.secondary-button>
<x-jetstream.secondary-button class="ml-3"
wire:click="createTag"
wire:key="createTagButton"
wire:loading.attr="disabled">
{{ __('Save') }}
</x-jetstream.secondary-button>
</x-slot>
</x-jetstream.dialog-modal>
</form>
@endif
<script src="{{ asset('js/skilltags.js') }}"></script>
<script>
document.addEventListener('livewire:load', () => {
// Listener for page reload event
document.addEventListener('reloadPage', () => {
window.location.reload();
});
});
</script>
</div>