Фронтенд покупательских страниц ATDC (SPA на SvelteKit).
Отдельный от админки (../atdc-svelte-kit) SvelteKit-проект, обслуживающий витрину магазина: главная, продукция, бренды, трансмиссии, сотрудничество, контакты, корзина и оформление заказа.
@sveltejs/adapter-nodesrc/
├── app.css / app.html / app.d.ts
├── lib/
│ ├── api/ REST-клиент (тот же BASE_URL, что в admin)
│ │ ├── index.ts getData / postData
│ │ ├── urls.ts endpoint-ы (products, brands, transmissions, orders)
│ │ └── types/ типы ответов и сущностей
│ ├── components/
│ │ ├── Header.svelte
│ │ ├── Footer.svelte
│ │ ├── LanguageSwitcher.svelte
│ │ ├── Accordion.svelte
│ │ └── SearchBar.svelte
│ ├── constants/navigation.ts URL-ы и навигационное меню
│ ├── i18n/
│ │ ├── index.ts загрузчик + стор `locale` + функция `t`
│ │ └── locales/ ru.yml / en.yml / es.yml — тексты в YAML
│ ├── stores/
│ │ ├── collection.ts общий writable-стор для коллекций из API
│ │ ├── products.ts
│ │ ├── brands.ts
│ │ ├── transmissions.ts
│ │ └── cart.ts локальная корзина в localStorage
│ └── utils/format.ts
└── routes/
├── +layout.svelte Header + Footer + main, гидратация локали/корзины
├── +layout.ts ssr=true (рендерим на сервере, чтобы шапка и футер
│ приходили в первом байте и не «прыгали» при загрузке)
├── +page.svelte Главная
├── about/ О нас
├── products/ Продукция (из API)
├── brands/ Бренды (из API)
├── transmissions/ Трансмиссии (из API)
├── cooperation/ Сотрудничество: как заказать, оплата, доставка,
│ сертификаты, гарантия, возврат, обмен
├── contacts/ Контакты
├── cart/ Корзина
└── checkout/ Оформление заказа (POST /orders)
Динамические данные (берутся из сервера):
GET /admin/products — список товаровGET /admin/brands — список брендовGET /admin/transmissions — трансмиссииОтправка заказа:
POST /orders — тело см. в src/lib/api/types/entities.ts (OrderPayload).BASE_URL задаётся в src/lib/api/urls.ts.
Пока публичный API ещё не подключён, фронт работает на встроенных мок-данных:
src/lib/api/mocks/ — реалистичные бренды (ALTO, PRECISION, TRANSTEC, STK, LINTEX, SONNAX, AISIN, RAYBESTOS), трансмиссии (6L80, 722.9, 09G, JF011E, DSG DQ250/DQ200, ZF 8HP и др.) и продукты (ремкомплекты, фильтры, фрикционные диски, соленоиды, гидротрансформаторы).
Управление флагом — в src/lib/api/config.ts:
USE_MOCKS = true. Каждый стор-коллекция (products, brands, transmissions) при load() возвращает данные из моков с искусственной задержкой MOCK_LATENCY_MS (350 мс), чтобы отрабатывал loading-скелетон.POST /orders тоже мокирован — заказ имитирует успех и пишет payload в console.info('[mock] POST …').USE_MOCKS = false (или PUBLIC_USE_MOCKS=false в .env) — все запросы идут в BASE_URL. Если реальный API недоступен и моки указаны — фронт делает graceful fallback на моки, чтобы UI не показывал «API is not reachable».Чтобы переключиться на реальный API:
# .env (или .env.production)
PUBLIC_USE_MOCKS=false
Или просто поменять fallback = true → false в src/lib/api/config.ts.
Всё остальное (тексты, структура страниц, последовательность шагов заказа, раскладка блоков) — зафиксировано в вёрстке.
+layout.ts (ssr = true). Сервер отдаёт полный HTML с
шапкой, футером и контентом сразу — браузер не видит пустого шелла, шапка/футер не
«плавают» при прямой загрузке или перезагрузке страницы./, /about, /cooperation, /contacts) — пререндерятся в
HTML на этапе vite build, отдаются как статика./products, /brands, /transmissions) рендерятся на сервере
как скелетон-плейсхолдеры (animated blocks), клиент дозагружает данные в onMount./cart и /checkout рендерятся на сервере как «пустая корзина», клиент в onMount
гидрирует состояние из localStorage; ранний первый рендер совпадает с SSR, так что
гидратация Svelte проходит без mismatch-ов.<a href> внутри SvelteKit) — клиентская, layout (Header/Footer)
сохраняется, меняется только <main>.Все строки лежат в отдельных YAML-файлах локалей — аналог config/locales/*.yml в Rails:
src/lib/i18n/locales/
├── ru.yml
├── en.yml
└── es.yml
Компоненты используют функцию t из стора:
<script lang="ts">
import { t } from '$lib/i18n';
</script>
<h1>{$t('home.hero.title')}</h1>
Выбор языка — в шапке (LanguageSwitcher.svelte). Сохраняется в localStorage (ключ atdc.locale).
Стор locale инициализируется дефолтом (ru), чтобы SSR и первый клиентский рендер совпадали и гидратация Svelte проходила чисто. Функция hydrateLocale() вызывается из +layout.svelte в onMount и при необходимости переключает язык на сохранённый (localStorage) или на navigator.language.
Добавить новый язык — положить <code>.yml (fr.yml, de.yml, …) в src/lib/i18n/locales/. Переключатель подхватит его автоматически (Vite import.meta.glob).
Ключ структурирован иерархически (products.table.code); доступ — через точку ($t('products.table.code')).
src/lib/stores/cart.ts (writable + derived).localStorage (ключ atdc.cart).hydrateCart() вызывается из +layout.svelte в
onMount и наполняет корзину из localStorage уже после гидратации; с этого
момента каждое изменение автоматически сохраняется обратно.cart.add(product, qty), cart.setQuantity(id, qty), cart.remove(id), cart.clear().cartCount, cartSubtotal.Поля: имя, компания (не обязательно), телефон, email, город, адрес, способ доставки, способ оплаты, комментарий, согласие на ОПД. Все способы доставки/оплаты синхронизированы с i18n-ключами из cooperation.delivery.* / cooperation.payment.*.
npm install
npm run dev
Открыть http://localhost:5173.
Продакшен-сборка:
npm run build
node build
/contacts — заглушка (нужен iframe, когда появится ссылка).auth по аналогии с админкой.Админка — соседний проект ../atdc-svelte-kit. Оба проекта:
BASE_URL (api.dev.atdc.ru);ObjectsResponse<T>).Логика отображения у них независимая: у админки — CRUD-таблицы + авторизация, у витрины — только публичное чтение + форма заказа.