Перейти к содержанию

Frontend - Silent Meadow

Обзор

Современный фронтенд платформы Silent Meadow, построенный на React 18 + TypeScript + TailwindCSS. Следует трендам дизайна 2026 года и реализует концепцию "Сбалансированная Цифровая Природа" - сочетание минимализма, природной эстетики и современных технологий.

Технологический стек

Core

  • React 18.2 - UI библиотека
  • TypeScript 5.3 - типизация
  • Vite 5 - сборщик (быстрее Webpack)
  • TailwindCSS 3.4 - utility-first стилизация

State Management

  • React Query (TanStack) 5.20 - server state + кэширование API
  • Zustand 4.5 - локальное UI состояние (фильтры, модалы)

UI Libraries

  • Framer Motion 11 - анимации и переходы
  • @pbe/react-yandex-maps 1.2 - интеграция Яндекс.Карт
  • Swiper 11 - карусели и галереи
  • Sonner 1.4 - toast notifications

Forms

  • React Hook Form 7.50 - управление формами
  • Zod 3.22 - валидация схем
  • @hookform/resolvers 3.3 - интеграция RHF + Zod

Routing

  • React Router 6.22 - навигация и routing

Utils

  • Axios 1.6 - HTTP клиент
  • date-fns 3.3 - работа с датами
  • clsx 2.1 - условные CSS классы
  • tailwind-merge 2.2 - слияние Tailwind классов

Структура проекта

frontend/
├── public/
│   ├── fonts/                      # Geist, Inter шрифты
│   ├── images/                     # Статические изображения
│   └── favicon.ico
├── src/
│   ├── main.tsx                    # Entry point
│   ├── App.tsx                     # Root компонент + routing
│   ├── vite-env.d.ts              # Vite типы
│   │
│   ├── components/
│   │   ├── ui/                     # UI Primitives
│   │   │   ├── Button.tsx         # 4 варианта: primary, secondary, ghost, glass
│   │   │   ├── Card.tsx           # 3 варианта: solid, glass, elevated
│   │   │   ├── Input.tsx          # Floating label, валидация
│   │   │   ├── Badge.tsx          # Статусы и теги
│   │   │   ├── Skeleton.tsx       # Loading states
│   │   │   └── index.ts           # Barrel export
│   │   │
│   │   ├── layout/                # Layout компоненты
│   │   │   ├── Header.tsx         # Навигация
│   │   │   ├── Footer.tsx
│   │   │   └── MobileNav.tsx      # Bottom tab bar
│   │   │
│   │   ├── PropertyCard.tsx       # Domain компоненты
│   │   ├── YandexMapView.tsx      # Яндекс.Карты с 436 маркерами
│   │   ├── FilterPanel.tsx        # Фильтры карты
│   │   ├── HouseCard.tsx          # Карточка дома
│   │   └── EmptyState.tsx         # Empty states
│   │
│   ├── pages/                     # Страницы (routes)
│   │   ├── PropertiesPage.tsx     # Главная - карта участков
│   │   ├── HousesPage.tsx         # Каталог домов
│   │   ├── AvitoAdsPage.tsx       # Управление объявлениями Avito
│   │   ├── LeadsPage.tsx          # CRM дашборд
│   │   └── NotFoundPage.tsx       # 404
│   │
│   ├── hooks/                     # Custom React hooks
│   │   ├── useProperties.ts       # React Query - участки
│   │   ├── useDebounce.ts         # Debounce hook
│   │   └── useMediaQuery.ts       # Responsive breakpoints
│   │
│   ├── lib/                       # Библиотеки и утилиты
│   │   ├── api/
│   │   │   ├── client.ts          # Axios instance
│   │   │   ├── properties.ts      # GET /v1/properties
│   │   │   └── yandex-maps.ts     # GET /v1/map/properties
│   │   ├── animations.ts          # Framer Motion presets
│   │   ├── utils.ts               # Helpers
│   │   └── formatters.ts          # formatPrice, formatDate
│   │
│   ├── store/                     # State management (Zustand)
│   │   ├── filterStore.ts         # Фильтры карты
│   │   └── uiStore.ts             # UI state (modals, drawers)
│   │
│   ├── types/                     # TypeScript types
│   │   ├── property.ts
│   │   ├── house.ts
│   │   └── api.ts
│   │
│   ├── styles/                    # Global styles
│   │   ├── index.css              # Tailwind imports + globals
│   │   ├── animations.css         # Keyframes
│   │   └── fonts.css              # Font-face declarations
│   │
│   └── router/                    # React Router config
│       └── index.tsx              # Routes configuration
├── .env.example                   # Environment variables template
├── .env.development               # Dev environment
├── index.html                     # HTML entry point
├── package.json                   # Dependencies
├── tailwind.config.js             # Дизайн-система Meadow Digital
├── tsconfig.json                  # TypeScript config
├── vite.config.ts                 # Vite config (aliases, proxy)
└── README.md

