feat: product badges and show page layout
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
029689407b
commit
9920fafab6
@@ -133,6 +133,26 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Badges -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Badges
|
||||
</label>
|
||||
<div class="mt-1 grid grid-cols-2 sm:grid-cols-4 gap-3">
|
||||
@foreach(\App\Models\Product::BADGES as $key => $label)
|
||||
<label class="flex items-center p-3 border border-gray-300 rounded-md">
|
||||
<input type="hidden" name="{{ $key }}" value="0">
|
||||
<input type="checkbox"
|
||||
name="{{ $key }}"
|
||||
value="1"
|
||||
{{ old($key, false) ? 'checked' : '' }}
|
||||
class="focus:ring-primary-500 h-4 w-4 text-primary-600 border-gray-300 rounded">
|
||||
<span class="ml-2 text-sm text-gray-900">{{ $label }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Thumbnail -->
|
||||
<div>
|
||||
<label for="thumbnail" class="block text-sm font-medium text-gray-700">
|
||||
|
||||
@@ -139,6 +139,34 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@php
|
||||
$badgesLocked = $product->status === 'approved' && !auth()->user()->hasAnyRole(['moderator', 'admin']);
|
||||
@endphp
|
||||
|
||||
<!-- Badges -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Badges
|
||||
</label>
|
||||
<div class="mt-1 grid grid-cols-2 sm:grid-cols-4 gap-3">
|
||||
@foreach(\App\Models\Product::BADGES as $key => $label)
|
||||
<label class="flex items-center p-3 border border-gray-300 rounded-md">
|
||||
<input type="hidden" name="{{ $key }}" value="0">
|
||||
<input type="checkbox"
|
||||
name="{{ $key }}"
|
||||
value="1"
|
||||
{{ old($key, $product->{$key}) ? 'checked' : '' }}
|
||||
{{ $badgesLocked ? 'disabled' : '' }}
|
||||
class="focus:ring-primary-500 h-4 w-4 text-primary-600 border-gray-300 rounded">
|
||||
<span class="ml-2 text-sm text-gray-900">{{ $label }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
@if($badgesLocked)
|
||||
<p class="mt-2 text-sm text-gray-500">Locked after approval</p>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Current Thumbnail -->
|
||||
@if($product->thumbnail_url)
|
||||
<div>
|
||||
|
||||
@@ -53,6 +53,18 @@
|
||||
<span>•</span>
|
||||
<span>{{ $product->created_at->format('M j, Y') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<x-product.badges :product="$product" />
|
||||
</div>
|
||||
|
||||
@if($product->tags->isNotEmpty())
|
||||
<div class="mt-3 flex flex-wrap gap-x-3 gap-y-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
@foreach($product->tags as $tag)
|
||||
<span>#{{ $tag->name }}</span>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
@@ -105,69 +117,78 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Product Content -->
|
||||
<div class="px-6 py-8">
|
||||
<!-- Product Thumbnail -->
|
||||
@if($product->thumbnail_url)
|
||||
<div class="mb-8 rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700">
|
||||
<img src="{{ $product->thumbnail_url }}"
|
||||
alt="{{ $product->title }}"
|
||||
class="w-full h-auto max-h-96 object-contain bg-gray-50 dark:bg-gray-900">
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Product Description -->
|
||||
<div class="mb-8">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">About</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 text-lg leading-relaxed whitespace-pre-line">{{ $product->description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Visit Website Button -->
|
||||
<div class="mb-8">
|
||||
<a href="{{ $product->website_url }}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 shadow-sm">
|
||||
Visit Website
|
||||
<svg class="ml-2 h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Product Metadata -->
|
||||
@if($product->isApproved() && $product->approved_at)
|
||||
<div class="pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<dl class="grid grid-cols-1 gap-x-4 gap-y-4 sm:grid-cols-2">
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Submitted by</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
|
||||
<a href="{{ route('profile.show', $product->user) }}" class="hover:text-primary-600 dark:hover:text-primary-400">
|
||||
{{ $product->user->name }}
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Submitted on</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $product->created_at->format('F j, Y') }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Approved on</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $product->approved_at->format('F j, Y') }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Category</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $product->category->name }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gallery -->
|
||||
<!-- slot:gallery -->
|
||||
|
||||
<div class="mt-6 grid grid-cols-1 lg:grid-cols-4 gap-6">
|
||||
<!-- Main column -->
|
||||
<div class="lg:col-span-3 space-y-6">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 px-6 py-8">
|
||||
<!-- Product Thumbnail -->
|
||||
@if($product->thumbnail_url)
|
||||
<div class="mb-8 rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700">
|
||||
<img src="{{ $product->thumbnail_url }}"
|
||||
alt="{{ $product->title }}"
|
||||
class="w-full h-auto max-h-96 object-contain bg-gray-50 dark:bg-gray-900">
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Product Description -->
|
||||
<div class="mb-8">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">About</h2>
|
||||
<p class="text-gray-700 dark:text-gray-300 text-lg leading-relaxed whitespace-pre-line">{{ $product->description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Visit Website Button -->
|
||||
<div class="mb-8">
|
||||
<a href="{{ $product->website_url }}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 shadow-sm">
|
||||
Visit Website
|
||||
<svg class="ml-2 h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Product Metadata -->
|
||||
@if($product->isApproved() && $product->approved_at)
|
||||
<div class="pt-6 border-t border-gray-200 dark:border-gray-700">
|
||||
<dl class="grid grid-cols-1 gap-x-4 gap-y-4 sm:grid-cols-2">
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Submitted by</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">
|
||||
<a href="{{ route('profile.show', $product->user) }}" class="hover:text-primary-600 dark:hover:text-primary-400">
|
||||
{{ $product->user->name }}
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Submitted on</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $product->created_at->format('F j, Y') }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Approved on</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $product->approved_at->format('F j, Y') }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">Category</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 dark:text-white">{{ $product->category->name }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<!-- slot:pricing -->
|
||||
|
||||
<!-- slot:alternatives -->
|
||||
|
||||
<!-- Comments Section -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700 mt-6">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700">
|
||||
<div class="px-6 py-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">
|
||||
Comments ({{ $product->comments()->count() }})
|
||||
@@ -259,6 +280,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar column -->
|
||||
<div class="lg:col-span-1 space-y-6">
|
||||
<!-- slot:team -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Moderator Actions -->
|
||||
@can('approve-product')
|
||||
|
||||
Reference in New Issue
Block a user