24-8: articles and legal pages — implemented, QA Review

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Naser Mansour
2026-10-31 18:54:18 +02:00
parent 7879ac7190
commit 2c068277a2
13 changed files with 203 additions and 129 deletions
@@ -278,7 +278,7 @@ new #[Layout('components.layouts.public')] class extends Component
@else
<section class="sec" style="padding-top:56px">
<div class="wrap">
<x-site.section-head :label="__('site.art_booking')" :title="__('booking.request_consultation')" :lede="__('site.booking_lede')" />
<x-site.section-head tag="h1" :label="__('site.art_booking')" :title="__('booking.request_consultation')" :lede="__('site.booking_lede')" />
<div class="book">
<div class="book-l on-dark">
@@ -55,91 +55,44 @@ new #[Layout('components.layouts.public')] class extends Component
}
}; ?>
<div class="wrap py-8">
<div class="max-w-4xl mx-auto px-0">
<flux:heading size="xl" class="text-body text-xl sm:text-2xl lg:text-3xl">{{ __('posts.posts') }}</flux:heading>
<!-- Search Bar -->
<div class="mt-4 sm:mt-6 relative">
<flux:input
wire:model.live.debounce.300ms="search"
placeholder="{{ __('posts.search_placeholder') }}"
class="w-full min-h-[44px]"
>
<x-slot:iconLeading>
<flux:icon name="magnifying-glass" class="w-5 h-5 text-body/50" />
</x-slot:iconLeading>
</flux:input>
<section class="sec" style="padding-top:56px">
<div class="wrap">
<x-site.section-head tag="h1" :label="__('site.hero_eyebrow')" :title="__('site.nav_articles')">
<div style="position:relative">
<label class="sr-only" for="posts-search">{{ __('posts.search_placeholder') }}</label>
<input
id="posts-search"
type="search"
class="search"
wire:model.live.debounce.300ms="search"
placeholder="{{ __('posts.search_placeholder') }}"
>
</div>
</x-site.section-head>
@if($search)
<button
wire:click="clearSearch"
class="absolute end-3 top-1/2 -translate-y-1/2 text-body/50 hover:text-body min-h-[44px] min-w-[44px] flex items-center justify-center"
>
<flux:icon name="x-mark" class="w-5 h-5" />
</button>
@endif
</div>
<!-- Search Results Info -->
@if($search)
<p class="mt-4 text-sm text-body/70">
@if($posts->total() > 0)
{{ __('posts.search_results', ['count' => $posts->total(), 'query' => $search]) }}
@else
{{ __('posts.no_results', ['query' => $search]) }}
@endif
</p>
@endif
<!-- Posts List -->
<div class="mt-6 sm:mt-8 space-y-4 sm:space-y-6">
@forelse($posts as $post)
<article wire:key="post-{{ $post->id }}" class="bg-card p-4 sm:p-6 rounded-lg shadow-card hover:shadow-card-hover transition-shadow">
<h2 class="text-lg sm:text-xl font-semibold text-text">
<a href="{{ route('posts.show', $post) }}" class="hover:text-cta" wire:navigate>
@if($search)
{!! $this->highlightSearch($post->getTitle(), $search) !!}
@else
{{ $post->getTitle() }}
@endif
</a>
</h2>
<time class="text-xs sm:text-sm text-body/70 mt-2 block">
{{ $post->published_at?->translatedFormat('d F Y') ?? $post->created_at->translatedFormat('d F Y') }}
</time>
<p class="mt-2 sm:mt-3 text-body text-sm sm:text-base">
@if($search)
{!! $this->highlightSearch($post->getExcerpt(), $search) !!}
@else
{{ $post->getExcerpt() }}
@endif
</p>
<a href="{{ route('posts.show', $post) }}" class="text-cta hover:text-cta-hover hover:underline mt-3 sm:mt-4 inline-flex items-center min-h-[44px]" wire:navigate>
{{ __('posts.read_more') }} &rarr;
</a>
</article>
@empty
<div class="empty-state bg-card rounded-lg">
@if($search)
<flux:icon name="magnifying-glass" class="empty-state-icon text-body/30" />
<p class="text-body/70">{{ __('posts.no_results', ['query' => $search]) }}</p>
<flux:button wire:click="clearSearch" class="mt-4">
{{ __('posts.clear_search') }}
</flux:button>
<p class="search-info">
@if($posts->total() > 0)
{{ __('posts.search_results', ['count' => $posts->total(), 'query' => $search]) }}
@else
<flux:icon name="document-text" class="empty-state-icon text-body/40" />
<p class="text-body/70">{{ __('posts.no_posts') }}</p>
{{ __('posts.no_results', ['query' => $search]) }}
@endif
</div>
@endforelse
</div>
<button type="button" class="btn btn-ghost" wire:click="clearSearch">{{ __('posts.clear_search') }}</button>
</p>
@endif
<div class="mt-8">
{{ $posts->links() }}
@if($posts->count() > 0)
<div class="posts posts-index">
@foreach($posts as $post)
<x-site.post-card :post="$post" wire:key="post-{{ $post->id }}" />
@endforeach
</div>
@elseif(! $search)
<p class="text-center" style="color:var(--muted)">{{ __('posts.no_posts') }}</p>
@endif
<div class="pagination-wrap">
{{ $posts->links() }}
</div>
</div>
</div>
</div>
</section>
@@ -18,24 +18,17 @@ new #[Layout('components.layouts.public')] class extends Component
}
}; ?>
<div class="wrap py-8">
<article class="max-w-3xl mx-auto">
<header class="mb-8">
<flux:heading size="xl" class="text-body">{{ $post->getTitle() }}</flux:heading>
<section class="sec" style="padding-top:56px">
<article class="wrap" style="max-width:768px">
<span class="meta">{{ $post->published_at?->translatedFormat('l, d F Y') ?? $post->created_at->translatedFormat('l, d F Y') }}</span>
<h1 style="font-size:clamp(2rem,3.4vw,3rem);margin:10px 0 28px">{{ $post->getTitle() }}</h1>
<time class="text-body/70 mt-2 block">
{{ $post->published_at?->translatedFormat('l, d F Y') ?? $post->created_at->translatedFormat('l, d F Y') }}
</time>
</header>
<div class="prose prose-lg prose-brand max-w-none site-prose">
{!! $post->getBody() !!}
</div>
<div class="prose prose-lg prose-brand max-w-none">
{!! $post->getBody() !!}
</div>
<footer class="mt-12 pt-6 border-t border-cta/20">
<a href="{{ route('posts.index') }}" class="text-cta hover:text-cta-hover hover:underline" wire:navigate>
&larr; {{ __('posts.back_to_posts') }}
</a>
</footer>
</article>
</div>
<footer style="border-top:1px solid var(--line);margin-top:48px;padding-top:24px">
<a class="btn btn-ghost" href="{{ route('posts.index') }}" wire:navigate>{{ __('posts.back_to_posts') }}</a>
</footer>
</article>
</section>