11 KiB
Flamy Trade — Frontend
Публичный лендинг и дашборд ML-прогнозов для крипторынка. Построен на SvelteKit 5 (Runes API), Tailwind v4, TypeScript и lightweight-charts v5.
Стек
| Слой | Технология |
|---|---|
| Фреймворк | SvelteKit 5 (runes, SSR) |
| Язык | TypeScript (strict) |
| Стили | Tailwind CSS v4 (Vite plugin, @theme) |
| Графики | lightweight-charts v5 (TradingView) |
| Сервер | @sveltejs/adapter-node (Node.js) |
| Пакетный менеджер | pnpm |
Быстрый старт
Требования: Node.js ≥ 20, pnpm ≥ 9
# 1. Установить зависимости
pnpm install
# 2. Запустить dev-сервер
pnpm dev
# 3. Открыть в браузере
# http://localhost:5173
Остальные команды:
pnpm build # Сборка для продакшена (папка build/)
pnpm preview # Превью продакшен-сборки
pnpm check # Svelte + TypeScript проверка типов
pnpm lint # ESLint + Prettier проверка
pnpm format # Автоформатирование
Структура проекта
src/
├── lib/
│ ├── components/
│ │ ├── Chart.svelte # lightweight-charts обёртка
│ │ ├── home/
│ │ │ ├── DashboardMockup.svelte # 3D-макет на главной
│ │ │ └── DashboardStatus.svelte
│ │ ├── layout/
│ │ │ ├── Header.svelte # Фиксированная шапка + мобильное меню
│ │ │ └── Footer.svelte
│ │ └── ui/
│ │ ├── Button.svelte # Универсальная кнопка/ссылка
│ │ └── Logo.svelte
│ ├── blog/
│ │ └── posts.ts # Статьи блога (статические данные)
│ ├── stores/
│ │ └── chartStore.ts # Типы + генератор фейковых данных
│ ├── utils.ts # cn() — утилита для className
│ └── index.ts
│
├── routes/
│ ├── +layout.svelte # Корневой layout: Header, Footer, шрифты
│ ├── +page.svelte # Главная страница (секции)
│ ├── +error.svelte # Страница ошибки
│ ├── (sections)/ # Секции главной страницы
│ │ ├── Hero.svelte
│ │ ├── Ticker.svelte
│ │ ├── About.svelte
│ │ ├── Features.svelte
│ │ ├── Stats.svelte
│ │ ├── BlogPreview.svelte
│ │ └── Cta.svelte
│ ├── about/
│ │ ├── +page.svelte
│ │ └── _data.ts
│ ├── blog/
│ │ ├── +page.svelte # Список статей
│ │ └── [slug]/
│ │ ├── +page.ts # Загрузка статьи по slug
│ │ └── +page.svelte # Статья
│ └── dashboard/
│ └── +page.svelte # Интерактивный дашборд с графиком
│
└── routes/layout.css # Tailwind @theme + глобальные стили
Дизайн-система
Цвета (layout.css)
--color-primary: #fe4b07 /* Акцент — оранжевый */
--color-primary-h:#c83e06 /* Hover-состояние */
--color-bg: #09080a /* Фон страницы */
--color-bg-e: #0f0e10 /* Elevated (шапка, карточки) */
--color-bg-c: #141318 /* Card background */
--color-bg-h: #1a191e /* Hover / бордеры */
--color-title: #f0ede6 /* Основной текст */
--color-desc: #8a887f /* Вторичный текст */
В Tailwind используются как bg-primary, text-desc, border-bg-h и т.д.
Шрифты
| Переменная | Семейство | Применение |
|---|---|---|
font-display |
Unbounded | Заголовки, кнопки, тикеры |
font-sans |
DM Sans | Основной текст |
font-mono |
JetBrains Mono | Цены, метки, метаданные |
Подключаются через Google Fonts в +layout.svelte.
Компонент Button.svelte
<!-- Первичная (ссылка) -->
<Button href="/dashboard">Открыть дашборд</Button>
<!-- Вторичная (кнопка) -->
<Button variant="secondary" onclick={handler}>Действие</Button>
Props: href?, target?, variant?: 'primary' | 'secondary', class?
Дашборд и Charts
Архитектура данных
chartStore.ts → generateChartData(symbolId, timeframeId)
└── возвращает ChartData
├── candles: CandleBar[] // 160 свечей
├── prediction: PredPoint[] // 19 прогнозных точек
├── signal: Signal // direction, confidence, entry/tp/sl
├── currentPrice: number
└── change24h(Pct): number
generateChartData — заглушка с детерминированными фейковыми данными. При подключении реального бекенда её нужно заменить на API-запрос, сохранив возвращаемые типы:
// chartStore.ts — заменить эту функцию на реальный запрос:
export async function fetchChartData(symbolId: string, tfId: TimeframeId): Promise<ChartData> {
const res = await fetch(`/api/chart/${symbolId}?tf=${tfId}`);
return res.json();
}
Компонент Chart.svelte
<Chart data={chartData} decimals={2} height={520} />
| Prop | Тип | Описание |
|---|---|---|
data |
ChartData |
Свечи + прогноз + сигнал |
decimals |
number |
Кол-во знаков после запятой для цены |
height |
number |
Высота canvas в пикселях (default: 520) |
Что рендерится:
- CandlestickSeries — исторические зелёные/красные свечи
- LineSeries — пунктирная оранжевая линия ML-прогноза (19 свечей вперёд)
- PriceLine × 3 — горизонтальные линии Entry / TP / SL с подписями на шкале
- OHLC тултип — кастомный HTML-оверлей при наведении (показывает O/H/L/C и ML-значение)
- ResizeObserver — автоматически подстраивает ширину и высоту при изменении окна
Таймфреймы и символы
Определены в chartStore.ts:
SYMBOLS // 8 монет: BTC ETH SOL BNB XRP ADA DOGE LINK
TIMEFRAMES // 6 таймфреймов: 1m 5m 15m 1h 4h 1d
Контракт API (для бекенда)
Дашборд ожидает от бекенда следующую форму ответа:
type ChartData = {
candles: Array<{
time: number; // Unix timestamp (UTC seconds)
open: number;
high: number;
low: number;
close: number;
}>;
prediction: Array<{
time: number; // Unix timestamp будущих свечей
value: number; // Прогнозная цена (mid/close)
}>;
signal: {
direction: 'long' | 'short';
confidence: number; // 0–100
entry: number;
tp: number;
sl: number;
};
currentPrice: number;
change24h: number;
change24hPct: number;
};
Эндпоинт (предполагаемый):
GET /api/chart/:symbol?tf=5m
Блог
Статьи хранятся в src/lib/blog/posts.ts как статический массив Post[].
type Post = {
id: number;
slug: string; // URL: /blog/:slug
date: string; // ISO 8601
title: string;
description: string;
tags: string[];
content: string; // HTML-строка
};
Для подключения CMS — заменить posts на API-запрос в +page.ts / +page.server.ts.
Конфигурация
SvelteKit (svelte.config.js)
- Адаптер:
adapter-node(деплой как Node.js-сервер) - Runes: принудительно включены для всех файлов вне
node_modules
Tailwind v4 (layout.css)
Tailwind подключается через Vite-плагин (@tailwindcss/vite), конфиг CSS-первый — все кастомные токены в блоке @theme в src/routes/layout.css.
Добавить новый токен:
/* layout.css */
@theme {
--color-accent: #your-color;
}
После этого доступен как bg-accent, text-accent и т.д.
Деплой
Сборка производит Node.js-сервер:
pnpm build
node build/index.js
Переменные окружения:
PORT=3000 # порт (default: 3000)
HOST=0.0.0.0 # хост
ORIGIN=https://... # обязательно при deploy за проксей
Docker (минимальный Dockerfile):
FROM node:22-alpine
WORKDIR /app
COPY build/ ./build/
COPY package.json .
RUN npm install --omit=dev --ignore-scripts
CMD ["node", "build/index.js"]
Соглашения по коду
- Svelte 5 Runes везде:
$state,$derived,$effect,$props— никакого legacy API - Нет
export let— только деструктуризация$props() - Tailwind-first — inline-стили только там, где Tailwind не справляется (динамические значения, chart dimensions)
- cn() из
$lib/utilsдля условного объединения классов - Нет комментариев если смысл очевиден из имён; комментарий — только для неочевидного инварианта
- SSR-safe — всё что требует
window/document— только вonMount - Cleanup — каждый
onMountвозвращает функцию очистки (removeEventListener, disconnect, remove)
Известные ограничения
- Данные в дашборде — фейковые (детерминированный генератор). Требует подключения реального API бекенда через замену
generateChartDataвchartStore.ts - Прогнозная линия — условная визуализация; реальная модель возвращает
prediction[]из бекенда - Блог — статические данные в коде; для production рекомендуется CMS или headless API