catalog.blade.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. @extends('layouts.app')
  2. @section('title', 'Каталог автомобилей — Точка')
  3. @php
  4. $fuelLabels = ['petrol'=>'Бензин','diesel'=>'Дизель','hybrid'=>'Гибрид','electric'=>'Электро','gas'=>'Газ','other'=>'Другое'];
  5. $countryFlags = ['Германия'=>'🇩🇪','Япония'=>'🇯🇵','Корея'=>'🇰🇷','США'=>'🇺🇸','Китай'=>'🇨🇳','ОАЭ'=>'🇦🇪','Грузия'=>'🇬🇪','Великобритания'=>'🇬🇧','Франция'=>'🇫🇷','Италия'=>'🇮🇹'];
  6. $conditions = $activeFilters['conditions'] ?? [];
  7. $countries = $activeFilters['countries'] ?? [];
  8. $fuels = $activeFilters['fuels'] ?? [];
  9. $make = $activeFilters['make'] ?? '';
  10. $priceTo = $activeFilters['priceTo'] ?? null;
  11. $year = $activeFilters['year'] ?? null;
  12. $sort = $activeFilters['sort'] ?? '';
  13. $priceMax = $filterOptions['price_max'] ?? 50000000;
  14. $priceMin = $filterOptions['price_min'] ?? 0;
  15. $sliderMax = $priceTo ?: $priceMax;
  16. $hasFilters = $conditions || $countries || $fuels || $make || $priceTo || $year;
  17. @endphp
  18. @section('content')
  19. <section class="page-hdr">
  20. <div class="container">
  21. <div class="sh-label reveal-up">Все автомобили</div>
  22. <h1 class="reveal">КАТАЛОГ</h1>
  23. <nav class="breadcrumb">
  24. <a href="{{ route('home') }}">Главная</a>
  25. <span>/</span>
  26. <span>Каталог</span>
  27. </nav>
  28. </div>
  29. </section>
  30. <section class="section sec-alt" style="padding-top:32px">
  31. <div class="container">
  32. {{-- Кнопка фильтров (мобильные) --}}
  33. <button class="btn btn-outline mob-filter-btn" id="mobFilterBtn">
  34. ⚙ Фильтры@if($hasFilters) <span class="chip chip-red" style="margin-left:8px;font-size:10px;padding:2px 8px">активны</span>@endif
  35. </button>
  36. {{-- form оборачивает ВСЁ — так aside и div стают прямыми детьми catalog-layout --}}
  37. <form method="GET" action="{{ route('catalog') }}" id="filterForm">
  38. <div class="catalog-layout">
  39. {{-- ═══ ФИЛЬТРЫ ═══ --}}
  40. <aside class="filters" id="filterPanel">
  41. <div class="filter-hdr">
  42. Фильтры
  43. @if($hasFilters)
  44. <a href="{{ route('catalog') }}" class="filter-reset">Сбросить</a>
  45. @endif
  46. </div>
  47. <div class="filter-group">
  48. <label>Состояние</label>
  49. <div class="f-checks">
  50. <label class="f-check"><input type="checkbox" name="condition[]" value="new" {{ in_array('new', $conditions) ? 'checked' : '' }}> Новый</label>
  51. <label class="f-check"><input type="checkbox" name="condition[]" value="used" {{ in_array('used', $conditions) ? 'checked' : '' }}> С пробегом</label>
  52. </div>
  53. </div>
  54. @if(!empty($filterOptions['makes']))
  55. <div class="filter-group">
  56. <label>Марка</label>
  57. <select class="f-sel" name="make">
  58. <option value="">Все марки</option>
  59. @foreach($filterOptions['makes'] as $m)
  60. <option value="{{ $m }}" {{ $make === $m ? 'selected' : '' }}>{{ $m }}</option>
  61. @endforeach
  62. </select>
  63. </div>
  64. @endif
  65. @if(!empty($filterOptions['countries']))
  66. <div class="filter-group">
  67. <label>Страна поставки</label>
  68. <div class="f-checks">
  69. @foreach($filterOptions['countries'] as $c)
  70. <label class="f-check">
  71. <input type="checkbox" name="country_origin[]" value="{{ $c }}" {{ in_array($c, $countries) ? 'checked' : '' }}>
  72. {{ $countryFlags[$c] ?? '' }} {{ $c }}
  73. </label>
  74. @endforeach
  75. </div>
  76. </div>
  77. @endif
  78. @if($priceMax > 0)
  79. <div class="filter-group">
  80. <label>Цена до (₽)</label>
  81. <input type="range" class="f-range" id="priceRange" name="price_to"
  82. min="{{ $priceMin }}" max="{{ $priceMax }}" step="100000" value="{{ $sliderMax }}"
  83. oninput="document.getElementById('priceVal').textContent=Number(this.value).toLocaleString('ru-RU')+' ₽'">
  84. <div class="f-range-row">от 0 до <strong id="priceVal">{{ number_format($sliderMax, 0, '.', ' ') }} ₽</strong></div>
  85. </div>
  86. @endif
  87. @if(!empty($filterOptions['years']))
  88. <div class="filter-group">
  89. <label>Год</label>
  90. <select class="f-sel" name="year">
  91. <option value="">Любой</option>
  92. @foreach($filterOptions['years'] as $y)
  93. <option value="{{ $y }}" {{ (string)$year === (string)$y ? 'selected' : '' }}>{{ $y }}</option>
  94. @endforeach
  95. </select>
  96. </div>
  97. @endif
  98. <div class="filter-group">
  99. <label>Топливо</label>
  100. <div class="f-checks">
  101. @foreach($fuelLabels as $val => $label)
  102. <label class="f-check">
  103. <input type="checkbox" name="engine_type[]" value="{{ $val }}" {{ in_array($val, $fuels) ? 'checked' : '' }}>
  104. {{ $label }}
  105. </label>
  106. @endforeach
  107. </div>
  108. </div>
  109. {{-- Скрытое поле сортировки --}}
  110. <input type="hidden" name="sort" id="sortHidden" value="{{ $sort }}">
  111. <button type="submit" class="btn btn-red" style="width:100%;justify-content:center;margin-top:8px">
  112. Применить
  113. </button>
  114. </aside>
  115. {{-- ═══ ОСНОВНАЯ ОБЛАСТЬ ═══ --}}
  116. <div>
  117. {{-- Активные теги --}}
  118. @if($hasFilters)
  119. <div class="active-tags" style="margin-bottom:12px">
  120. @foreach($conditions as $c)
  121. <span class="atag">{{ $c === 'new' ? 'Новый' : 'С пробегом' }}</span>
  122. @endforeach
  123. @if($make)<span class="atag">{{ $make }}</span>@endif
  124. @foreach($countries as $c)
  125. <span class="atag">{{ $countryFlags[$c] ?? '' }} {{ $c }}</span>
  126. @endforeach
  127. @foreach($fuels as $f)
  128. <span class="atag">{{ $fuelLabels[$f] ?? $f }}</span>
  129. @endforeach
  130. @if($priceTo)<span class="atag">до {{ number_format($priceTo, 0, '.', ' ') }} ₽</span>@endif
  131. @if($year)<span class="atag">{{ $year }} г.</span>@endif
  132. <a href="{{ route('catalog') }}" class="atag" style="text-decoration:none">✕ Сбросить</a>
  133. </div>
  134. @endif
  135. {{-- Top-bar --}}
  136. <div class="cat-top">
  137. <div class="cat-count">Найдено: <strong>{{ $cars->total() }}</strong> авт.</div>
  138. <div style="display:flex;gap:12px;align-items:center">
  139. <div class="cat-sort">
  140. <label style="font-size:13px;color:var(--muted)">Сортировка:</label>
  141. <select onchange="applySort(this.value)">
  142. <option value="" {{ $sort==='' ?'selected':'' }}>По умолчанию</option>
  143. <option value="price_asc" {{ $sort==='price_asc' ?'selected':'' }}>Цена ↑</option>
  144. <option value="price_desc" {{ $sort==='price_desc' ?'selected':'' }}>Цена ↓</option>
  145. <option value="year_desc" {{ $sort==='year_desc' ?'selected':'' }}>Год ↓</option>
  146. </select>
  147. </div>
  148. <div class="view-btns">
  149. <button type="button" class="vbtn active" id="btnGrid" onclick="setView('grid')" title="Сетка">▦</button>
  150. <button type="button" class="vbtn" id="btnList" onclick="setView('list')" title="Список">☰</button>
  151. </div>
  152. </div>
  153. </div>
  154. {{-- Сетка карточек --}}
  155. <div class="cars-grid" id="carsGrid">
  156. @forelse($cars as $car)
  157. @include('pages.partials._car_card', compact('car', 'fuelLabels', 'countryFlags'))
  158. @empty
  159. <div class="no-results" style="grid-column:1/-1">
  160. <div class="nr-i">🔍</div>
  161. <h3>Ничего не найдено</h3>
  162. <p>Попробуйте изменить фильтры</p>
  163. </div>
  164. @endforelse
  165. </div>
  166. {{-- Пагинация --}}
  167. @if($cars->hasPages())
  168. <div class="pagination" style="margin-top:36px">
  169. @if($cars->onFirstPage())
  170. <span class="pag" style="opacity:.35">←</span>
  171. @else
  172. <a class="pag" href="{{ $cars->previousPageUrl() }}">←</a>
  173. @endif
  174. @foreach($cars->getUrlRange(1, $cars->lastPage()) as $pg => $url)
  175. <a class="pag {{ $pg===$cars->currentPage()?'active':'' }}" href="{{ $url }}">{{ $pg }}</a>
  176. @endforeach
  177. @if($cars->hasMorePages())
  178. <a class="pag" href="{{ $cars->nextPageUrl() }}">→</a>
  179. @else
  180. <span class="pag" style="opacity:.35">→</span>
  181. @endif
  182. </div>
  183. @endif
  184. </div>
  185. </div>
  186. </form>
  187. </div>
  188. </section>
  189. @endsection
  190. @push('styles')
  191. <style>
  192. .mob-filter-btn { display: none; }
  193. @media(max-width:1024px) {
  194. .catalog-layout { grid-template-columns: 1fr !important; }
  195. .filters { display: none; }
  196. .filters.open { display: block; }
  197. .mob-filter-btn { display: flex; width: 100%; justify-content: center; margin-bottom: 16px; }
  198. }
  199. </style>
  200. @endpush
  201. @push('scripts')
  202. <script>
  203. function applySort(v) {
  204. document.getElementById('sortHidden').value = v;
  205. document.getElementById('filterForm').submit();
  206. }
  207. function setView(v) {
  208. document.getElementById('carsGrid').classList.toggle('list-view', v === 'list');
  209. document.getElementById('btnGrid').classList.toggle('active', v === 'grid');
  210. document.getElementById('btnList').classList.toggle('active', v === 'list');
  211. }
  212. document.getElementById('mobFilterBtn').addEventListener('click', function () {
  213. document.getElementById('filterPanel').classList.toggle('open');
  214. });
  215. </script>
  216. @endpush