Дизайн-система: Meadow Digital

Цветовая палитра

Primary (зелёные акценты природы)

--meadow-green-50: #f0f9f4   /* Утренняя роса - светлые фоны */
--meadow-green-100: #dcf3e5  /* Светлая трава - hover states */
--meadow-green-300: #86d5a8  /* Свежая зелень - вторичные кнопки */
--meadow-green-500: #34b574  /* Основной зелёный - CTA кнопки */
--meadow-green-700: #2a8f5c  /* Тёмная зелень - hover на CTA */
--meadow-green-900: #1e6342  /* Лесной мох - акценты */

Neutral (earth tones)

--stone-50: #fafaf9      /* Белый камень - основной фон */
--stone-100: #f5f5f4     /* Светлый песок - карточки */
--stone-200: #e7e5e4     /* Песчаник - borders */
--stone-500: #78716c     /* Глина - вторичный текст */
--stone-900: #1c1917     /* Чёрная почва - основной текст */

Accent (функциональные цвета)

--sky-blue: #0ea5e9      /* Интерактивные элементы, ссылки */
--emerald-500: #10b981   /* Доступно, успех */
--amber-500: #f59e0b     /* Скидки, спецпредложения */
--red-500: #ef4444       /* Продано, ошибки */

Glassmorphism эффекты

--glass-bg: rgba(255, 255, 255, 0.75)
--glass-border: rgba(255, 255, 255, 0.3)
--glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.08)
--glass-blur: blur(16px)

Типографика

Font Stack

  • Primary: Geist (UI, заголовки) - modern geometric sans-serif
  • Secondary: Inter (body текст) - максимальная читаемость
  • Mono: Geist Mono (цены, кадастровые номера)

Type Scale (модульная шкала 1.250)

Hero:  3.815rem (61px)  - героические заголовки
H1:    3.052rem (49px)  - главные заголовки
H2:    2.441rem (39px)  - заголовки секций
H3:    1.953rem (31px)  - подзаголовки
Lead:  1.25rem  (20px)  - лид-текст
Base:  1rem     (16px)  - основной текст
Small: 0.8rem   (13px)  - вторичный текст

Font Weights

  • Light (300) - lead text
  • Normal (400) - body
  • Medium (500) - UI elements
  • Semibold (600) - subheadings
  • Bold (700) - headings

Spacing (8pt grid)

--space-1: 0.25rem  /* 4px */
--space-2: 0.5rem   /* 8px */
--space-3: 0.75rem  /* 12px */
--space-4: 1rem     /* 16px */
--space-6: 1.5rem   /* 24px */
--space-8: 2rem     /* 32px */
--space-12: 3rem    /* 48px */
--space-16: 4rem    /* 64px */

Shadows

--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05)
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07)
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1)
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15)
--shadow-glass: 0 8px 32px rgba(0, 0, 0, 0.08)

Border Radius

--radius-sm: 0.375rem  /* 6px */
--radius-md: 0.5rem    /* 8px */
--radius-lg: 0.75rem   /* 12px */
--radius-xl: 1rem      /* 16px */

Компоненты

UI Primitives

Button

