Сайт и панель управления студии: каталог работ, приём заказов с оплатой переводом, две темы, три языка. Работает на it2.uz.
Сайт студии целиком: витрина работ, страницы проектов с живым показом, приём заказов и панель владельца.
Что внутри:
— Каталог проектов с фильтрами, страницами и встроенным окном живого сайта.
— Оплата переводом на карту: покупатель переводит и отмечает это, владелец подтверждает поступление в панели. Данные карт на сервер не попадают вовсе.
— Панель владельца: проекты, услуги, команда, заказы, сообщения, посетители, журнал действий, настройки.
— Вход через Google и вход владельца по паролю, двухфакторная проверка по одноразовому коду.
— Три языка (русский, английский, узбекский) с отдельными адресами и разметкой hreflang.
— Светлая и тёмная темы, выбор запоминается и применяется до первой отрисовки.
Как сделано: Next.js 15 на App Router, React 19, TypeScript, Prisma и PostgreSQL (Neon, Франкфурт), Auth.js, Tailwind CSS v4, анимации на Motion. Страницы статические с суточным сроком жизни и раздаются с ближайшего к посетителю узла Vercel.
Отдельная работа — скорость. Первая версия спрашивала сессию в общем макете, из-за чего каждая страница собиралась заново на сервере и не кэшировалась. Перенос сессии на сторону браузера сократил ответ примерно с 880 до 300 мс.
Фрагмент из настоящего кода проекта — чтобы было видно, что внутри.
/** * Переключатель темы. * * Переходы снимаются на время смены. Без этого Chrome оставляет * старый цвет всему, у чего есть transition на color: заголовки * карточек висели почти чёрными на чёрном до перезагрузки — * браузер не считает изменение переменной поводом пересчитать * анимируемое свойство. */function toggle() { const next = theme === "dark" ? "light" : "dark"; const root = document.documentElement; root.classList.add("theme-switching"); if (next === "dark") { root.setAttribute("data-theme", "dark"); } else { root.removeAttribute("data-theme"); } // Чтение offsetHeight заставляет пересчитать стили прямо здесь, // пока переходы выключены. Именно так, а не через // requestAnimationFrame: в фоновой вкладке кадры не рисуются, // обработчик бы не вызвался, и класс завис бы навсегда. void root.offsetHeight; root.classList.remove("theme-switching"); localStorage.setItem("ithub:theme", next); setTheme(next);}Заявка на проект
Заполните форму — обсудим детали и сроки.
Zarifa Material — ткани из Дубая
