From f2659158c95abea29726e8302ee7f13cb4f5cc8c Mon Sep 17 00:00:00 2001 From: "Anton.AE" Date: Sat, 4 Apr 2026 19:58:19 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20test1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 201 +++++++++++++++++ index3.css | 43 ++++ index3.html | 44 ++-- index3.js | 71 +++++- promt.md | 205 ------------------ .../template-parts/test1-shared-header.php | 4 +- 6 files changed, 330 insertions(+), 238 deletions(-) create mode 100644 AGENTS.md delete mode 100644 promt.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..640f5648 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,201 @@ +🎯 Цель + +Создавать высококонверсионные, быстрые и масштабируемые сайты на WordPress, которые одновременно: + +решают бизнес-задачи +выглядят как продукт топ-уровня +хорошо индексируются и ранжируются +легко поддерживаются и развиваются +🧠 Общие принципы +1. Бизнес > Дизайн > Код + +Никаких решений ради красоты или «как у всех». +Каждый элемент должен отвечать на вопрос: зачем он здесь и какую метрику улучшает? + +2. Минимум сложности — максимум эффекта +избегаем перегруженных решений +не используем тяжелые плагины без необходимости +код и структура должны быть прозрачными +3. Скорость — критичный фактор +Core Web Vitals — не обсуждается +оптимизация на этапе проектирования, а не после +4. SEO встроено с самого начала + +Не «потом добавим», а: + +структура +контент +семантика +— закладываются на этапе прототипа +🧩 Роли агентов +🎨 1. Design Agent (Топовый дизайнер) +Задача: + +Создавать интерфейсы, которые: + +визуально выделяются +усиливают доверие +ведут пользователя к действию +Принципы: +дизайн = инструмент продаж +каждый блок — смысловой +акцент на иерархию, контраст, whitespace +Делает: +UI-киты и дизайн-системы +адаптивные макеты (mobile-first) +визуальные концепции (hero, CTA, USP) +состояния (hover, loading, empty states) +Проверка качества: +можно ли понять смысл страницы за 3 секунды? +есть ли четкий путь пользователя? +не перегружен ли интерфейс? +🧱 2. Prototype Agent (Прототипировщик) +Задача: + +Превратить бизнес-требования в логичную структуру сайта + +Делает: +user flow +wireframes (низкая детализация) +структура страниц +логика блоков +Принципы: +сначала смысл → потом визуал +прототип = скелет продаж +Обязательные элементы: +четкий hero-блок +социальное доказательство +триггеры доверия +логичный CTA +Ошибки: +рисовать дизайн вместо структуры +игнорировать сценарии пользователя +⚙️ 3. Dev Agent (WordPress разработчик) +Задача: + +Собрать быстрый, чистый и масштабируемый сайт + +Стек: +WordPress (custom theme / Gutenberg / ACF) +минимизация page builders (или их грамотное использование) +Принципы: +чистый код > быстрый костыль +не использовать 10 плагинов там, где можно 1 +безопасность по умолчанию +Делает: +кастомные темы +ACF / блоки Gutenberg +оптимизация загрузки (lazy load, critical CSS) +настройка кеширования +Обязательные требования: +PageSpeed 90+ +отсутствие лишних запросов +валидная HTML-структура +🔍 4. SEO Agent (SEO специалист) +Задача: + +Привести трафик и обеспечить видимость в поиске + +Делает: +сбор семантики +кластеризация запросов +структура сайта +оптимизация контента +Важно: + +SEO начинается ДО разработки + +Обязательные элементы: +правильная структура H1-H3 +мета-теги +перелинковка +schema.org +Проверка: +страница отвечает на интент? +есть ли шанс попасть в топ-10? +не переоптимизирован ли текст? +🧠 5. Strategy Agent (опционально, но желательно) +Задача: + +Связать всё воедино + +Делает: +анализ конкурентов +позиционирование +формирование оффера +определение ЦА +🔄 Workflow (процесс работы) +1. Исследование +бизнес +конкуренты +аудитория + +👉 результат: понимание задачи + +2. SEO + структура +семантика +карта сайта + +👉 результат: логика страниц + +3. Прототип +wireframes +user flow + +👉 результат: понятная структура + +4. Дизайн +UI + визуал +адаптив + +👉 результат: готовый макет + +5. Разработка +сборка сайта +оптимизация + +👉 результат: работающий сайт + +6. Тестирование +скорость +UX +SEO + +👉 результат: готовность к запуску + +⚠️ Частые ошибки (важно) +❌ Делать дизайн без прототипа + +→ получается красивая, но бесполезная страница + +❌ Делать SEO после разработки + +→ переделка структуры и потери времени + +❌ Использовать Elementor "как попало" + +→ медленный сайт и проблемы с поддержкой + +❌ Игнорировать mobile-first + +→ теряется до 70% пользователей + +✅ Definition of Done (когда сайт готов) + +Сайт считается готовым, если: + +🚀 PageSpeed 90+ (mobile) +📱 идеально работает на мобильных +🔍 оптимизирован под SEO +🎯 есть четкий CTA и логика конверсии +🧱 легко редактируется (через WP) +⚡ быстро загружается (<2 сек) +🧩 Итог + +Хороший WordPress-сайт — это не: + +«поставили тему и натянули дизайн» + +А это: + +система, где стратегия, структура, дизайн, код и SEO работают вместе \ No newline at end of file diff --git a/index3.css b/index3.css index 6b3eb5c5..6805ee84 100644 --- a/index3.css +++ b/index3.css @@ -67,6 +67,15 @@ text-decoration: none; } + a:focus-visible, + button:focus-visible, + input:focus-visible, + textarea:focus-visible, + select:focus-visible { + outline: 3px solid rgba(13, 79, 214, 0.44); + outline-offset: 3px; + } + button, input, textarea, @@ -439,6 +448,20 @@ transform: translateY(-2px); } + .button:focus-visible, + .ghost-button:focus-visible, + .mini-button:focus-visible, + .cart-button:focus-visible, + .mobile-toggle:focus-visible, + .faq-question:focus-visible, + .close-button:focus-visible, + .header-phone:focus-visible, + .mobile-nav a:focus-visible, + .footer-links a:focus-visible, + .footer-legal a:focus-visible { + box-shadow: 0 0 0 4px rgba(13, 79, 214, 0.18); + } + .hero-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); @@ -1472,3 +1495,23 @@ grid-template-columns: 1fr; } } + + @media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + + .reveal { + opacity: 1; + transform: none; + animation: none !important; + } + } diff --git a/index3.html b/index3.html index 832d3696..0ab2a9e2 100644 --- a/index3.html +++ b/index3.html @@ -44,7 +44,7 @@ @@ -477,67 +477,67 @@
- -
Обычно доставка воды в Севастополе занимает от 2 до 4 часов в пределах активных маршрутов. При высокой загрузке мы предлагаем ближайший удобный интервал и обязательно подтверждаем его по телефону.
+
Обычно доставка воды в Севастополе занимает от 2 до 4 часов в пределах активных маршрутов. При высокой загрузке мы предлагаем ближайший удобный интервал и обязательно подтверждаем его по телефону.
- -
Принимаем наличные, оплату картой при получении, перевод по номеру телефона и безналичный расчет для компаний. Для офисов можем выставить счет.
+
- -
Если у вас нет своей тары, при первом заказе может взиматься возвратный депозит за бутыль. При возврате тары депозит учитывается в следующих заказах.
+
- -
Для семьи из 2-4 человек обычно достаточно заказа 2-4 бутылей 19 литров раз в 1-2 недели. Точный график зависит от потребления и наличия кулера.
+
- -
Мы используем артезианскую воду из защищенного источника, проводим фильтрацию, санитарную обработку тары и регулярный лабораторный контроль. По запросу предоставляем информацию о сертификатах качества.
+
- -
Да, мы регулярно обслуживаем офисы, кафе, фитнес-клубы, студии и медицинские кабинеты. Настраиваем график, безнал и объем под ваш режим работы.
+
- -
Для воды 19 литров можно заказать от одной бутыли. Для небольших упаковок минимальная сумма заказа составляет 500 ₽, чтобы доставка оставалась быстрой и выгодной.
+
- -
Сохраните пустые бутыли до следующего визита курьера. Мы заберем их при следующей доставке или согласуем отдельный выезд при крупном заказе.
+
@@ -639,7 +639,7 @@ -
Спасибо! Заявка принята. Мы свяжемся с вами для подтверждения заказа.
+
Спасибо! Заявка принята. Мы свяжемся с вами для подтверждения заказа.
@@ -709,8 +709,8 @@
-
Товаров0
-
Сумма0 ₽
+
Товаров0
+
Сумма0 ₽
@@ -744,7 +744,7 @@ -
Спасибо! Ваш заказ сохранен. Мы свяжемся с вами в ближайшее время.
+
Спасибо! Ваш заказ сохранен. Мы свяжемся с вами в ближайшее время.
diff --git a/index3.js b/index3.js index 2d1c9cc2..d5aae2b4 100644 --- a/index3.js +++ b/index3.js @@ -29,8 +29,29 @@ const audienceContent = { const orderSuccess = document.getElementById('orderSuccess') const contactSuccess = document.getElementById('contactSuccess') const wooCommerceConfig = window.test1WooCommerce || null + const cartPanel = cartDrawer?.querySelector('.cart-panel') + const modalCard = modalBackdrop?.querySelector('.modal-card') let cart = [] + let lastCartTrigger = null + let lastModalTrigger = null + + const getFocusableElements = container => { + if (!container) { + return [] + } + + return Array.from(container.querySelectorAll('a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])')) + .filter(element => !element.hasAttribute('hidden') && !element.closest('[hidden]')) + } + + const focusFirstElement = container => { + const [first] = getFocusableElements(container) + + if (first) { + first.focus() + } + } const updateAudience = audience => { heroAudienceText.textContent = audienceContent[audience] @@ -55,31 +76,49 @@ const audienceContent = { document.body.classList.remove('menu-open') } - const openCart = () => { + const openCart = triggerElement => { + lastCartTrigger = triggerElement || document.activeElement cartDrawer.classList.add('open') cartDrawer.setAttribute('aria-hidden', 'false') document.body.classList.add('modal-open') + focusFirstElement(cartPanel) } const closeCart = () => { + const shouldRestoreFocus = cartDrawer.classList.contains('open') cartDrawer.classList.remove('open') cartDrawer.setAttribute('aria-hidden', 'true') document.body.classList.remove('modal-open') + + if (shouldRestoreFocus && lastCartTrigger && typeof lastCartTrigger.focus === 'function') { + lastCartTrigger.focus() + } + + lastCartTrigger = null } - const openModal = () => { + const openModal = triggerElement => { + lastModalTrigger = triggerElement || document.activeElement orderItemsField.value = cart.length ? cart.map(item => `${item.name} (${item.volume}) - ${item.price} ₽`).join('\n') : '' modalBackdrop.classList.add('open') modalBackdrop.setAttribute('aria-hidden', 'false') document.body.classList.add('modal-open') + focusFirstElement(modalCard) } const closeModal = () => { + const shouldRestoreFocus = modalBackdrop.classList.contains('open') modalBackdrop.classList.remove('open') modalBackdrop.setAttribute('aria-hidden', 'true') document.body.classList.remove('modal-open') + + if (shouldRestoreFocus && lastModalTrigger && typeof lastModalTrigger.focus === 'function') { + lastModalTrigger.focus() + } + + lastModalTrigger = null } const renderCart = () => { @@ -173,7 +212,7 @@ const audienceContent = { price: Number(button.dataset.price) }) renderCart() - openCart() + openCart(button) button.disabled = false }) .catch(() => { @@ -189,14 +228,14 @@ const audienceContent = { price: Number(button.dataset.price) }) renderCart() - openCart() + openCart(button) }) }) - cartOpenButton.addEventListener('click', openCart) + cartOpenButton.addEventListener('click', () => openCart(cartOpenButton)) mobileCartOpenButton.addEventListener('click', () => { closeMobileMenu() - openCart() + openCart(mobileCartOpenButton) }) cartCloseButton.addEventListener('click', closeCart) viewCartButton.addEventListener('click', () => { @@ -211,11 +250,11 @@ const audienceContent = { } closeCart() - openModal() + openModal(checkoutButton) }) orderButtons.forEach(button => { - button.addEventListener('click', openModal) + button.addEventListener('click', () => openModal(button)) }) modalCloseButton.addEventListener('click', closeModal) @@ -234,15 +273,29 @@ const audienceContent = { faqItems.forEach(item => { const trigger = item.querySelector('.faq-question') + const answer = item.querySelector('.faq-answer') + + if (!trigger || !answer) { + return + } + trigger.addEventListener('click', () => { const isOpen = item.classList.contains('open') faqItems.forEach(entry => { + const entryTrigger = entry.querySelector('.faq-question') + const entryAnswer = entry.querySelector('.faq-answer') + entry.classList.remove('open') - entry.querySelector('.faq-question').setAttribute('aria-expanded', 'false') + entryTrigger?.setAttribute('aria-expanded', 'false') + + if (entryAnswer) { + entryAnswer.hidden = true + } }) if (!isOpen) { item.classList.add('open') trigger.setAttribute('aria-expanded', 'true') + answer.hidden = false } }) }) diff --git a/promt.md b/promt.md deleted file mode 100644 index 694bd98a..00000000 --- a/promt.md +++ /dev/null @@ -1,205 +0,0 @@ -Проанализируй текущую страницу корзины интернет-магазина доставки воды в Севастополе (WordPress + WooCommerce) и предложи полный редизайн с упором на увеличение конверсии. - -Текущая проблема: страница выглядит аккуратно, но перегружена, слабо мотивирует к оформлению заказа и не создает ощущения срочности и простоты. - -Цель: сделать корзину максимально простой, быстрой и продающей. - ---- - -# 1. Основные задачи редизайна - -* Упростить интерфейс (убрать перегруз) -* Ускорить принятие решения -* Усилить CTA (кнопки) -* Добавить триггеры срочности и выгоды -* Увеличить средний чек (upsell) -* Сохранить SEO-ценность страницы - ---- - -# 2. UX-переработка (КРИТИЧНО) - -## 2.1. Левый блок (полностью пересобрать) - -Текущее состояние: - -* перегружен текстом и карточками - -Задача: -сделать компактный продающий блок: - -Структура: - -* H1: - «Корзина — доставка воды в Севастополе» - -* Подзаголовок: - «Доставим за 2–4 часа на дом или в офис» - -* 2–3 преимущества: - - * Бесплатная доставка от X руб - * Работаем ежедневно - * Чистая питьевая вода - -* 1 CTA: - «Оформить заказ за 30 секунд» - ---- - -## 2.2. Убрать лишнее - -Удалить: - -* дублирующие тексты -* длинные объяснения -* второстепенные карточки - -Принцип: -👉 1 экран = 1 действие - ---- - -## 2.3. Правый блок (усилить) - -Оставить: - -* список товаров -* количество -* итог - -Добавить: - -* блок «Добавьте еще»: - - * «Добавьте 1 бутыль — доставка бесплатно» - * «Чаще всего берут: помпа» - ---- - -## 2.4. Sticky итог - -Сделать фиксированный блок: - -* сумма -* доставка -* кнопка - ---- - -# 3. Усиление CTA - -Заменить все кнопки: - -❌ «Перейти к оформлению заказа» -✔ «Оформить заказ за 30 секунд» -✔ «Получить воду сегодня» - -Добавить: - -* микро-текст под кнопкой: - «Без регистрации» - ---- - -# 4. Триггеры конверсии - -Добавить: - -## 4.1. Срочность - -* «Доставим сегодня при заказе до 18:00» -* «Осталось 5 слотов на сегодня» - -## 4.2. Социальное доказательство - -* «Более 1000 клиентов в Севастополе» - -## 4.3. Гарантия - -* «Если не понравится — вернем деньги» - ---- - -# 5. Upsell (увеличение чека) - -Добавить блок: - -«Рекомендуем добавить» - -* Помпа -* Стаканы -* Малые бутылки - -С текстом: -«Чаще всего заказывают вместе» - ---- - -# 6. Быстрый заказ (КРИТИЧНО) - -Добавить: - -* поле «Телефон» -* кнопка «Заказать в 1 клик» - -Интеграция: - -* WooCommerce / кастомный AJAX - ---- - -# 7. SEO-оптимизация - -## 7.1. H1 - -* «Корзина доставки воды в Севастополе» - -## 7.2. Текст (короткий, 500–800 символов) - -Добавить внизу: - -Ключи: - -* доставка воды Севастополь -* заказать воду 19 литров -* вода на дом - ---- - -# 8. Мобильная версия - -Сделать: - -* CTA на первом экране -* Sticky кнопка -* Убрать лишний текст - ---- - -# 9. WooCommerce реализация - -Учитывать: - -* hooks: - - * woocommerce_cart_totals_before_order_total - * woocommerce_after_cart_table - -* кастомизация: - - * functions.php - * AJAX обновление - ---- - -# 10. Результат - -На выходе предоставить: - -1. Новый UX-скелет страницы -2. Готовые тексты (все блоки) -3. Новый CTA -4. Upsell блок -5. SEO текст -6. Рекомендации по внедрению в WooCommerce diff --git a/wp-content/themes/twentytwentyfour/template-parts/test1-shared-header.php b/wp-content/themes/twentytwentyfour/template-parts/test1-shared-header.php index ae35313b..de691ae9 100644 --- a/wp-content/themes/twentytwentyfour/template-parts/test1-shared-header.php +++ b/wp-content/themes/twentytwentyfour/template-parts/test1-shared-header.php @@ -39,7 +39,7 @@ $test1_header_mode = isset( $test1_header_mode ) ? $test1_header_mode :