Варианты: - primary - meadow-green-500, белый текст (главные CTA) - secondary - stone-200, тёмный текст - ghost - прозрачный, hover: stone-100 - glass - glassmorphism эффект

Sizes: sm (32px), md (40px), lg (48px)

Props:

interface ButtonProps {
  variant?: 'primary' | 'secondary' | 'ghost' | 'glass';
  size?: 'sm' | 'md' | 'lg';
  icon?: ReactNode;
  loading?: boolean;
  disabled?: boolean;
  children: ReactNode;
}

Card

Варианты: - solid - белый фон, border stone-200 - glass - glassmorphism (для popups на карте) - elevated - белый + shadow-lg

Props:

interface CardProps {
  variant?: 'solid' | 'glass' | 'elevated';
  hoverable?: boolean;
  clickable?: boolean;
  children: ReactNode;
}

Input

Фичи: - Floating label анимация - Real-time валидация с Zod - Иконки слева/справа - Clear button (X)

Props:

interface InputProps {
  label?: string;
  error?: string;
  icon?: ReactNode;
  clearable?: boolean;
  type?: string;
}

Badge

Использование: - Статусы участков: "Доступен" (green), "Забронирован" (amber), "Продан" (red) - Фильтры: "8 соток", "До 500К"

Props:

interface BadgeProps {
  color?: 'green' | 'blue' | 'amber' | 'red' | 'stone';
  size?: 'sm' | 'md';
  children: ReactNode;
}

Domain Components

PropertyCard

Карточка участка - ключевой компонент, появляется 436+ раз на главной странице.

Дизайн: - Aspect ratio 4:3 для фото - Glassmorphism badge с номером участка - Цена крупно (Geist Mono, semibold) - Скидка badge (amber) если есть original_price - Статус badge внизу справа - Hover: 3D tilt effect + shadow lift

Props:

interface PropertyCardProps {
  property: {
    id: string;
    number: string;
    area_sotok: number;
    price: number;
    original_price?: number;
    status: 'available' | 'reserved' | 'sold';
    settlement: string;
    images: string[];
  };
  onFavorite?: (id: string) => void;
  onClick?: (id: string) => void;
}

YandexMapView

Интерактивная карта с 436 участками.

Функционал: - Custom SVG маркеры (3 цвета по статусам) - Кластеризация на zoom < 15 - Glassmorphism popup при клике - Синхронизация с PropertyCard в списке

Props:

interface YandexMapViewProps {
  properties: Property[];
  selectedProperty?: Property;
  onPropertySelect: (property: Property) => void;
  filterStatus?: string[];
  clusterProperties?: boolean;
}

FilterPanel

Панель фильтров для карты участков.

Фильтры: 1. Цена: Range slider (299K - 500K) 2. Площадь: Range slider (8 - 15 соток) 3. Поселок: Checkboxes 4. Статус: Checkboxes

Props:

interface FilterPanelProps {
  onFilterChange: (filters: PropertyFilters) => void;
  activeFilters: PropertyFilters;
}

interface PropertyFilters {
  priceRange: [number, number];
  areaRange: [number, number];
  settlement: string[];
  status: string[];
}

Страницы

PropertiesPage (приоритет)

Главная страница - интерактивная карта с 436 участками.

Layout Desktop: - FilterPanel (left sidebar, 280px) - YandexMapView (center, 50%) - Property Grid (right, 50%)

Layout Mobile: - Tabs "Карта" / "Список" - Filter chips (horizontal scroll) - Floating action button "Карта"

Функционал: - Map-List синхронизация (click/hover) - Real-time фильтрация (debounced 500ms) - Infinite scroll / pagination - Stagger animation для карточек

HousesPage

Каталог 9 типов домов.

Layout: - Grid 3x3 (responsive: 3 → 2 → 1 колонка) - Filter tabs: Все | Шале | Барнхаус | Хай-тек - House Detail Modal с планировкой

AvitoAdsPage / CianAdsPage

Управление объявлениями.

