Make product cards fully clickable
All checks were successful
Build and Push Docker Image / build (push) Successful in 27s
All checks were successful
Build and Push Docker Image / build (push) Successful in 27s
This commit is contained in:
@@ -75,6 +75,16 @@ class FavoritePageTests(TestCase):
|
||||
self.assertContains(response, "/media/items/sink-primary.jpg")
|
||||
self.assertContains(response, 'href="/catalog/plumbing/kitchen-sink/"', html=False)
|
||||
self.assertContains(response, 'href="/catalog/plumbing/mono-tap/"', html=False)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a class="item-card-overlay" href="/catalog/plumbing/kitchen-sink/"',
|
||||
html=False,
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a class="item-card-overlay" href="/catalog/plumbing/mono-tap/"',
|
||||
html=False,
|
||||
)
|
||||
self.assertContains(response, "Удалить из избранного")
|
||||
|
||||
def test_toggle_endpoint_adds_and_removes_favorite(self):
|
||||
|
||||
@@ -66,6 +66,11 @@ class HomePopularProductsTests(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, visible_item.name)
|
||||
self.assertContains(response, reverse("detail", args=[self.category.slug, visible_item.slug]))
|
||||
self.assertContains(
|
||||
response,
|
||||
f'<a class="product-card-link" href="{reverse("detail", args=[self.category.slug, visible_item.slug])}"',
|
||||
html=False,
|
||||
)
|
||||
self.assertContains(response, "1600,00 руб.")
|
||||
self.assertNotContains(response, "Hidden sink")
|
||||
|
||||
|
||||
@@ -279,6 +279,42 @@ class CatalogViewTests(TestCase):
|
||||
response = self.client.get("/catalog/")
|
||||
|
||||
self.assertContains(response, 'href="/catalog/plumbing/kitchen-sink/"')
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a class="item-card-overlay" href="/catalog/plumbing/kitchen-sink/"',
|
||||
html=False,
|
||||
)
|
||||
|
||||
def test_sidebar_product_cards_include_full_card_links(self):
|
||||
sale_item = Item.objects.create(
|
||||
name="Акционная ванна",
|
||||
slug="sale-bath",
|
||||
category=self.plumbing,
|
||||
price="900.00",
|
||||
discount_price="750.00",
|
||||
is_available=True,
|
||||
)
|
||||
new_item = Item.objects.create(
|
||||
name="Новый душ",
|
||||
slug="new-shower",
|
||||
category=self.plumbing,
|
||||
price="500.00",
|
||||
is_available=True,
|
||||
is_new=True,
|
||||
)
|
||||
|
||||
response = self.client.get("/catalog/")
|
||||
|
||||
self.assertContains(
|
||||
response,
|
||||
f'<a class="sidebar-mini-card__overlay" href="/catalog/plumbing/{sale_item.slug}/"',
|
||||
html=False,
|
||||
)
|
||||
self.assertContains(
|
||||
response,
|
||||
f'<a class="sidebar-mini-card__overlay" href="/catalog/plumbing/{new_item.slug}/"',
|
||||
html=False,
|
||||
)
|
||||
|
||||
def test_catalog_item_card_shows_favorite_button_for_authenticated_user(self):
|
||||
user = get_user_model().objects.create_user(
|
||||
|
||||
@@ -125,6 +125,13 @@ class CartFlowTests(TestCase):
|
||||
self.assertContains(response, "3200,00 руб.")
|
||||
self.assertContains(response, "3295,00 руб.")
|
||||
self.assertContains(response, "/media/items/cart-item.jpg")
|
||||
self.assertContains(
|
||||
response,
|
||||
'<a class="cart-item__overlay" href="/catalog/plumbing/kitchen-sink/"',
|
||||
html=False,
|
||||
)
|
||||
self.assertContains(response, 'id="cart-increment-', html=False)
|
||||
self.assertContains(response, 'action="/orders/cart/remove/"', html=False)
|
||||
self.assertNotContains(response, 'name="promo_code"', html=False)
|
||||
|
||||
def test_cart_page_redirects_guest_to_login(self):
|
||||
|
||||
@@ -26,13 +26,17 @@
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: 230px minmax(0, 1fr);
|
||||
gap: 34px;
|
||||
align-items: start;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cart-item__media {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: block;
|
||||
width: 100%;
|
||||
aspect-ratio: 1.55 / 1;
|
||||
@@ -40,6 +44,13 @@
|
||||
background: rgba(99, 118, 141, 0.12);
|
||||
}
|
||||
|
||||
.cart-item__overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 2;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cart-item__media img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
@@ -61,6 +72,8 @@
|
||||
}
|
||||
|
||||
.cart-item__title {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
color: var(--dark);
|
||||
font-size: 25px;
|
||||
@@ -81,6 +94,8 @@
|
||||
}
|
||||
|
||||
.cart-item__controls {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -200,9 +200,11 @@ aside {
|
||||
}
|
||||
|
||||
.item-card {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
border: 1px solid rgba(54, 33, 62, 0.14);
|
||||
background: #ffffff;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;
|
||||
}
|
||||
|
||||
@@ -213,6 +215,15 @@ aside {
|
||||
}
|
||||
|
||||
.item-card-media-link {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.item-card-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 2;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -259,6 +270,8 @@ aside {
|
||||
}
|
||||
|
||||
.item-card-favorite-form {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
@@ -296,10 +309,14 @@ aside {
|
||||
}
|
||||
|
||||
.item-card-favorite-button--login {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.item-card-title-link {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -688,13 +705,24 @@ aside {
|
||||
|
||||
/* Sidebar mini-cards */
|
||||
.sidebar-mini-card {
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sidebar-mini-card__overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 2;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebar-mini-card__img-link {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
flex: 0 0 52px;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
@@ -719,6 +747,8 @@ aside {
|
||||
}
|
||||
|
||||
.sidebar-mini-card__name {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
color: #36213e;
|
||||
font-size: 15px;
|
||||
line-height: 1.2;
|
||||
|
||||
@@ -507,6 +507,7 @@
|
||||
flex-direction: column;
|
||||
background: #ffffff;
|
||||
border: 1px solid rgba(54, 33, 62, 0.12);
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;
|
||||
}
|
||||
|
||||
@@ -517,6 +518,8 @@
|
||||
}
|
||||
|
||||
.product-media {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
min-height: 0;
|
||||
flex: 1 1 auto;
|
||||
display: block;
|
||||
@@ -524,6 +527,13 @@
|
||||
background: rgba(99, 118, 141, 0.1);
|
||||
}
|
||||
|
||||
.product-card-link {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 2;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.product-media img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
@@ -545,7 +555,7 @@
|
||||
|
||||
.product-actions {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
z-index: 3;
|
||||
top: 18px;
|
||||
left: 18px;
|
||||
display: flex;
|
||||
@@ -604,6 +614,8 @@
|
||||
}
|
||||
|
||||
.product-name {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
min-height: 52px;
|
||||
margin-top: 8px;
|
||||
display: -webkit-box;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{% url 'detail' item.category.slug item.slug as item_url %}
|
||||
<article class="item-card{% if item.id in favorite_item_ids %} is-favorite{% endif %}" data-item-card="{{ item.id }}">
|
||||
<a class="item-card-media-link" href="{% url 'detail' item.category.slug item.slug %}" aria-label="Открыть товар {{ item.name }}">
|
||||
<a class="item-card-overlay" href="{{ item_url }}" aria-label="Открыть товар {{ item.name }}" tabindex="-1" aria-hidden="true"></a>
|
||||
<a class="item-card-media-link" href="{{ item_url }}" aria-label="Открыть товар {{ item.name }}">
|
||||
{% with primary_image=item.primary_image %}
|
||||
<div class="item-card-image">
|
||||
{% if primary_image %}
|
||||
@@ -44,7 +46,7 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<a class="item-card-title-link" href="{% url 'detail' item.category.slug item.slug %}" aria-label="Открыть товар {{ item.name }}">
|
||||
<a class="item-card-title-link" href="{{ item_url }}" aria-label="Открыть товар {{ item.name }}">
|
||||
<h2 class="item-card-title">{{ item.name }}</h2>
|
||||
</a>
|
||||
<div class="item-card-footer">
|
||||
|
||||
@@ -104,15 +104,17 @@
|
||||
</h2>
|
||||
{% for sale_item in sidebar_sale_items %}
|
||||
<div class="sidebar-mini-card">
|
||||
{% url 'detail' sale_item.category.slug sale_item.slug as sale_item_url %}
|
||||
<a class="sidebar-mini-card__overlay" href="{{ sale_item_url }}" aria-label="Открыть товар {{ sale_item.name }}" tabindex="-1" aria-hidden="true"></a>
|
||||
{% with img=sale_item.primary_image %}
|
||||
{% if img %}
|
||||
<a href="{% url 'detail' sale_item.category.slug sale_item.slug %}" class="sidebar-mini-card__img-link">
|
||||
<a href="{{ sale_item_url }}" class="sidebar-mini-card__img-link">
|
||||
<img src="{{ img.image.url }}" alt="{{ img.alt|default:sale_item.name }}">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="sidebar-mini-card__body">
|
||||
<a href="{% url 'detail' sale_item.category.slug sale_item.slug %}" class="sidebar-mini-card__name">{{ sale_item.name }}</a>
|
||||
<a href="{{ sale_item_url }}" class="sidebar-mini-card__name">{{ sale_item.name }}</a>
|
||||
<span class="sidebar-mini-card__price">{{ sale_item.display_price }} руб.</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -130,15 +132,17 @@
|
||||
</h2>
|
||||
{% for new_item in sidebar_new_items %}
|
||||
<div class="sidebar-mini-card">
|
||||
{% url 'detail' new_item.category.slug new_item.slug as new_item_url %}
|
||||
<a class="sidebar-mini-card__overlay" href="{{ new_item_url }}" aria-label="Открыть товар {{ new_item.name }}" tabindex="-1" aria-hidden="true"></a>
|
||||
{% with img=new_item.primary_image %}
|
||||
{% if img %}
|
||||
<a href="{% url 'detail' new_item.category.slug new_item.slug %}" class="sidebar-mini-card__img-link">
|
||||
<a href="{{ new_item_url }}" class="sidebar-mini-card__img-link">
|
||||
<img src="{{ img.image.url }}" alt="{{ img.alt|default:new_item.name }}">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="sidebar-mini-card__body">
|
||||
<a href="{% url 'detail' new_item.category.slug new_item.slug %}" class="sidebar-mini-card__name">{{ new_item.name }}</a>
|
||||
<a href="{{ new_item_url }}" class="sidebar-mini-card__name">{{ new_item.name }}</a>
|
||||
<span class="sidebar-mini-card__price">{{ new_item.display_price }} руб.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
{% for item in home_products %}
|
||||
{% url 'detail' item.category.slug item.slug as item_url %}
|
||||
<article class="product product-{{ forloop.counter }}">
|
||||
<a class="product-card-link" href="{{ item_url }}" aria-label="Открыть товар {{ item.name }}" tabindex="-1" aria-hidden="true"></a>
|
||||
<a class="product-media" href="{{ item_url }}" aria-label="Открыть товар {{ item.name }}">
|
||||
{% with primary_image=item.primary_image %}
|
||||
{% if primary_image %}
|
||||
|
||||
@@ -25,8 +25,10 @@
|
||||
<div class="cart-items">
|
||||
{% for cart_item in cart_items %}
|
||||
{% with item=cart_item.item %}
|
||||
{% url 'detail' item.category.slug item.slug as item_url %}
|
||||
<article class="cart-item" data-auth-cart-item data-current-quantity="{{ cart_item.quantity }}">
|
||||
<a class="cart-item__media" href="{% url 'detail' item.category.slug item.slug %}">
|
||||
<a class="cart-item__overlay" href="{{ item_url }}" aria-label="Открыть товар {{ item.name }}" tabindex="-1" aria-hidden="true"></a>
|
||||
<a class="cart-item__media" href="{{ item_url }}">
|
||||
{% with primary_image=item.primary_image %}
|
||||
{% if primary_image %}
|
||||
<img src="{{ primary_image.image.url }}" alt="{{ primary_image.alt|default:item.name }}">
|
||||
@@ -37,7 +39,7 @@
|
||||
</a>
|
||||
|
||||
<div class="cart-item__info">
|
||||
<a class="cart-item__title" href="{% url 'detail' item.category.slug item.slug %}">{{ item.name }}</a>
|
||||
<a class="cart-item__title" href="{{ item_url }}">{{ item.name }}</a>
|
||||
{% if cart_item.selected_color %}
|
||||
<span class="cart-item__color">({{ cart_item.selected_color.name }})</span>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user