This commit is contained in:
221
resources/views/shop/product.blade.php
Normal file
221
resources/views/shop/product.blade.php
Normal file
@@ -0,0 +1,221 @@
|
||||
@extends('layouts.shop')
|
||||
|
||||
@php
|
||||
$productGallery = $product->gallery_urls;
|
||||
$productImage = $productGallery[0] ?? ($product->image_url ?: config('seo.default_image'));
|
||||
$productImageUrl = str_starts_with($productImage, 'http://') || str_starts_with($productImage, 'https://')
|
||||
? $productImage
|
||||
: url($productImage);
|
||||
$productSchemaImages = array_map(
|
||||
fn (string $image) => str_starts_with($image, 'http://') || str_starts_with($image, 'https://')
|
||||
? $image
|
||||
: url($image),
|
||||
$productGallery !== [] ? array_values($productGallery) : [$productImageUrl]
|
||||
);
|
||||
|
||||
$manufacturer = trim((string) ($product->specs['manufacturer'] ?? ''));
|
||||
$conditionRaw = mb_strtolower(trim((string) ($product->specs['condition'] ?? '')));
|
||||
$itemCondition = str_contains($conditionRaw, 'б/у') || str_contains($conditionRaw, 'used')
|
||||
? 'https://schema.org/UsedCondition'
|
||||
: 'https://schema.org/NewCondition';
|
||||
|
||||
$productSchema = [
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => 'Product',
|
||||
'name' => $product->name,
|
||||
'description' => $product->short_description ?: ($product->description ?: "Купить {$product->name} по выгодной цене."),
|
||||
'sku' => $product->sku ?: null,
|
||||
'category' => $product->category?->name,
|
||||
'image' => $productSchemaImages,
|
||||
'url' => route('products.show', $product),
|
||||
'offers' => [
|
||||
'@type' => 'Offer',
|
||||
'priceCurrency' => config('shop.currency_code', 'RUB'),
|
||||
'price' => (string) $product->price,
|
||||
'availability' => $product->stock > 0 ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock',
|
||||
'itemCondition' => $itemCondition,
|
||||
'url' => route('products.show', $product),
|
||||
],
|
||||
];
|
||||
|
||||
if ($manufacturer !== '') {
|
||||
$productSchema['brand'] = [
|
||||
'@type' => 'Brand',
|
||||
'name' => $manufacturer,
|
||||
];
|
||||
}
|
||||
@endphp
|
||||
|
||||
@section('meta_title', $product->name)
|
||||
@section('meta_description', \Illuminate\Support\Str::limit(strip_tags($product->short_description ?: ($product->description ?: "Купить {$product->name} по выгодной цене.")), 160))
|
||||
@section('meta_keywords', $product->name . ', ' . ($product->category?->name ?? 'товар') . ', купить')
|
||||
@section('meta_canonical', route('products.show', $product))
|
||||
@section('meta_image', $productImageUrl)
|
||||
@section('meta_image_alt', $product->name)
|
||||
@section('meta_og_type', 'product')
|
||||
|
||||
@push('structured_data')
|
||||
<script type="application/ld+json">
|
||||
@json($productSchema, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@php
|
||||
$favoriteIds = array_map('intval', (array) session('favorites', []));
|
||||
$compareIds = array_map('intval', (array) session('compare', []));
|
||||
$isFavorite = in_array($product->id, $favoriteIds, true);
|
||||
$isCompared = in_array($product->id, $compareIds, true);
|
||||
$cartItems = (array) session('cart', []);
|
||||
$isInCart = isset($cartItems[$product->id]);
|
||||
@endphp
|
||||
|
||||
@include('partials.breadcrumbs', [
|
||||
'items' => [
|
||||
['label' => 'Главная', 'url' => route('home')],
|
||||
['label' => 'Каталог', 'url' => route('catalog.index')],
|
||||
['label' => $product->category?->name ?? 'Категория', 'url' => $product->category ? route('catalog.category', $product->category) : null],
|
||||
['label' => $product->name, 'url' => null],
|
||||
],
|
||||
])
|
||||
|
||||
<section class="pc-section pc-product-page">
|
||||
<div class="pc-product-hero">
|
||||
<div class="pc-product-gallery" data-product-gallery>
|
||||
@if ($productGallery !== [])
|
||||
<img
|
||||
class="pc-product-image-lg"
|
||||
src="{{ $productGallery[0] }}"
|
||||
alt="{{ $product->name }}"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
data-product-gallery-main
|
||||
>
|
||||
@else
|
||||
<div class="pc-product-image-lg" role="img" aria-label="{{ $product->name }}"></div>
|
||||
@endif
|
||||
|
||||
@if (count($productGallery) > 1)
|
||||
<div class="pc-product-thumbs" aria-label="Дополнительные изображения товара">
|
||||
@foreach ($productGallery as $imageUrl)
|
||||
<button
|
||||
class="pc-product-thumb {{ $loop->first ? 'is-active' : '' }}"
|
||||
type="button"
|
||||
data-product-gallery-thumb
|
||||
data-image-src="{{ $imageUrl }}"
|
||||
data-image-alt="{{ $product->name }} - фото {{ $loop->iteration }}"
|
||||
aria-label="Показать фото {{ $loop->iteration }}"
|
||||
aria-pressed="{{ $loop->first ? 'true' : 'false' }}"
|
||||
>
|
||||
<img
|
||||
src="{{ $imageUrl }}"
|
||||
alt="{{ $product->name }} - миниатюра {{ $loop->iteration }}"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
>
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<div class="pc-product-info">
|
||||
<h1>{{ $product->name }}</h1>
|
||||
<p class="pc-muted">{{ $product->short_description }}</p>
|
||||
<div class="pc-product-badges">
|
||||
@if ($product->sku)
|
||||
<span class="pc-sku">Артикул: {{ $product->sku }}</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="pc-product-price">
|
||||
<strong>{{ number_format($product->price, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</strong>
|
||||
@if (!empty($product->old_price))
|
||||
<span class="pc-product-old">{{ number_format($product->old_price, 0, '.', ' ') }} {{ config('shop.currency_symbol', '₽') }}</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="pc-product-actions">
|
||||
@if ($product->stock > 0)
|
||||
<form method="post" action="{{ route('cart.add', $product) }}" data-preserve-scroll="true">
|
||||
@csrf
|
||||
<button class="pc-btn primary {{ $isInCart ? 'is-active' : '' }}" type="submit">
|
||||
{{ $isInCart ? 'В корзине' : 'В корзину' }}
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<button class="pc-btn primary" type="button" disabled>Нет в наличии</button>
|
||||
@endif
|
||||
<form method="post" action="{{ route('favorites.toggle', $product) }}" data-preserve-scroll="true">
|
||||
@csrf
|
||||
<button class="pc-btn ghost {{ $isFavorite ? 'is-active' : '' }}" type="submit">
|
||||
{{ $isFavorite ? 'Убрать из избранного' : 'В избранное' }}
|
||||
</button>
|
||||
</form>
|
||||
<form method="post" action="{{ route('compare.toggle', $product) }}" data-preserve-scroll="true">
|
||||
@csrf
|
||||
<button class="pc-btn ghost {{ $isCompared ? 'is-active' : '' }}" type="submit">
|
||||
{{ $isCompared ? 'Убрать из сравнения' : 'В сравнение' }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pc-tabs">
|
||||
<input type="radio" name="product-tabs" id="tab-specs" checked>
|
||||
<input type="radio" name="product-tabs" id="tab-desc">
|
||||
<input type="radio" name="product-tabs" id="tab-shipping">
|
||||
<input type="radio" name="product-tabs" id="tab-payment">
|
||||
|
||||
<div class="pc-tab-labels">
|
||||
<label for="tab-specs">Характеристики</label>
|
||||
<label for="tab-desc">Описание</label>
|
||||
<label for="tab-shipping">Доставка</label>
|
||||
<label for="tab-payment">Оплата</label>
|
||||
</div>
|
||||
|
||||
<div class="pc-tab-content">
|
||||
<section class="pc-tab-panel pc-tab-specs">
|
||||
<div class="pc-specs-grid">
|
||||
@forelse (($product->specs ?? []) as $key => $value)
|
||||
<div class="pc-spec-row">
|
||||
<span>{{ $specLabels[$key] ?? str_replace('_', ' ', $key) }}</span>
|
||||
<strong>{{ $value }}</strong>
|
||||
</div>
|
||||
@empty
|
||||
<p class="pc-muted">Характеристики еще не добавлены.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
</section>
|
||||
<section class="pc-tab-panel pc-tab-desc">
|
||||
<p class="pc-muted">{{ $product->description ?? 'Описание товара будет добавлено позже.' }}</p>
|
||||
</section>
|
||||
<section class="pc-tab-panel pc-tab-shipping">
|
||||
<ul class="pc-list">
|
||||
<li>Доставка курьером по городу</li>
|
||||
<li>Самовывоз из пункта выдачи</li>
|
||||
<li>Отправка по стране 1-3 дня</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="pc-tab-panel pc-tab-payment">
|
||||
<ul class="pc-list">
|
||||
<li>Оплата картой онлайн</li>
|
||||
<li>Банковский перевод</li>
|
||||
<li>Рассрочка на крупные заказы</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@if ($related->isNotEmpty())
|
||||
<section class="pc-section">
|
||||
<div class="pc-section-title">
|
||||
<h2>Что еще посмотреть в этой категории</h2>
|
||||
</div>
|
||||
<div class="pc-products-grid">
|
||||
@foreach ($related as $item)
|
||||
@include('partials.product-card', ['product' => $item])
|
||||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
@endif
|
||||
@endsection
|
||||
Reference in New Issue
Block a user