index.html.twig 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. {% extends "base.html.twig" %}
  2. {% block title %}
  3. {% if current_category_name %}
  4. {{ current_category_name }} - {{ site_title }}
  5. {% else %}
  6. {% if current_lang == 'en' %}Home{% else %}Αρχική{% endif %} - {{ site_title }}
  7. {% endif %}
  8. {% endblock %}
  9. {% block extra_css %}
  10. <style>
  11. /* --- HERO SECTION --- */
  12. .hero {
  13. background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
  14. padding: 60px 30px;
  15. text-align: center;
  16. border-radius: var(--border-radius);
  17. margin-bottom: 40px;
  18. border: 1px solid var(--border-color);
  19. box-shadow: 0 10px 30px rgba(0,0,0,0.3);
  20. position: relative;
  21. overflow: hidden;
  22. }
  23. .hero::before {
  24. content: ''; position: absolute; top: -50px; left: -50px; width: 150px; height: 150px; background: rgba(249, 115, 22, 0.15); border-radius: 50%; filter: blur(60px); pointer-events: none;
  25. }
  26. .hero h1 { margin-top: 0; font-size: 2.8em; color: var(--text-main); font-weight: 900; letter-spacing: -1px; text-shadow: 2px 2px 4px rgba(0,0,0,0.5); }
  27. .hero p { color: var(--text-muted); font-size: 1.2em; font-weight: 500; }
  28. /* --- TOP FILTER BAR --- */
  29. .top-filters-bar {
  30. background: var(--panel-bg);
  31. padding: 20px 25px;
  32. border-radius: var(--border-radius);
  33. box-shadow: var(--shadow-sm);
  34. margin-bottom: 35px;
  35. border: 1px solid var(--border-color);
  36. display: flex;
  37. flex-wrap: wrap;
  38. gap: 15px;
  39. align-items: center;
  40. justify-content: space-between;
  41. }
  42. .filter-group { display: flex; align-items: center; gap: 10px; }
  43. .filter-group label { font-size: 13px; font-weight: 700; color: var(--text-muted); white-space: nowrap; text-transform: uppercase; letter-spacing: 0.5px; }
  44. .filter-control {
  45. padding: 10px 14px;
  46. border: 1px solid var(--border-color);
  47. border-radius: 6px;
  48. font-family: 'Inter', sans-serif;
  49. font-size: 13px;
  50. background: #0f172a;
  51. outline: none;
  52. color: var(--text-main);
  53. transition: 0.2s;
  54. }
  55. .filter-control:focus { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(249, 115, 22, 0.2); }
  56. .price-inputs { display: flex; align-items: center; gap: 8px; }
  57. .price-inputs input { width: 80px; }
  58. .price-inputs span { color: var(--text-muted); font-weight: bold; }
  59. .btn-apply-filters {
  60. padding: 10px 20px;
  61. background: var(--primary);
  62. color: white;
  63. border: none;
  64. border-radius: 6px;
  65. font-weight: 800;
  66. cursor: pointer;
  67. font-size: 13px;
  68. text-transform: uppercase;
  69. letter-spacing: 1px;
  70. transition: 0.2s;
  71. }
  72. .btn-apply-filters:hover { background: var(--primary-hover); transform: translateY(-1px); }
  73. .btn-clear-filters {
  74. color: #fca5a5;
  75. text-decoration: none;
  76. font-size: 13px;
  77. font-weight: 700;
  78. transition: 0.2s;
  79. text-transform: uppercase;
  80. letter-spacing: 0.5px;
  81. display: flex;
  82. align-items: center;
  83. gap: 4px;
  84. }
  85. .btn-clear-filters:hover { color: #ef4444; }
  86. /* --- PRODUCTS GRID --- */
  87. .products-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 25px; }
  88. .product-card {
  89. background: var(--panel-bg);
  90. border-radius: var(--border-radius);
  91. overflow: hidden;
  92. box-shadow: var(--shadow-sm);
  93. border: 1px solid var(--border-color);
  94. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  95. display: flex;
  96. flex-direction: column;
  97. }
  98. .product-card:hover {
  99. transform: translateY(-8px);
  100. box-shadow: 0 15px 30px rgba(0,0,0,0.4);
  101. border-color: rgba(249, 115, 22, 0.5);
  102. }
  103. .product-image-container { position: relative; width: 100%; height: 220px; background: #0f172a; overflow: hidden;}
  104. .product-image { width: 100%; height: 100%; object-fit: cover; transition: transform 0.5s ease; }
  105. .product-card:hover .product-image { transform: scale(1.05); }
  106. .no-img-text { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--text-muted); font-weight: bold; text-transform: uppercase; letter-spacing: 1px;}
  107. .product-info { padding: 20px; display: flex; flex-direction: column; flex-grow: 1; }
  108. .product-title { margin: 0 0 12px; font-size: 1.15em; color: var(--text-main); font-weight: 700; line-height: 1.3; }
  109. .product-price { font-size: 1.3em; font-weight: 900; color: var(--accent-green); margin-bottom: 15px; }
  110. .product-attributes { font-size: 12px; color: var(--text-muted); margin-bottom: 20px; flex-grow: 1; display: flex; flex-wrap: wrap; gap: 6px; }
  111. .attr-badge { background: rgba(255,255,255,0.05); padding: 4px 10px; border-radius: 4px; border: 1px solid rgba(255,255,255,0.1); color: #cbd5e1; font-weight: 500; }
  112. .attr-badge strong { color: var(--text-main); }
  113. .btn-view { display: block; padding: 12px 15px; background: rgba(59, 130, 246, 0.1); color: var(--accent-blue); text-decoration: none; border-radius: 6px; font-size: 14px; font-weight: 800; text-align: center; margin-top: auto; text-transform: uppercase; letter-spacing: 1px; border: 1px solid rgba(59, 130, 246, 0.2); transition: 0.2s; }
  114. .btn-view:hover { background: var(--accent-blue); color: white; }
  115. .section-title { border-bottom: 2px solid var(--primary); padding-bottom: 10px; display: inline-block; margin-top: 0; color: var(--text-main); font-weight: 800; text-transform: uppercase; letter-spacing: 0.5px; }
  116. /* --- PAGINATION STYLES --- */
  117. .pagination-container { display: flex; justify-content: center; gap: 8px; margin-top: 50px; margin-bottom: 20px; flex-wrap: wrap; }
  118. .page-btn { padding: 10px 16px; background: var(--panel-bg); border: 1px solid var(--border-color); color: var(--text-main); border-radius: 6px; text-decoration: none; font-weight: 700; transition: 0.2s; font-size: 14px; }
  119. .page-btn:hover { background: rgba(255,255,255,0.05); border-color: var(--text-muted); }
  120. .page-btn.active { background: var(--primary); color: white; border-color: var(--primary); }
  121. .page-dots { padding: 10px; color: var(--text-muted); font-weight: bold; pointer-events: none; }
  122. @media (max-width: 768px) {
  123. .hero h1 { font-size: 2em; }
  124. .top-filters-bar { flex-direction: column; align-items: stretch; padding: 15px; }
  125. .filter-group { flex-direction: column; align-items: stretch; gap: 8px; }
  126. .price-inputs { width: 100%; }
  127. .price-inputs input { width: 100%; }
  128. }
  129. </style>
  130. {% endblock %}
  131. {% block content %}
  132. {% if search_query is defined and search_query != '' %}
  133. <div style="background: rgba(59, 130, 246, 0.1); padding: 20px; border-radius: var(--border-radius); border: 1px solid rgba(59, 130, 246, 0.2); margin-bottom: 30px;">
  134. <h3 style="margin-top:0; color: var(--accent-blue);">
  135. {% if current_lang == 'en' %}Search results for:{% else %}Αποτελέσματα αναζήτησης για:{% endif %} "<strong>{{ search_query }}</strong>"
  136. </h3>
  137. <p style="margin-bottom:0; color: var(--text-main); font-weight:500;">
  138. {% if current_lang == 'en' %}Found {{ total_products }} products.{% else %}Βρέθηκαν {{ total_products }} προϊόντα.{% endif %}
  139. </p>
  140. </div>
  141. {% endif %}
  142. {% if current_category_name %}
  143. <h2 class="section-title">
  144. {{ text.category_title_prefix|default('Κατηγορία:') }} {{ current_category_name }}
  145. </h2>
  146. <p style="color: var(--text-muted); margin-bottom: 25px; font-size: 15px;">{{ text.category_subtitle_prefix|default('Εμφάνιση εξοπλισμού για') }} <strong>{{ current_category_name }}</strong></p>
  147. <!-- ΟΡΙΖΟΝΤΙΑ ΜΠΑΡΑ ΦΙΛΤΡΩΝ -->
  148. <form action="index.php" method="GET" class="top-filters-bar" id="topFilterForm">
  149. {% if category_id %}
  150. <input type="hidden" name="category_id" value="{{ category_id }}">
  151. {% endif %}
  152. {% if search_query %}
  153. <input type="hidden" name="q" value="{{ search_query }}">
  154. {% endif %}
  155. <div style="display: flex; flex-wrap: wrap; gap: 20px; flex-grow: 1;">
  156. <div class="filter-group">
  157. <label>{{ text.filter_sort_label|default('Ταξινόμηση:') }}</label>
  158. <select name="sort" class="filter-control" onchange="document.getElementById('topFilterForm').submit();">
  159. <option value="newest" {% if filters.sort == 'newest' %}selected{% endif %}>
  160. {% if current_lang == 'en' %}Newest{% else %}Νεότερα{% endif %}
  161. </option>
  162. <option value="price_asc" {% if filters.sort == 'price_asc' %}selected{% endif %}>
  163. {% if current_lang == 'en' %}Price: Low to High{% else %}Φθηνότερα{% endif %}
  164. </option>
  165. <option value="price_desc" {% if filters.sort == 'price_desc' %}selected{% endif %}>
  166. {% if current_lang == 'en' %}Price: High to Low{% else %}Ακριβότερα{% endif %}
  167. </option>
  168. </select>
  169. </div>
  170. <div class="filter-group">
  171. <label>{{ text.filter_price_label|default('Τιμή (€):') }}</label>
  172. <div class="price-inputs">
  173. <input type="number" name="min_price" class="filter-control" placeholder="{{ text.filter_price_from|default('Από') }}" value="{{ filters.min_price }}">
  174. <span>-</span>
  175. <input type="number" name="max_price" class="filter-control" placeholder="{{ text.filter_price_to|default('Έως') }}" value="{{ filters.max_price }}">
  176. </div>
  177. </div>
  178. {% if category_attributes %}
  179. {% for attr in category_attributes %}
  180. {% set attr_values = attr.distinct_values|split('||') %}
  181. {% if attr_values|length > 0 and attr.distinct_values != '' %}
  182. <div class="filter-group">
  183. <label>{{ attr.display_name|default(attr.name_el) }}:</label>
  184. <select name="attr[{{ attr.id }}]" class="filter-control" onchange="document.getElementById('topFilterForm').submit();">
  185. <option value="">{% if current_lang == 'en' %}All{% else %}Όλα{% endif %}</option>
  186. {% for val in attr_values %}
  187. <option value="{{ val }}" {% if filters.attr[attr.id] == val %}selected{% endif %}>{{ val }}{{ attr.unit ? ' ' ~ attr.unit : '' }}</option>
  188. {% endfor %}
  189. </select>
  190. </div>
  191. {% endif %}
  192. {% endfor %}
  193. {% endif %}
  194. <!-- ΝΕΟ ΦΙΛΤΡΟ: ΕΜΦΑΝΙΣΗ ΑΝΑ ΣΕΛΙΔΑ -->
  195. <div class="filter-group">
  196. <label>{% if current_lang == 'en' %}Show:{% else %}Ανά σελίδα:{% endif %}</label>
  197. <select name="limit" class="filter-control" onchange="document.getElementById('topFilterForm').submit();">
  198. <option value="30" {% if limit == 30 %}selected{% endif %}>30</option>
  199. <option value="50" {% if limit == 50 %}selected{% endif %}>50</option>
  200. <option value="100" {% if limit == 100 %}selected{% endif %}>100</option>
  201. </select>
  202. </div>
  203. </div>
  204. <div style="display: flex; align-items: center; gap: 20px;">
  205. <button type="submit" class="btn-apply-filters">
  206. {% if current_lang == 'en' %}Apply{% else %}Εφαρμογή{% endif %}
  207. </button>
  208. {% if filters.sort or filters.min_price or filters.max_price or filters.attr %}
  209. <a href="index.php?{% if category_id %}category_id={{ category_id }}{% endif %}{% if search_query %}&q={{ search_query }}{% endif %}" class="btn-clear-filters">
  210. ✖ {% if current_lang == 'en' %}Clear Filters{% else %}Καθαρισμός{% endif %}
  211. </a>
  212. {% endif %}
  213. </div>
  214. </form>
  215. {% elseif search_query is empty %}
  216. <div class="hero">
  217. <h1>{{ text.site_slogan|default('Βρες τον καλύτερο εξοπλισμό Χόκεϊ!') }}</h1>
  218. <p>{{ text.site_sub_slogan|default('Αγορά και πώληση καινούργιου & μεταχειρισμένου εξοπλισμού.') }}</p>
  219. </div>
  220. <h2 class="section-title">{{ text.title_new_arrivals|default('Νέες Αφίξεις') }}</h2>
  221. {% endif %}
  222. <div class="products-grid">
  223. {% for product in products %}
  224. <div class="product-card">
  225. <div class="product-image-container">
  226. {% if product.image_path %}
  227. <img src="{{ product.image_path }}" class="product-image" alt="{{ product.title }}">
  228. {% else %}
  229. <div class="no-img-text">No Image</div>
  230. {% endif %}
  231. </div>
  232. <div class="product-info">
  233. <h3 class="product-title">{{ product.title }}</h3>
  234. {% if product.sku %}
  235. <div style="font-size: 12px; color: var(--text-muted); margin-bottom: 8px; font-weight: 600;">
  236. SKU: <span style="color: var(--text-main);">{{ product.sku }}</span>
  237. </div>
  238. {% endif %}
  239. <div class="product-price">{{ product.price|number_format(2, ',', '.') }} €</div>
  240. <div class="product-attributes">
  241. {% if product.attributes is not empty %}
  242. {% for attr in product.attributes %}
  243. <span class="attr-badge">
  244. <strong>{{ attr.name }}:</strong> {{ attr.value }}{{ attr.unit ? ' ' ~ attr.unit : '' }}
  245. </span>
  246. {% endfor %}
  247. {% endif %}
  248. </div>
  249. <a href="product.php?id={{ product.id }}" class="btn-view">{{ text.btn_view_product|default('Προβολή') }}</a>
  250. </div>
  251. </div>
  252. {% else %}
  253. <div style="grid-column: 1 / -1; background: var(--panel-bg); padding: 40px; text-align: center; border-radius: var(--border-radius); border: 1px dashed var(--border-color); color: var(--text-muted); font-size: 16px;">
  254. {% if current_lang == 'en' %}
  255. No products found in this category.
  256. {% else %}
  257. Δεν βρέθηκαν διαθέσιμα προϊόντα.
  258. {% endif %}
  259. </div>
  260. {% endfor %}
  261. </div>
  262. <!-- ΣΕΛΙΔΟΠΟΙΗΣΗ ΣΤΟ ΚΑΤΩ ΜΕΡΟΣ (PAGINATION) -->
  263. {% if total_pages > 1 %}
  264. <div class="pagination-container">
  265. {% if current_page > 1 %}
  266. <a href="{{ pagination_url }}{{ current_page - 1 }}" class="page-btn">
  267. &laquo; {% if current_lang == 'en' %}Prev{% else %}Προηγ.{% endif %}
  268. </a>
  269. {% endif %}
  270. {# Έξυπνη εμφάνιση σελίδων (κρύβει τις ενδιάμεσες αν είναι πάνω από 5) #}
  271. {% set start_page = max(1, current_page - 2) %}
  272. {% set end_page = min(total_pages, current_page + 2) %}
  273. {% if start_page > 1 %}
  274. <a href="{{ pagination_url }}1" class="page-btn">1</a>
  275. {% if start_page > 2 %}<span class="page-dots">...</span>{% endif %}
  276. {% endif %}
  277. {% for p in start_page..end_page %}
  278. <a href="{{ pagination_url }}{{ p }}" class="page-btn {% if p == current_page %}active{% endif %}">{{ p }}</a>
  279. {% endfor %}
  280. {% if end_page < total_pages %}
  281. {% if end_page < total_pages - 1 %}<span class="page-dots">...</span>{% endif %}
  282. <a href="{{ pagination_url }}{{ total_pages }}" class="page-btn">{{ total_pages }}</a>
  283. {% endif %}
  284. {% if current_page < total_pages %}
  285. <a href="{{ pagination_url }}{{ current_page + 1 }}" class="page-btn">
  286. {% if current_lang == 'en' %}Next{% else %}Επόμ.{% endif %} &raquo;
  287. </a>
  288. {% endif %}
  289. </div>
  290. {% endif %}
  291. {% endblock %}