Функционал: - Таблица объявлений (сортировка, фильтры) - Create Ad Wizard (3 шага) - AI генерация описаний - Статистика (просмотры, обращения)

LeadsPage

CRM дашборд лидов.

Функционал: - Kanban board (drag-and-drop) - Lead detail drawer - AI recommendations - Фильтры по источнику/статусу

API Integration

Backend endpoints

Base URL: http://localhost:8000/api/v1

Properties

GET /properties?filters
GET /properties/{id}
POST /properties
PATCH /properties/{id}
DELETE /properties/{id}

Map

GET /map/properties           # GeoJSON все участки
GET /map/clusters?zoom=X      # Кластеризация
GET /map/geocode              # Геокодинг адресов

Houses

GET /houses
GET /houses/{id}

Leads

GET /leads?source=&status=
GET /leads/{id}
PATCH /leads/{id}

React Query hooks

useProperties

const { data, isLoading } = useProperties(filters);
// Возвращает: { items: Property[], total: number }

useProperty

const { data } = useProperty(id);
// Возвращает: Property

useUpdateProperty

const { mutate } = useUpdateProperty();
mutate({ id, data });

Анимации и микровзаимодействия

Framer Motion variants

// lib/animations.ts
export const fadeIn = {
  initial: { opacity: 0, y: 20 },
  animate: { opacity: 1, y: 0 },
  transition: { duration: 0.3 }
};

export const staggerChildren = {
  animate: {
    transition: { staggerChildren: 0.1 }
  }
};

Ключевые анимации

  1. Button hover - scale(1.02) + shadow lift
  2. Card hover - 3D tilt effect
  3. Filter animation - stagger для карточек
  4. Map pin pulse - для новых лидов
  5. Toast notifications - slide in from top

Performance оптимизации

Code splitting

// Route-based splitting
const PropertiesPage = lazy(() => import('./pages/PropertiesPage'));
const HousesPage = lazy(() => import('./pages/HousesPage'));

Image optimization

// Lazy loading + blur placeholder
<img loading="lazy" decoding="async" />

React Query caching

staleTime: 5 * 60 * 1000,        // 5 минут
cacheTime: 10 * 60 * 1000,       // 10 минут
refetchOnWindowFocus: false,
keepPreviousData: true

Bundle size targets

Initial load: < 150kb gzipped
Total JS: < 500kb gzipped
Lighthouse score: > 90

Development

Запуск dev сервера

cd frontend
npm run dev
# http://localhost:3000

Build production

npm run build
# dist/ folder

Lint

npm run lint
npm run format

Type checking

npm run type-check

Деплой

Vercel

# Install Vercel CLI
npm i -g vercel

# Deploy
vercel

Environment variables

VITE_API_URL=http://localhost:8000
VITE_YANDEX_MAPS_API_KEY=your_key

Тестирование

Manual smoke testing

  1. PropertiesPage - карта, фильтры, карточки
  2. HousesPage - grid, carousel, modal
  3. Performance - Lighthouse > 90
  4. Responsive - 375px, 768px, 1280px
  5. Cross-browser - Chrome, Safari, Firefox

Acceptance criteria

✅ Фронтенд запускается без ошибок ✅ Все 436 участков на карте с кластеризацией ✅ Фильтры работают real-time (debounced 500ms) ✅ Map-List синхронизация (click/hover) ✅ PropertyCard анимации smooth ✅ Mobile версия функциональна ✅ Glassmorphism эффекты рендерятся ✅ Шрифты Geist/Inter загружаются ✅ API интеграция с backend ✅ Build production без ошибок

Полезные ссылки

Документация

Шрифты

Референсы дизайна

  • Airbnb - map + listings sync
  • Zillow - real estate UX
  • Apple - minimalism
  • Figma - glassmorphism

Changelog

2026-02-16

  • Инициализация проекта Vite + React + TypeScript
  • Установка всех зависимостей
  • Создание документации
  • Подготовка к настройке TailwindCSS

Статус: В разработке Приоритет: PropertiesPage (карта участков) Сроки: 14 дней Команда: Solo developer + Claude Code