Refresh storefront design with full-bleed hero and new type system

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
orohi
2026-07-25 05:40:56 +03:00
co-authored by Cursor
parent 54eaff4c70
commit 67acce62f1
8 changed files with 497 additions and 275 deletions
+410 -199
View File
File diff suppressed because it is too large Load Diff
+15 -6
View File
@@ -1,16 +1,25 @@
(() => { (() => {
const header = document.querySelector(".site-header");
const onScroll = () => {
if (!header) return;
header.classList.toggle("is-scrolled", window.scrollY > 12);
};
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
const reveals = document.querySelectorAll(".reveal"); const reveals = document.querySelectorAll(".reveal");
if ("IntersectionObserver" in window) { if ("IntersectionObserver" in window) {
const observer = new IntersectionObserver( const observer = new IntersectionObserver(
(entries) => { (entries) => {
entries.forEach((entry) => { entries.forEach((entry, index) => {
if (entry.isIntersecting) { if (!entry.isIntersecting) return;
entry.target.classList.add("is-visible"); const el = entry.target;
observer.unobserve(entry.target); el.style.transitionDelay = `${Math.min(index * 0.04, 0.2)}s`;
} el.classList.add("is-visible");
observer.unobserve(el);
}); });
}, },
{ threshold: 0.15 } { threshold: 0.12, rootMargin: "0px 0px -8% 0px" }
); );
reveals.forEach((el) => observer.observe(el)); reveals.forEach((el) => observer.observe(el));
} else { } else {
+1 -1
View File
@@ -7,7 +7,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link <link
href="https://fonts.googleapis.com/css2?family=Syne:wght@500;700;800&family=Manrope:wght@400;500;600;700&display=swap" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,500;12..96,700;12..96,800&family=Figtree:wght@400;500;600;700&display=swap"
rel="stylesheet" rel="stylesheet"
/> />
<link rel="stylesheet" href="/static/css/style.css" /> <link rel="stylesheet" href="/static/css/style.css" />
+1 -1
View File
@@ -7,7 +7,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link <link
href="https://fonts.googleapis.com/css2?family=Syne:wght@700;800&family=Manrope:wght@400;600;700&display=swap" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,700;12..96,800&family=Figtree:wght@400;600;700&display=swap"
rel="stylesheet" rel="stylesheet"
/> />
<link rel="stylesheet" href="/static/css/style.css" /> <link rel="stylesheet" href="/static/css/style.css" />
+12 -3
View File
@@ -11,7 +11,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link <link
href="https://fonts.googleapis.com/css2?family=Syne:wght@500;700;800&family=Manrope:wght@400;500;600;700&display=swap" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,500;12..96,700;12..96,800&family=Figtree:wght@400;500;600;700&display=swap"
rel="stylesheet" rel="stylesheet"
/> />
<link rel="stylesheet" href="/static/css/style.css" /> <link rel="stylesheet" href="/static/css/style.css" />
@@ -31,9 +31,18 @@
</header> </header>
<main>{% block content %}{% endblock %}</main> <main>{% block content %}{% endblock %}</main>
<footer class="site-footer" id="support"> <footer class="site-footer" id="support">
<div class="footer-grid">
<div>
<div class="footer-brand">{{ app_name }}</div> <div class="footer-brand">{{ app_name }}</div>
<p>Цифровые товары с мгновенной выдачей. Вопросы: support@pitopn.shop</p> <p>Цифровые товары с мгновенной выдачей.</p>
<p class="footer-copy">© {{ app_name }} 2026</p> </div>
<div class="footer-links">
<a href="/#catalog">Каталог</a>
<a href="/lookup">Мой заказ</a>
<a href="/cart">Корзина</a>
</div>
</div>
<p class="footer-copy">© {{ app_name }} 2026 · support@pitopn.shop</p>
</footer> </footer>
<script src="/static/js/main.js" defer></script> <script src="/static/js/main.js" defer></script>
</body> </body>
+12 -25
View File
@@ -9,44 +9,31 @@
</div> </div>
{% if not items %} {% if not items %}
<p class="empty">Корзина пуста. <a href="/#catalog">Перейти в каталог</a></p> <div class="empty-state">
<p>Корзина пуста</p>
<a class="btn btn-primary" href="/#catalog">Перейти в каталог</a>
</div>
{% else %} {% else %}
<div class="table-wrap"> <div class="cart-list">
<table class="data-table">
<thead>
<tr>
<th>Товар</th>
<th>Цена</th>
<th>Кол-во</th>
<th>Сумма</th>
<th></th>
</tr>
</thead>
<tbody>
{% for item in items %} {% for item in items %}
<tr> <article class="cart-row tone-{{ item.product.image_gradient }}">
<td> <div class="cart-thumb"><span class="product-mark">{{ item.product.title[:1] }}</span></div>
<div class="cart-info">
<a href="/product/{{ item.product.slug }}">{{ item.product.title }}</a> <a href="/product/{{ item.product.slug }}">{{ item.product.title }}</a>
<div class="muted">В наличии: {{ item.stock }}</div> <div class="muted">В наличии: {{ item.stock }}</div>
</td> </div>
<td>{{ item.product.price | rub }}</td> <div class="cart-price">{{ item.product.price | rub }}</div>
<td>
<form method="post" action="/cart/update" class="inline-form"> <form method="post" action="/cart/update" class="inline-form">
<input type="hidden" name="product_id" value="{{ item.product.id }}" /> <input type="hidden" name="product_id" value="{{ item.product.id }}" />
<input type="number" name="quantity" min="0" max="{{ item.stock }}" value="{{ item.quantity }}" /> <input type="number" name="quantity" min="0" max="{{ item.stock }}" value="{{ item.quantity }}" />
<button class="btn btn-ghost btn-tiny" type="submit">OK</button> <button class="btn btn-ghost btn-tiny" type="submit">OK</button>
</form> </form>
</td> <div class="cart-line">{{ item.line_total | rub }}</div>
<td>{{ item.line_total | rub }}</td>
<td>
<form method="post" action="/cart/remove/{{ item.product.id }}"> <form method="post" action="/cart/remove/{{ item.product.id }}">
<button class="btn btn-ghost btn-tiny" type="submit">Удалить</button> <button class="btn btn-ghost btn-tiny" type="submit">Удалить</button>
</form> </form>
</td> </article>
</tr>
{% endfor %} {% endfor %}
</tbody>
</table>
</div> </div>
<div class="cart-summary"> <div class="cart-summary">
<div class="price big">Итого: {{ total | rub }}</div> <div class="price big">Итого: {{ total | rub }}</div>
+25 -19
View File
@@ -2,21 +2,22 @@
{% block content %} {% block content %}
<section class="hero"> <section class="hero">
<div class="hero-bg" aria-hidden="true">
<div class="hero-mesh"></div>
<div class="hero-scan"></div>
<div class="hero-glyph">
<span></span><span></span><span></span>
</div>
</div>
<div class="hero-copy"> <div class="hero-copy">
<p class="brand-mark">{{ app_name }}</p> <p class="brand-mark">{{ app_name }}</p>
<h1>Цифровые товары без ожидания</h1> <h1>Код приходит сразу после оплаты</h1>
<p class="hero-lead"> <p class="hero-lead">Ключи, софт и карты пополнения с автоматической выдачей.</p>
Ключи, софт и подарочные карты — оплатил и сразу получил код.
</p>
<div class="hero-actions"> <div class="hero-actions">
<a class="btn btn-primary" href="#catalog">Смотреть каталог</a> <a class="btn btn-primary" href="#catalog">Открыть каталог</a>
<a class="btn btn-ghost" href="/lookup">Найти заказ</a> <a class="btn btn-ghost" href="/lookup">Найти заказ</a>
</div> </div>
</div> </div>
<div class="hero-visual" aria-hidden="true">
<div class="hero-plane"></div>
<div class="hero-orbit"></div>
</div>
</section> </section>
<section class="categories" aria-label="Категории"> <section class="categories" aria-label="Категории">
@@ -26,8 +27,9 @@
</div> </div>
<ul class="category-list"> <ul class="category-list">
{% for category in categories %} {% for category in categories %}
<li> <li class="reveal">
<a class="category-link" href="#catalog"> <a class="category-link" href="#catalog">
<span class="category-index">0{{ loop.index }}</span>
<span class="category-name">{{ category.name }}</span> <span class="category-name">{{ category.name }}</span>
<span class="category-desc">{{ category.description }}</span> <span class="category-desc">{{ category.description }}</span>
</a> </a>
@@ -39,14 +41,16 @@
<section class="catalog" id="catalog"> <section class="catalog" id="catalog">
<div class="section-head"> <div class="section-head">
<h2>Каталог</h2> <h2>Каталог</h2>
<p>Популярные позиции с автоматической выдачей</p> <p>Позиции с мгновенной выдачей цифрового кода</p>
</div> </div>
{% if featured %} {% if featured %}
<div class="featured-rail" aria-label="Избранное"> <div class="featured-rail" aria-label="Избранное">
{% for product in featured %} {% for product in featured %}
<article class="product product-featured gradient-{{ product.image_gradient }} reveal"> <article class="product product-featured tone-{{ product.image_gradient }} reveal">
<a class="product-media" href="/product/{{ product.slug }}"></a> <a class="product-media" href="/product/{{ product.slug }}">
<span class="product-mark">{{ product.title[:1] }}</span>
</a>
<div class="product-body"> <div class="product-body">
<p class="product-tag">{{ product.delivery_note }}</p> <p class="product-tag">{{ product.delivery_note }}</p>
<h3><a href="/product/{{ product.slug }}">{{ product.title }}</a></h3> <h3><a href="/product/{{ product.slug }}">{{ product.title }}</a></h3>
@@ -67,8 +71,10 @@
<div class="product-grid"> <div class="product-grid">
{% for product in products %} {% for product in products %}
<article class="product gradient-{{ product.image_gradient }} reveal"> <article class="product tone-{{ product.image_gradient }} reveal">
<a class="product-media" href="/product/{{ product.slug }}"></a> <a class="product-media" href="/product/{{ product.slug }}">
<span class="product-mark">{{ product.title[:1] }}</span>
</a>
<div class="product-body"> <div class="product-body">
<p class="product-tag">{{ product.delivery_note }}</p> <p class="product-tag">{{ product.delivery_note }}</p>
<h3><a href="/product/{{ product.slug }}">{{ product.title }}</a></h3> <h3><a href="/product/{{ product.slug }}">{{ product.title }}</a></h3>
@@ -95,17 +101,17 @@
<p>Три шага до цифрового кода</p> <p>Три шага до цифрового кода</p>
</div> </div>
<ol class="steps"> <ol class="steps">
<li> <li class="reveal">
<span class="step-num">01</span> <span class="step-num">01</span>
<h3>Выберите товар</h3> <h3>Выберите товар</h3>
<p>Добавьте ключ, подписку или карту в корзину.</p> <p>Добавьте ключ, подписку или карту в корзину.</p>
</li> </li>
<li> <li class="reveal">
<span class="step-num">02</span> <span class="step-num">02</span>
<h3>Оформите заказ</h3> <h3>Оформите заказ</h3>
<p>Укажите email — туда привязывается выдача.</p> <p>Укажите email — к нему привязывается выдача.</p>
</li> </li>
<li> <li class="reveal">
<span class="step-num">03</span> <span class="step-num">03</span>
<h3>Получите сразу</h3> <h3>Получите сразу</h3>
<p>Коды открываются на странице заказа мгновенно.</p> <p>Коды открываются на странице заказа мгновенно.</p>
+4 -4
View File
@@ -5,15 +5,15 @@
<section class="page-section product-page"> <section class="page-section product-page">
<a class="back-link" href="/#catalog">К каталогу</a> <a class="back-link" href="/#catalog">К каталогу</a>
<div class="product-layout"> <div class="product-layout">
<div class="product-hero-media gradient-{{ product.image_gradient }}"> <div class="product-stage tone-{{ product.image_gradient }}">
<div class="product-media tall"></div> <span class="product-mark xl">{{ product.title[:1] }}</span>
</div> </div>
<div class="product-info"> <div class="product-info">
<p class="product-tag">{{ product.delivery_note }}</p> <p class="product-tag">{{ product.delivery_note }}</p>
<h1>{{ product.title }}</h1> <h1>{{ product.title }}</h1>
<p class="lead">{{ product.short_description }}</p> <p class="lead">{{ product.short_description }}</p>
<p>{{ product.description }}</p> <p class="body-copy">{{ product.description }}</p>
<p class="stock-line">В наличии: {{ stock }} шт.</p> <p class="stock-line">В наличии: <strong>{{ stock }}</strong> шт.</p>
<div class="buy-row"> <div class="buy-row">
<span class="price big">{{ product.price | rub }}</span> <span class="price big">{{ product.price | rub }}</span>
<form method="post" action="/cart/add/{{ product.id }}" class="inline-form"> <form method="post" action="/cart/add/{{ product.id }}" class="inline-form">