feat: add price filter and dynamic slider to catalog
All checks were successful
Build and Push Docker Image / build (push) Successful in 41s

- Implemented JavaScript-based price slider for catalog filtering
- Updated catalog views to handle min/max price inputs and compute slider bounds
- Enhanced templates (`index.html`, `side-bar.html`) with filtering form and updated URLs
- Added CSS for price slider styling and form layout
- Introduced utility functions for URL building and price parsing
- Expanded tests for price filtering, sliders, and sidebar active states
- Updated context processor and header for dynamic navigation with price filters
This commit is contained in:
2026-05-16 11:12:24 +02:00
parent 52cbc1c2b3
commit 3d356c7d6a
11 changed files with 579 additions and 11 deletions

View File

@@ -3,7 +3,7 @@
<div class="container">
<div class="header-top">
<div class="logo"><a href="/">SantehRay</a></div>
<form action="">
<form action="/catalog/" method="get">
<div class="search-wrap">
<div class="search-select-wrap">
<div class="search-category-dropdown" data-category-dropdown>
@@ -67,9 +67,11 @@
</div>
</div>
<label>
<input class="search-input" type="text" placeholder="Кто ищет, тот найдет...">
<input class="search-input" type="text" name="q" value="{{ navigation_search_query }}" placeholder="Кто ищет, тот найдет...">
</label>
<button>
<input type="hidden" name="min_price" value="{{ navigation_min_price }}">
<input type="hidden" name="max_price" value="{{ navigation_max_price }}">
<button type="submit" aria-label="Найти товары">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-search" viewBox="0 0 16 16">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"></path>

View File

@@ -1,9 +1,9 @@
<aside>
<section class="categories a-section">
<h2>Категории</h2>
<a href="/catalog/" class="category {% if selected_category.id == None %}active{% endif %}">Все товары</a>
<a href="{{ all_items_url }}" class="category {% if selected_category.id == None %}active{% endif %}">Все товары</a>
{% for category in categories %}
<a href="/catalog/{{ category.slug }}/" class="category {% if selected_category.id == category.slug %}active{% endif %}">
<a href="{{ category.catalog_url }}" class="category {% if selected_category.id == category.slug %}active{% endif %}">
{{ category.name }}
</a>
{% empty %}
@@ -14,11 +14,11 @@
<section class="sub-categories a-section">
<h2>Подкатегории</h2>
{% if selected_category.id != None %}
<a href="/catalog/{{ selected_category.id }}/" class="category {% if selected_subcategory.id == None %}active{% endif %}">
<a href="{{ selected_category_url }}" class="category {% if selected_subcategory.id == None %}active{% endif %}">
Все подкатегории
</a>
{% for subcategory in subcategories %}
<a href="/catalog/{{ selected_category.id }}/?subcategory={{ subcategory.slug }}" class="category {% if selected_subcategory.id == subcategory.slug %}active{% endif %}">
<a href="{{ subcategory.catalog_url }}" class="category {% if selected_subcategory.id == subcategory.slug %}active{% endif %}">
{{ subcategory.name }}
</a>
{% empty %}
@@ -29,9 +29,54 @@
{% endif %}
</section>
<form action="">
<form action="{{ price_filter_action }}" method="get" class="catalog-filter-form">
<input type="hidden" name="q" value="{{ current_search_query }}">
{% if selected_subcategory.id != None %}
<input type="hidden" name="subcategory" value="{{ selected_subcategory.id }}">
{% endif %}
<section class="a-section cost-section">
<h2>Стоимость</h2>
<div
class="catalog-price-slider"
data-price-slider
data-min-bound="{{ price_slider_min_bound }}"
data-max-bound="{{ price_slider_max_bound }}"
>
<input type="hidden" name="min_price" value="{{ current_min_price }}" data-price-hidden-min>
<input type="hidden" name="max_price" value="{{ current_max_price }}" data-price-hidden-max>
<div class="catalog-price-slider__values" aria-live="polite">
<span data-price-label-min>{{ price_slider_selected_min }} руб.</span>
<span data-price-label-max>{{ price_slider_selected_max }} руб.</span>
</div>
<div class="catalog-price-slider__controls">
<div class="catalog-price-slider__track">
<div class="catalog-price-slider__track-fill" data-price-track-fill></div>
</div>
<input
type="range"
min="{{ price_slider_min_bound }}"
max="{{ price_slider_max_bound }}"
step="0.01"
value="{{ price_slider_selected_min }}"
class="catalog-price-slider__range"
aria-label="Минимальная цена"
data-price-range-min
>
<input
type="range"
min="{{ price_slider_min_bound }}"
max="{{ price_slider_max_bound }}"
step="0.01"
value="{{ price_slider_selected_max }}"
class="catalog-price-slider__range"
aria-label="Максимальная цена"
data-price-range-max
>
</div>
</div>
<button type="submit" class="catalog-filter-submit">Применить</button>
</section>
<section class="a-section color-section">

View File

@@ -7,6 +7,10 @@
<link rel="stylesheet" href="{% static "css/catalog.css" %}">
{% endblock %}
{% block add_js %}
<script src="{% static 'js/catalog-price-slider.js' %}"></script>
{% endblock %}
{% block content %}
<!-- HEADER -->
{% include "_fragments/header.html" with active="catalog" %}