|
@@ -0,0 +1,1260 @@
|
|
|
|
|
+# PhotoPlaces Twilight — Дизайн-система
|
|
|
|
|
+
|
|
|
|
|
+> **photoplaces_twilight** — концепция дизайна, вдохновлённая магией сумерек: когда golden hour переходит в blue hour, и каждый кадр наполнен тёплым светом и креативностью.
|
|
|
|
|
+
|
|
|
|
|
+## 1. АНАЛИЗ ПРОЕКТА
|
|
|
|
|
+
|
|
|
|
|
+### Что это
|
|
|
|
|
+PhotoPlaces Twilight — маркетплейс фотолокаций. Пользователи находят места и студии для фотосъёмок, бронируют, общаются с фотографами.
|
|
|
|
|
+
|
|
|
|
|
+### Целевая аудитория
|
|
|
|
|
+- **Фотографы** (25-40 лет): ищут новые локации, хотят впечатлить клиентов
|
|
|
|
|
+- **Владельцы студий/локаций**: хотят привлечь клиентов, показать пространство
|
|
|
|
|
+- **Заказчики съёмок** (20-35 лет): свадьбы, любительские, коммерческие съёмки
|
|
|
|
|
+
|
|
|
|
|
+### Эмоциональный посыл
|
|
|
|
|
+1. **Вдохновение** — хочется снимать, открывать новые места
|
|
|
|
|
+2. **Надёжность** — можно доверять бронирование
|
|
|
|
|
+3. **Профессионализм** — серьёзный подход к фотосъёмке
|
|
|
|
|
+4. **Открытость** — дружелюбное сообщество
|
|
|
|
|
+
|
|
|
|
|
+### Ключевые ценности
|
|
|
|
|
+Вдохновение • Надёжность • Красота • Сообщество
|
|
|
|
|
+
|
|
|
|
|
+### Визуальный характер
|
|
|
|
|
+**Современный минимализм с акцентом на визуальный контент.**
|
|
|
|
|
+Фотографии — главные герои. Интерфейс — рамка, которая не отвлекает.
|
|
|
|
|
+
|
|
|
|
|
+### Философия Twilight
|
|
|
|
|
+- **Golden Hour** — тёплые янтарные акценты (secondary `#F59E0B`)
|
|
|
|
|
+- **Blue Hour** — глубокий индиго как основной цвет (primary `#6366F1`)
|
|
|
|
|
+- **Ночной контраст** — чистый минимализм на тёмном фоне
|
|
|
|
|
+- **Магия момента** — каждое фото как произведение искусства
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 2. ЦВЕТОВАЯ ПАЛИТРА
|
|
|
|
|
+
|
|
|
|
|
+### Философия Twilight
|
|
|
|
|
+Тёмная тема — идеальный фон для фотографий (как ночное небо). Акцентный цвет — индиго-фиолетовый, который ассоциируется с креативностью и вечерним blue hour. Тёплый янтарный secondary — отсылка к golden hour.
|
|
|
|
|
+
|
|
|
|
|
+### Primary: Индиго-фиолетовый
|
|
|
|
|
+
|
|
|
|
|
+| Формат | Значение |
|
|
|
|
|
+|--------|----------|
|
|
|
|
|
+| Hex | `#6366F1` |
|
|
|
|
|
+| RGB | `rgb(99, 102, 241)` |
|
|
|
|
|
+| HSL | `hsl(239, 84%, 67%)` |
|
|
|
|
|
+
|
|
|
|
|
+**Почему именно этот:**
|
|
|
|
|
+- Ассоциируется с креативностью и вечерним светом (golden hour → blue hour)
|
|
|
|
|
+- Хорошо читается на тёмном фоне
|
|
|
|
|
+- Отличается от типичного зелёного/синего в конкурентах
|
|
|
|
|
+- Работает как для CTA, так и для акцентов
|
|
|
|
|
+
|
|
|
|
|
+### Secondary: Тёплый янтарный
|
|
|
|
|
+
|
|
|
|
|
+| Формат | Значение |
|
|
|
|
|
+|--------|----------|
|
|
|
|
|
+| Hex | `#F59E0B` |
|
|
|
|
|
+| RGB | `rgb(245, 158, 11)` |
|
|
|
|
|
+| HSL | `hsl(38, 92%, 50%)` |
|
|
|
|
|
+
|
|
|
|
|
+**Назначение:** бейджи, рейтинг, избранные, премиум-метки
|
|
|
|
|
+
|
|
|
|
|
+### Accent: Бирюзовый
|
|
|
|
|
+
|
|
|
|
|
+| Формат | Значение |
|
|
|
|
|
+|--------|----------|
|
|
|
|
|
+| Hex | `#06B6D4` |
|
|
|
|
|
+| RGB | `rgb(6, 182, 212)` |
|
|
|
|
|
+| HSL | `hsl(189, 94%, 43%)` |
|
|
|
|
|
+
|
|
|
|
|
+**Назначение:** ссылки, интерактивные элементы, ховер-состояния
|
|
|
|
|
+
|
|
|
|
|
+### Neutrals (тёмная тема)
|
|
|
|
|
+
|
|
|
|
|
+| Токен | Hex | Назначение |
|
|
|
|
|
+|-------|-----|------------|
|
|
|
|
|
+| `--bg` | `#09090B` | Основной фон |
|
|
|
|
|
+| `--bg-elevated` | `#18181B` | Поверхности (карточки, модалки) |
|
|
|
|
|
+| `--bg-hover` | `#27272A` | Ховер-состояния |
|
|
|
|
|
+| `--border` | `#3F3F46` | Границы, разделители |
|
|
|
|
|
+| `--border-subtle` | `#27272A` | Мягкие границы |
|
|
|
|
|
+| `--text-primary` | `#FAFAFA` | Основной текст |
|
|
|
|
|
+| `--text-secondary` | `#A1A1AA` | Вторичный текст |
|
|
|
|
|
+| `--text-muted` | `#71717A` | Приглушённый текст |
|
|
|
|
|
+
|
|
|
|
|
+### Neutrals (светлая тема)
|
|
|
|
|
+
|
|
|
|
|
+| Токен | Hex | Назначение |
|
|
|
|
|
+|-------|-----|------------|
|
|
|
|
|
+| `--bg` | `#FAFAFA` | Основной фон |
|
|
|
|
|
+| `--bg-elevated` | `#FFFFFF` | Поверхности |
|
|
|
|
|
+| `--bg-hover` | `#F4F4F5` | Ховер-состояния |
|
|
|
|
|
+| `--border` | `#E4E4E7` | Границы |
|
|
|
|
|
+| `--border-subtle` | `#F4F4F5` | Мягкие границы |
|
|
|
|
|
+| `--text-primary` | `#18181B` | Основной текст |
|
|
|
|
|
+| `--text-secondary` | `#52525B` | Вторичный текст |
|
|
|
|
|
+| `--text-muted` | `#A1A1AA` | Приглушённый текст |
|
|
|
|
|
+
|
|
|
|
|
+### Functional Colors
|
|
|
|
|
+
|
|
|
|
|
+| Состояние | Hex | Назначение |
|
|
|
|
|
+|-----------|-----|------------|
|
|
|
|
|
+| `--success` | `#22C55E` | Успешные действия, подтверждения |
|
|
|
|
|
+| `--warning` | `#F59E0B` | Предупреждения, ожидание |
|
|
|
|
|
+| `--error` | `#EF4444` | Ошибки, удаление |
|
|
|
|
|
+| `--info` | `#3B82F6` | Информационные сообщения |
|
|
|
|
|
+
|
|
|
|
|
+### Accessibility (контрастные пары)
|
|
|
|
|
+
|
|
|
|
|
+| Комбинация | Ratio | WCAG |
|
|
|
|
|
+|------------|-------|------|
|
|
|
|
|
+| `#FAFAFA` на `#09090B` | 19.3:1 | AAA ✓ |
|
|
|
|
|
+| `#6366F1` на `#09090B` | 6.8:1 | AA ✓ |
|
|
|
|
|
+| `#A1A1AA` на `#09090B` | 7.2:1 | AA ✓ |
|
|
|
|
|
+| `#18181B` на `#FAFAFA` | 19.3:1 | AAA ✓ |
|
|
|
|
|
+| `#6366F1` на `#FFFFFF` | 4.7:1 | AA ✓ |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 3. ТИПОГРАФИКА
|
|
|
|
|
+
|
|
|
|
|
+### Шрифты
|
|
|
|
|
+
|
|
|
|
|
+| Роль | Шрифт | Обоснование |
|
|
|
|
|
+|------|-------|-------------|
|
|
|
|
|
+| **Заголовки** | Inter | Геометрический, чистый, отлично читается на экране |
|
|
|
|
|
+| **Основной текст** | Inter | Единообразие, хорошая читаемость |
|
|
|
|
|
+| **Mono** | JetBrains Mono | Для кода, ID, технической информации |
|
|
|
|
|
+
|
|
|
|
|
+Почему Inter:
|
|
|
|
|
+- Бесплатный (Google Fonts)
|
|
|
|
|
+- Оптимизирован для экранов
|
|
|
|
|
+- Отличная поддержка кириллицы
|
|
|
|
|
+- Множество начертаний (от Thin до Black)
|
|
|
|
|
+
|
|
|
|
|
+### Масштабная шкала
|
|
|
|
|
+
|
|
|
|
|
+| Токен | Размер | Line-height | Letter-spacing | Использование |
|
|
|
|
|
+|-------|--------|-------------|----------------|---------------|
|
|
|
|
|
+| `--text-xs` | 12px | 16px | 0.01em | Метки, капшены |
|
|
|
|
|
+| `--text-sm` | 14px | 20px | 0.01em | Small text, описания |
|
|
|
|
|
+| `--text-base` | 16px | 24px | 0em | Основной текст |
|
|
|
|
|
+| `--text-lg` | 18px | 28px | -0.01em | Крупный body text |
|
|
|
|
|
+| `--text-xl` | 20px | 28px | -0.01em | h5, h4 |
|
|
|
|
|
+| `--text-2xl` | 24px | 32px | -0.02em | h3 |
|
|
|
|
|
+| `--text-3xl` | 30px | 36px | -0.02em | h2 |
|
|
|
|
|
+| `--text-4xl` | 36px | 40px | -0.03em | h1 |
|
|
|
|
|
+| `--text-5xl` | 48px | 48px | -0.03em | Hero заголовки |
|
|
|
|
|
+
|
|
|
|
|
+### Иерархия текста
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+Hero (text-5xl, font-bold)
|
|
|
|
|
+ └── Подзаголовок (text-lg, text-secondary)
|
|
|
|
|
+
|
|
|
|
|
+Раздел (text-3xl, font-semibold)
|
|
|
|
|
+ └── Описание (text-base, text-secondary)
|
|
|
|
|
+
|
|
|
|
|
+Карточка заголовок (text-xl, font-medium)
|
|
|
|
|
+ └── Карточка описание (text-sm, text-secondary)
|
|
|
|
|
+
|
|
|
|
|
+Метка (text-xs, font-medium, uppercase, tracking-wider)
|
|
|
|
|
+ └── Значение (text-base, font-semibold)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 4. СЕТКА И ОТСТУПЫ
|
|
|
|
|
+
|
|
|
|
|
+### Базовая единица: 4px
|
|
|
|
|
+
|
|
|
|
|
+### Spacing Scale
|
|
|
|
|
+
|
|
|
|
|
+| Токен | Значение | Использование |
|
|
|
|
|
+|-------|----------|---------------|
|
|
|
|
|
+| `--space-0` | 0px | Нет отступа |
|
|
|
|
|
+| `--space-0.5` | 2px | Минимальный зазор |
|
|
|
|
|
+| `--space-1` | 4px | Минимальный отступ |
|
|
|
|
|
+| `--space-1.5` | 6px | Between иконок |
|
|
|
|
|
+| `--space-2` | 8px | Внутренний padding кнопок |
|
|
|
|
|
+| `--space-3` | 12px | Between элементов в строке |
|
|
|
|
|
+| `--space-4` | 16px | Стандартный padding |
|
|
|
|
|
+| `--space-5` | 20px | Между секциями |
|
|
|
|
|
+| `--space-6` | 24px | Карточки, блоки |
|
|
|
|
|
+| `--space-8` | 32px | Между группами |
|
|
|
|
|
+| `--space-10` | 40px | Отступы секций |
|
|
|
|
|
+| `--space-12` | 48px | Крупные разделители |
|
|
|
|
|
+| `--space-16` | 64px | Hero-секции |
|
|
|
|
|
+| `--space-20` | 80px | Между страницами |
|
|
|
|
|
+
|
|
|
|
|
+### Сетка
|
|
|
|
|
+
|
|
|
|
|
+| Параметр | Значение |
|
|
|
|
|
+|----------|----------|
|
|
|
|
|
+| Колонки (desktop) | 12 |
|
|
|
|
|
+| Колонки (tablet) | 8 |
|
|
|
|
|
+| Колонки (mobile) | 4 |
|
|
|
|
|
+| Gutter | 24px (desktop), 16px (mobile) |
|
|
|
|
|
+| Max-width | 1280px |
|
|
|
|
|
+| Padding | 32px (desktop), 16px (mobile) |
|
|
|
|
|
+
|
|
|
|
|
+### Breakpoints
|
|
|
|
|
+
|
|
|
|
|
+| Имя | Минимальная ширина | Описание |
|
|
|
|
|
+|-----|-------------------|----------|
|
|
|
|
|
+| `sm` | 640px | Мобильный (альбом) |
|
|
|
|
|
+| `md` | 768px | Планшет |
|
|
|
|
|
+| `lg` | 1024px | Десктоп |
|
|
|
|
|
+| `xl` | 1280px | Широкий десктоп |
|
|
|
|
|
+| `2xl` | 1536px | Экстрабольшой |
|
|
|
|
|
+
|
|
|
|
|
+### Border Radius
|
|
|
|
|
+
|
|
|
|
|
+| Токен | Значение | Использование |
|
|
|
|
|
+|-------|----------|---------------|
|
|
|
|
|
+| `--radius-sm` | 6px | Кнопки, инпуты |
|
|
|
|
|
+| `--radius-md` | 8px | Карточки, модалки |
|
|
|
|
|
+| `--radius-lg` | 12px | Крупные блоки |
|
|
|
|
|
+| `--radius-xl` | 16px | Hero-элементы |
|
|
|
|
|
+| `--radius-2xl` | 24px | Аватары, круглые элементы |
|
|
|
|
|
+| `--radius-full` | 9999px | Пилюли, бейджи |
|
|
|
|
|
+
|
|
|
|
|
+### Shadows (тёмная тема)
|
|
|
|
|
+
|
|
|
|
|
+| Токен | Значение |
|
|
|
|
|
+|-------|----------|
|
|
|
|
|
+| `--shadow-sm` | `0 1px 2px rgba(0,0,0,0.4)` |
|
|
|
|
|
+| `--shadow-md` | `0 4px 6px -1px rgba(0,0,0,0.4), 0 2px 4px rgba(0,0,0,0.3)` |
|
|
|
|
|
+| `--shadow-lg` | `0 10px 15px -3px rgba(0,0,0,0.4), 0 4px 6px rgba(0,0,0,0.3)` |
|
|
|
|
|
+| `--shadow-xl` | `0 20px 25px -5px rgba(0,0,0,0.4), 0 8px 10px rgba(0,0,0,0.3)` |
|
|
|
|
|
+| `--shadow-glow` | `0 0 20px rgba(99,102,241,0.3)` |
|
|
|
|
|
+
|
|
|
|
|
+### Shadows (светлая тема)
|
|
|
|
|
+
|
|
|
|
|
+| Токен | Значение |
|
|
|
|
|
+|-------|----------|
|
|
|
|
|
+| `--shadow-sm` | `0 1px 2px rgba(0,0,0,0.05)` |
|
|
|
|
|
+| `--shadow-md` | `0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px rgba(0,0,0,0.06)` |
|
|
|
|
|
+| `--shadow-lg` | `0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px rgba(0,0,0,0.05)` |
|
|
|
|
|
+| `--shadow-xl` | `0 20px 25px -5px rgba(0,0,0,0.1), 0 8px 10px rgba(0,0,0,0.04)` |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 5. КОМПОНЕНТЫ
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Button
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Основной интерактивный элемент. Визуально — чистый, с чёткими состояниями.
|
|
|
|
|
+
|
|
|
|
|
+#### Variants
|
|
|
|
|
+
|
|
|
|
|
+**Primary**
|
|
|
|
|
+```css
|
|
|
|
|
+background: var(--primary);
|
|
|
|
|
+color: white;
|
|
|
|
|
+font-weight: 600;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Secondary**
|
|
|
|
|
+```css
|
|
|
|
|
+background: transparent;
|
|
|
|
|
+border: 1px solid var(--border);
|
|
|
|
|
+color: var(--text-primary);
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Ghost**
|
|
|
|
|
+```css
|
|
|
|
|
+background: transparent;
|
|
|
|
|
+color: var(--text-secondary);
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Danger**
|
|
|
|
|
+```css
|
|
|
|
|
+background: var(--error);
|
|
|
|
|
+color: white;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### Размеры
|
|
|
|
|
+
|
|
|
|
|
+| Размер | Высота | Padding | Шрифт | Border-radius |
|
|
|
|
|
+|--------|--------|---------|-------|---------------|
|
|
|
|
|
+| `sm` | 32px | 8px 12px | 13px | 6px |
|
|
|
|
|
+| `md` | 40px | 10px 16px | 14px | 8px |
|
|
|
|
|
+| `lg` | 48px | 12px 24px | 16px | 8px |
|
|
|
|
|
+| `xl` | 56px | 16px 32px | 18px | 12px |
|
|
|
|
|
+
|
|
|
|
|
+#### Состояния
|
|
|
|
|
+
|
|
|
|
|
+| Состояние | Изменение |
|
|
|
|
|
+|-----------|-----------|
|
|
|
|
|
+| Default | Базовый вид |
|
|
|
|
|
+| Hover | `brightness(1.1)`, `transform: translateY(-1px)` |
|
|
|
|
|
+| Active | `brightness(0.95)`, `transform: translateY(0)` |
|
|
|
|
|
+| Focus | `outline: 2px solid var(--primary)`, `outline-offset: 2px` |
|
|
|
|
|
+| Disabled | `opacity: 0.5`, `cursor: not-allowed` |
|
|
|
|
|
+| Loading | Спиннер вместо текста, `pointer-events: none` |
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+// Primary
|
|
|
|
|
+<button className="bg-indigo-600 text-white font-semibold rounded-lg
|
|
|
|
|
+ hover:bg-indigo-500 active:bg-indigo-700
|
|
|
|
|
+ focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-zinc-900
|
|
|
|
|
+ disabled:opacity-50 disabled:cursor-not-allowed
|
|
|
|
|
+ transition-all duration-150
|
|
|
|
|
+ px-4 py-2 text-sm">
|
|
|
|
|
+
|
|
|
|
|
+// Secondary
|
|
|
|
|
+<button className="bg-transparent border border-zinc-700 text-zinc-100 font-medium rounded-lg
|
|
|
|
|
+ hover:bg-zinc-800 active:bg-zinc-700
|
|
|
|
|
+ focus:outline-none focus:ring-2 focus:ring-zinc-500 focus:ring-offset-2 focus:ring-offset-zinc-900
|
|
|
|
|
+ disabled:opacity-50 disabled:cursor-not-allowed
|
|
|
|
|
+ transition-all duration-150
|
|
|
|
|
+ px-4 py-2 text-sm">
|
|
|
|
|
+
|
|
|
|
|
+// Ghost
|
|
|
|
|
+<button className="bg-transparent text-zinc-400 font-medium rounded-lg
|
|
|
|
|
+ hover:bg-zinc-800 hover:text-zinc-100 active:bg-zinc-700
|
|
|
|
|
+ focus:outline-none focus:ring-2 focus:ring-zinc-500 focus:ring-offset-2 focus:ring-offset-zinc-900
|
|
|
|
|
+ disabled:opacity-50 disabled:cursor-not-allowed
|
|
|
|
|
+ transition-all duration-150
|
|
|
|
|
+ px-4 py-2 text-sm">
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### Доступность
|
|
|
|
|
+- `aria-label` для кнопок с иконками
|
|
|
|
|
+- `aria-disabled="true"` вместо `disabled` для семантики
|
|
|
|
|
+- `role="button"` для div-кнопок (но лучше использовать `<button>`)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Input / TextField
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Поле ввода с лейблом, плейсхолдером и состояниями ошибки.
|
|
|
|
|
+
|
|
|
|
|
+#### Визуал
|
|
|
|
|
+```
|
|
|
|
|
+┌─────────────────────────────────┐
|
|
|
|
|
+│ Лейбл (обязательный) │
|
|
|
|
|
+├─────────────────────────────────┤
|
|
|
|
|
+│ Иконка │ Placeholder/Value │
|
|
|
|
|
+└─────────────────────────────────┘
|
|
|
|
|
+│ Текст ошибки (если есть) │
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### Размеры
|
|
|
|
|
+
|
|
|
|
|
+| Размер | Высота | Padding | Шрифт |
|
|
|
|
|
+|--------|--------|---------|-------|
|
|
|
|
|
+| `sm` | 32px | 8px 12px | 13px |
|
|
|
|
|
+| `md` | 40px | 10px 14px | 14px |
|
|
|
|
|
+| `lg` | 48px | 12px 16px | 16px |
|
|
|
|
|
+
|
|
|
|
|
+#### Состояния
|
|
|
|
|
+
|
|
|
|
|
+| Состояние | Визуал |
|
|
|
|
|
+|-----------|--------|
|
|
|
|
|
+| Default | `border-zinc-700`, `bg-zinc-900` |
|
|
|
|
|
+| Focus | `border-indigo-500`, `ring-2 ring-indigo-500/20` |
|
|
|
|
|
+| Error | `border-red-500`, `ring-2 ring-red-500/20` |
|
|
|
|
|
+| Disabled | `opacity-50`, `cursor-not-allowed` |
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+<div className="flex flex-col gap-1.5">
|
|
|
|
|
+ <label className="text-sm font-medium text-zinc-300">
|
|
|
|
|
+ Лейбл
|
|
|
|
|
+ </label>
|
|
|
|
|
+ <input
|
|
|
|
|
+ className="h-10 px-3 rounded-lg
|
|
|
|
|
+ bg-zinc-900 border border-zinc-700 text-zinc-100
|
|
|
|
|
+ placeholder:text-zinc-500
|
|
|
|
|
+ focus:outline-none focus:border-indigo-500 focus:ring-2 focus:ring-indigo-500/20
|
|
|
|
|
+ disabled:opacity-50 disabled:cursor-not-allowed
|
|
|
|
|
+ transition-colors duration-150
|
|
|
|
|
+ text-sm"
|
|
|
|
|
+ placeholder="Введите значение"
|
|
|
|
|
+ />
|
|
|
|
|
+ <span className="text-xs text-red-400">
|
|
|
|
|
+ Текст ошибки
|
|
|
|
|
+ </span>
|
|
|
|
|
+</div>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### Доступность
|
|
|
|
|
+- `aria-label` или `aria-labelledby` для лейбла
|
|
|
|
|
+- `aria-invalid="true"` при ошибке
|
|
|
|
|
+- `aria-describedby` для связи с текстом ошибки
|
|
|
|
|
+- `aria-required="true"` для обязательных полей
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Card
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Карточка для отображения локаций, студий, профилей. Главная фича — крупное фото.
|
|
|
|
|
+
|
|
|
|
|
+#### Визуал
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+┌─────────────────────────────────┐
|
|
|
|
|
+│ │
|
|
|
|
|
+│ [ФОТО / IMAGE] │
|
|
|
|
|
+│ │
|
|
|
|
|
+├─────────────────────────────────┤
|
|
|
|
|
+│ Заголовок карточки │
|
|
|
|
|
+│ Описание (2 строки) │
|
|
|
|
|
+│ │
|
|
|
|
|
+│ ★ 4.8 · Москва · Студия │
|
|
|
|
|
+├─────────────────────────────────┤
|
|
|
|
|
+│ [Забронировать] [Избранное ♡]│
|
|
|
|
|
+└─────────────────────────────────┘
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### Варианты
|
|
|
|
|
+
|
|
|
|
|
+| Вариант | Использование |
|
|
|
|
|
+|---------|---------------|
|
|
|
|
|
+| Default | Карточка локации в каталоге |
|
|
|
|
|
+| Compact | Карточка в боковой панели |
|
|
|
|
|
+| Featured | Крупная карточка в hero-секции |
|
|
|
|
|
+| Minimal | Карточка в списке результатов |
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+<div className="group rounded-xl bg-zinc-900 border border-zinc-800
|
|
|
|
|
+ overflow-hidden hover:border-zinc-700
|
|
|
|
|
+ transition-all duration-300 hover:shadow-xl hover:shadow-black/20
|
|
|
|
|
+ hover:-translate-y-1">
|
|
|
|
|
+
|
|
|
|
|
+ {/* Изображение */}
|
|
|
|
|
+ <div className="aspect-[4/3] overflow-hidden">
|
|
|
|
|
+ <img
|
|
|
|
|
+ className="w-full h-full object-cover
|
|
|
|
|
+ group-hover:scale-105 transition-transform duration-500"
|
|
|
|
|
+ src="..."
|
|
|
|
|
+ alt="..."
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Контент */}
|
|
|
|
|
+ <div className="p-4">
|
|
|
|
|
+ <h3 className="text-lg font-semibold text-zinc-100 mb-1">
|
|
|
|
|
+ Название
|
|
|
|
|
+ </h3>
|
|
|
|
|
+ <p className="text-sm text-zinc-400 line-clamp-2 mb-3">
|
|
|
|
|
+ Описание локации
|
|
|
|
|
+ </p>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Мета-информация */}
|
|
|
|
|
+ <div className="flex items-center gap-2 text-xs text-zinc-500">
|
|
|
|
|
+ <span className="flex items-center gap-1">
|
|
|
|
|
+ <StarIcon className="w-3.5 h-3.5 text-amber-400" />
|
|
|
|
|
+ 4.8
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span>·</span>
|
|
|
|
|
+ <span>Москва</span>
|
|
|
|
|
+ <span>·</span>
|
|
|
|
|
+ <span>Студия</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Действия */}
|
|
|
|
|
+ <div className="px-4 pb-4 flex items-center justify-between">
|
|
|
|
|
+ <button className="text-sm font-medium text-indigo-400 hover:text-indigo-300">
|
|
|
|
|
+ Забронировать
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button className="text-zinc-500 hover:text-rose-400 transition-colors">
|
|
|
|
|
+ <HeartIcon className="w-5 h-5" />
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</div>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### Доступность
|
|
|
|
|
+- `role="article"` или `<article>`
|
|
|
|
|
+- `alt` для изображений
|
|
|
|
|
+- `aria-label` для кнопок действий
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Badge / Tag
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Метки для категорий, статусов, тегов.
|
|
|
|
|
+
|
|
|
|
|
+#### Варианты
|
|
|
|
|
+
|
|
|
|
|
+| Вариант | Цвет | Использование |
|
|
|
|
|
+|---------|------|---------------|
|
|
|
|
|
+| Default | `bg-zinc-800 text-zinc-300` | Обычные теги |
|
|
|
|
|
+| Primary | `bg-indigo-500/20 text-indigo-400` | Основные категории |
|
|
|
|
|
+| Success | `bg-emerald-500/20 text-emerald-400` | Доступно, подтверждено |
|
|
|
|
|
+| Warning | `bg-amber-500/20 text-amber-400` | Ожидание, на модерации |
|
|
|
|
|
+| Error | `bg-red-500/20 text-red-400` | Ошибка, отменено |
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+<span className="inline-flex items-center gap-1 px-2.5 py-1 rounded-full
|
|
|
|
|
+ bg-indigo-500/20 text-indigo-400 text-xs font-medium">
|
|
|
|
|
+ Студия
|
|
|
|
|
+</span>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Modal / Dialog
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Модальное окно для форм, подтверждений, детальной информации.
|
|
|
|
|
+
|
|
|
|
|
+#### Размеры
|
|
|
|
|
+
|
|
|
|
|
+| Размер | Ширина | Описание |
|
|
|
|
|
+|--------|--------|----------|
|
|
|
|
|
+| `sm` | 400px | Подтверждения, простые формы |
|
|
|
|
|
+| `md` | 500px | Формы входа/регистрации |
|
|
|
|
|
+| `lg` | 640px | Сложные формы, детали |
|
|
|
|
|
+| `xl` | 800px | Полноэкранный просмотр |
|
|
|
|
|
+
|
|
|
|
|
+#### Визуал
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+┌─────────────────────────────────────────┐
|
|
|
|
|
+│ Заголовок [X закрыть]│
|
|
|
|
|
+├─────────────────────────────────────────┤
|
|
|
|
|
+│ │
|
|
|
|
|
+│ Содержимое │
|
|
|
|
|
+│ │
|
|
|
|
|
+├─────────────────────────────────────────┤
|
|
|
|
|
+│ [Отмена] [Действие] │
|
|
|
|
|
+└─────────────────────────────────────────┘
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+// Backdrop
|
|
|
|
|
+<div className="fixed inset-0 z-50 bg-black/60 backdrop-blur-sm
|
|
|
|
|
+ animate-in fade-in duration-200" />
|
|
|
|
|
+
|
|
|
|
|
+// Modal
|
|
|
|
|
+<div className="fixed left-1/2 top-1/2 z-50
|
|
|
|
|
+ -translate-x-1/2 -translate-y-1/2
|
|
|
|
|
+ w-full max-w-md p-6
|
|
|
|
|
+ bg-zinc-900 border border-zinc-800 rounded-xl shadow-2xl
|
|
|
|
|
+ animate-in fade-in zoom-in-95 duration-200">
|
|
|
|
|
+
|
|
|
|
|
+ {/* Header */}
|
|
|
|
|
+ <div className="flex items-center justify-between mb-4">
|
|
|
|
|
+ <h2 className="text-lg font-semibold text-zinc-100">
|
|
|
|
|
+ Заголовок
|
|
|
|
|
+ </h2>
|
|
|
|
|
+ <button className="text-zinc-500 hover:text-zinc-300">
|
|
|
|
|
+ <XIcon className="w-5 h-5" />
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Content */}
|
|
|
|
|
+ <div className="text-zinc-400">
|
|
|
|
|
+ Содержимое
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Footer */}
|
|
|
|
|
+ <div className="flex justify-end gap-3 mt-6">
|
|
|
|
|
+ <button className="secondary">Отмена</button>
|
|
|
|
|
+ <button className="primary">Подтвердить</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</div>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### Доступность
|
|
|
|
|
+- `role="dialog"`
|
|
|
|
|
+- `aria-modal="true"`
|
|
|
|
|
+- `aria-labelledby` для заголовка
|
|
|
|
|
+- Фокус внутри модалки (focus trap)
|
|
|
|
|
+- Закрытие по Escape
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Navigation (Header)
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Верхняя навигация с лого, ссылками и действиями пользователя.
|
|
|
|
|
+
|
|
|
|
|
+#### Визуал
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+┌─────────────────────────────────────────────────────────────┐
|
|
|
|
|
+│ PhotoPlaces Twilight Локации Студии Фотографы [Войти] │
|
|
|
|
|
+└─────────────────────────────────────────────────────────────┘
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+<header className="sticky top-0 z-40 w-full
|
|
|
|
|
+ bg-zinc-950/80 backdrop-blur-xl
|
|
|
|
|
+ border-b border-zinc-800">
|
|
|
|
|
+
|
|
|
|
|
+ <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
|
|
|
+ <div className="flex h-16 items-center justify-between">
|
|
|
|
|
+
|
|
|
|
|
+ {/* Logo */}
|
|
|
|
|
+ <Link href="/" className="flex items-center gap-2">
|
|
|
|
|
+ <CameraIcon className="h-8 w-8 text-indigo-500" />
|
|
|
|
|
+ <span className="text-xl font-bold text-zinc-100">
|
|
|
|
|
+ PhotoPlaces Twilight
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </Link>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Nav Links */}
|
|
|
|
|
+ <nav className="hidden md:flex items-center gap-6">
|
|
|
|
|
+ <Link href="/places" className="text-sm text-zinc-400 hover:text-zinc-100 transition-colors">
|
|
|
|
|
+ Локации
|
|
|
|
|
+ </Link>
|
|
|
|
|
+ <Link href="/studios" className="text-sm text-zinc-400 hover:text-zinc-100 transition-colors">
|
|
|
|
|
+ Студии
|
|
|
|
|
+ </Link>
|
|
|
|
|
+ <Link href="/photographers" className="text-sm text-zinc-400 hover:text-zinc-100 transition-colors">
|
|
|
|
|
+ Фотографы
|
|
|
|
|
+ </Link>
|
|
|
|
|
+ </nav>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Actions */}
|
|
|
|
|
+ <div className="flex items-center gap-3">
|
|
|
|
|
+ <button className="text-sm text-zinc-400 hover:text-zinc-100">
|
|
|
|
|
+ Войти
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button className="bg-indigo-600 text-white text-sm font-medium px-4 py-2 rounded-lg hover:bg-indigo-500">
|
|
|
|
|
+ Регистрация
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</header>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Footer
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Подвал сайта с ссылками, копирайтом, соцсетями.
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+<footer className="border-t border-zinc-800 bg-zinc-950">
|
|
|
|
|
+ <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-12">
|
|
|
|
|
+
|
|
|
|
|
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-8">
|
|
|
|
|
+ {/* Колонка 1: О проекте */}
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h3 className="text-sm font-semibold text-zinc-100 mb-4">
|
|
|
|
|
+ PhotoPlaces Twilight
|
|
|
|
|
+ </h3>
|
|
|
|
|
+ <p className="text-sm text-zinc-500">
|
|
|
|
|
+ Маркетплейс фотолокаций
|
|
|
|
|
+ </p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Колонка 2: Навигация */}
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h4 className="text-sm font-medium text-zinc-300 mb-3">Навигация</h4>
|
|
|
|
|
+ <ul className="space-y-2">
|
|
|
|
|
+ <li><a href="/places" className="text-sm text-zinc-500 hover:text-zinc-300">Локации</a></li>
|
|
|
|
|
+ <li><a href="/studios" className="text-sm text-zinc-500 hover:text-zinc-300">Студии</a></li>
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Колонка 3: Контакты */}
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h4 className="text-sm font-medium text-zinc-300 mb-3">Контакты</h4>
|
|
|
|
|
+ <ul className="space-y-2">
|
|
|
|
|
+ <li><a href="mailto:info@photoplaces.ru" className="text-sm text-zinc-500 hover:text-zinc-300">info@photoplaces.ru</a></li>
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ {/* Колонка 4: Соцсети */}
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <h4 className="text-sm font-medium text-zinc-300 mb-3">Соцсети</h4>
|
|
|
|
|
+ <div className="flex gap-3">
|
|
|
|
|
+ <a href="#" className="text-zinc-500 hover:text-zinc-300">
|
|
|
|
|
+ <TelegramIcon className="w-5 h-5" />
|
|
|
|
|
+ </a>
|
|
|
|
|
+ <a href="#" className="text-zinc-500 hover:text-zinc-300">
|
|
|
|
|
+ <InstagramIcon className="w-5 h-5" />
|
|
|
|
|
+ </a>
|
|
|
|
|
+ <a href="#" className="text-zinc-500 hover:text-zinc-300">
|
|
|
|
|
+ <PinterestIcon className="w-5 h-5" />
|
|
|
|
|
+ </a>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div className="mt-8 pt-8 border-t border-zinc-800">
|
|
|
|
|
+ <p className="text-xs text-zinc-600 text-center">
|
|
|
|
|
+ © 2024 PhotoPlaces Twilight. Все права защищены.
|
|
|
|
|
+ </p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ </div>
|
|
|
|
|
+</footer>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Toast / Notification
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Всплывающие уведомления о результатах действий.
|
|
|
|
|
+
|
|
|
|
|
+#### Варианты
|
|
|
|
|
+
|
|
|
|
|
+| Тип | Иконка | Цвет | Пример |
|
|
|
|
|
+|-----|--------|------|--------|
|
|
|
|
|
+| Success | CheckCircle | `text-emerald-400` | "Локация добавлена" |
|
|
|
|
|
+| Error | XCircle | `text-red-400` | "Ошибка сервера" |
|
|
|
|
|
+| Warning | AlertTriangle | `text-amber-400` | "Проверьте данные" |
|
|
|
|
|
+| Info | Info | `text-blue-400` | "Отправлена заявка" |
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+<div className="fixed bottom-4 right-4 z-50
|
|
|
|
|
+ flex items-center gap-3 px-4 py-3
|
|
|
|
|
+ bg-zinc-900 border border-zinc-800 rounded-lg shadow-xl
|
|
|
|
|
+ animate-in slide-in-from-bottom-5 fade-in duration-300">
|
|
|
|
|
+
|
|
|
|
|
+ <CheckCircleIcon className="w-5 h-5 text-emerald-400 shrink-0" />
|
|
|
|
|
+ <p className="text-sm text-zinc-100">
|
|
|
|
|
+ Локация успешно добавлена!
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <button className="text-zinc-500 hover:text-zinc-300 ml-2">
|
|
|
|
|
+ <XIcon className="w-4 h-4" />
|
|
|
|
|
+ </button>
|
|
|
|
|
+</div>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Tabs
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Переключение между секциями или вкладками.
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+<div className="border-b border-zinc-800">
|
|
|
|
|
+ <nav className="flex gap-6" role="tablist">
|
|
|
|
|
+ <button
|
|
|
|
|
+ role="tab"
|
|
|
|
|
+ aria-selected="true"
|
|
|
|
|
+ className="py-3 text-sm font-medium text-indigo-400 border-b-2 border-indigo-400"
|
|
|
|
|
+ >
|
|
|
|
|
+ Вкладка 1
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button
|
|
|
|
|
+ role="tab"
|
|
|
|
|
+ aria-selected="false"
|
|
|
|
|
+ className="py-3 text-sm font-medium text-zinc-500 hover:text-zinc-300 border-b-2 border-transparent"
|
|
|
|
|
+ >
|
|
|
|
|
+ Вкладка 2
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </nav>
|
|
|
|
|
+</div>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Tooltip / Popover
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Вспомогательная информация при наведении.
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+<div className="relative group">
|
|
|
|
|
+ <button>Элемент</button>
|
|
|
|
|
+ <div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2
|
|
|
|
|
+ px-3 py-1.5 rounded-lg
|
|
|
|
|
+ bg-zinc-800 text-zinc-200 text-xs
|
|
|
|
|
+ opacity-0 group-hover:opacity-100
|
|
|
|
|
+ transition-opacity duration-200
|
|
|
|
|
+ pointer-events-none
|
|
|
|
|
+ whitespace-nowrap">
|
|
|
|
|
+ Подсказка
|
|
|
|
|
+ <div className="absolute top-full left-1/2 -translate-x-1/2
|
|
|
|
|
+ border-4 border-transparent border-t-zinc-800" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+</div>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### Table
|
|
|
|
|
+
|
|
|
|
|
+#### Описание
|
|
|
|
|
+Таблица данных для админки, списков бронирований.
|
|
|
|
|
+
|
|
|
|
|
+#### Tailwind-классы
|
|
|
|
|
+
|
|
|
|
|
+```tsx
|
|
|
|
|
+<div className="overflow-x-auto rounded-lg border border-zinc-800">
|
|
|
|
|
+ <table className="w-full text-sm">
|
|
|
|
|
+ <thead>
|
|
|
|
|
+ <tr className="border-b border-zinc-800 bg-zinc-900/50">
|
|
|
|
|
+ <th className="text-left py-3 px-4 font-medium text-zinc-400">Название</th>
|
|
|
|
|
+ <th className="text-left py-3 px-4 font-medium text-zinc-400">Статус</th>
|
|
|
|
|
+ <th className="text-left py-3 px-4 font-medium text-zinc-400">Дата</th>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </thead>
|
|
|
|
|
+ <tbody>
|
|
|
|
|
+ <tr className="border-b border-zinc-800/50 hover:bg-zinc-900/50 transition-colors">
|
|
|
|
|
+ <td className="py-3 px-4 text-zinc-100">Название</td>
|
|
|
|
|
+ <td className="py-3 px-4">
|
|
|
|
|
+ <span className="inline-flex px-2 py-1 rounded-full bg-emerald-500/20 text-emerald-400 text-xs">
|
|
|
|
|
+ Активно
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </td>
|
|
|
|
|
+ <td className="py-3 px-4 text-zinc-400">01.01.2024</td>
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </tbody>
|
|
|
|
|
+ </table>
|
|
|
|
|
+</div>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 6. АНИМАЦИИ И ПЕРЕХОДЫ
|
|
|
|
|
+
|
|
|
|
|
+### Длительность
|
|
|
|
|
+
|
|
|
|
|
+| Токен | Значение | Использование |
|
|
|
|
|
+|-------|----------|---------------|
|
|
|
|
|
+| `--duration-fast` | 100ms | Hover-эффекты, color transitions |
|
|
|
|
|
+| `--duration-normal` | 200ms | Toggle, appearance |
|
|
|
|
|
+| `--duration-slow` | 300ms | Modal, dropdown |
|
|
|
|
|
+| `--duration-slower` | 500ms | Page transitions, complex |
|
|
|
|
|
+
|
|
|
|
|
+### Кривые
|
|
|
|
|
+
|
|
|
|
|
+| Токен | Значение | Использование |
|
|
|
|
|
+|-------|----------|---------------|
|
|
|
|
|
+| `--ease-default` | `cubic-bezier(0.4, 0, 0.2, 1)` | Стандартные переходы |
|
|
|
|
|
+| `--ease-in` | `cubic-bezier(0.4, 0, 1, 1)` | Уход элементов |
|
|
|
|
|
+| `--ease-out` | `cubic-bezier(0, 0, 0.2, 1)` | Появление элементов |
|
|
|
|
|
+| `--ease-spring` | `cubic-bezier(0.34, 1.56, 0.64, 1)` | Bounce-эффекты |
|
|
|
|
|
+
|
|
|
|
|
+### Примеры анимаций
|
|
|
|
|
+
|
|
|
|
|
+```css
|
|
|
|
|
+/* Появление модалки */
|
|
|
|
|
+@keyframes modal-in {
|
|
|
|
|
+ from {
|
|
|
|
|
+ opacity: 0;
|
|
|
|
|
+ transform: translate(-50%, -50%) scale(0.95);
|
|
|
|
|
+ }
|
|
|
|
|
+ to {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ transform: translate(-50%, -50%) scale(1);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Slide-in toast */
|
|
|
|
|
+@keyframes toast-in {
|
|
|
|
|
+ from {
|
|
|
|
|
+ opacity: 0;
|
|
|
|
|
+ transform: translateY(100%);
|
|
|
|
|
+ }
|
|
|
|
|
+ to {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+ transform: translateY(0);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Shimmer для skeleton */
|
|
|
|
|
+@keyframes shimmer {
|
|
|
|
|
+ 0% { background-position: -200% 0; }
|
|
|
|
|
+ 100% { background-position: 200% 0; }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.skeleton {
|
|
|
|
|
+ background: linear-gradient(
|
|
|
|
|
+ 90deg,
|
|
|
|
|
+ var(--bg-elevated) 25%,
|
|
|
|
|
+ var(--bg-hover) 50%,
|
|
|
|
|
+ var(--bg-elevated) 75%
|
|
|
|
|
+ );
|
|
|
|
|
+ background-size: 200% 100%;
|
|
|
|
|
+ animation: shimmer 1.5s infinite;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 7. ПРАВИЛА И ПРИНЦИПЫ
|
|
|
|
|
+
|
|
|
|
|
+### 1. Content First (Контент важнее декора)
|
|
|
|
|
+
|
|
|
|
|
+Фотографии — главные герои. Интерфейс обрамляет, но не перетягивает внимание.
|
|
|
|
|
+
|
|
|
|
|
+**Плохо:** Яркие рамки вокруг фото, мигающие кнопки, слишком много цвета
|
|
|
|
|
+**Хорошо:** Фото занимает 70% карточки, UI — тихий фон
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 2. Clarity Over Cleverness (Понятность важнее красивости)
|
|
|
|
|
+
|
|
|
|
|
+Пользователь должен понимать, что делать, без инструкций.
|
|
|
|
|
+
|
|
|
|
|
+**Плохо:** Кнопка-иконка без подписи,神秘ные жесты
|
|
|
|
|
+**Хорошо:** "Забронировать" вместо просто иконки корзины
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 3. Accessible by Default (Доступность не опциональность)
|
|
|
|
|
+
|
|
|
|
|
+Каждый элемент должен работать для всех пользователей.
|
|
|
|
|
+
|
|
|
|
|
+**Плохо:** Серый текст на сером фоне, нет фокуса, нет aria
|
|
|
|
|
+**Хорошо:** Контраст 4.5:1, видимый фокус, семантический HTML
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 4. Consistent Rhythm (Единый ритм)
|
|
|
|
|
+
|
|
|
|
|
+Отступы, размеры, анимации следуют единой системе.
|
|
|
|
|
+
|
|
|
|
|
+**Плохо:** Разные отступы в карточках, рандомные размеры шрифтов
|
|
|
|
|
+**Хорошо:** Везде spacing-4, text-sm для описаний, radius-lg для карточек
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 5. Progressive Disclosure (Показывай по необходимости)
|
|
|
|
|
+
|
|
|
|
|
+Не перегружай интерфейс. Показывай детали по мере необходимости.
|
|
|
|
|
+
|
|
|
|
|
+**Плохо:** Вся форма бронирования на главной
|
|
|
|
|
+**Хорошо:** Сначала карточка → клик → модалка с формой
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 8. ТОКЕНЫ ДЛЯ FIGMA
|
|
|
|
|
+
|
|
|
|
|
+### JSON-структура (Tokens Studio)
|
|
|
|
|
+
|
|
|
|
|
+> PhotoPlaces Twilight Design Tokens
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "colors": {
|
|
|
|
|
+ "primary": {
|
|
|
|
|
+ "50": "#EEF2FF",
|
|
|
|
|
+ "100": "#E0E7FF",
|
|
|
|
|
+ "200": "#C7D2FE",
|
|
|
|
|
+ "300": "#A5B4FC",
|
|
|
|
|
+ "400": "#818CF8",
|
|
|
|
|
+ "500": "#6366F1",
|
|
|
|
|
+ "600": "#4F46E5",
|
|
|
|
|
+ "700": "#4338CA",
|
|
|
|
|
+ "800": "#3730A3",
|
|
|
|
|
+ "900": "#312E81"
|
|
|
|
|
+ },
|
|
|
|
|
+ "secondary": {
|
|
|
|
|
+ "500": "#F59E0B",
|
|
|
|
|
+ "600": "#D97706"
|
|
|
|
|
+ },
|
|
|
|
|
+ "accent": {
|
|
|
|
|
+ "500": "#06B6D4",
|
|
|
|
|
+ "600": "#0891B2"
|
|
|
|
|
+ },
|
|
|
|
|
+ "neutral": {
|
|
|
|
|
+ "50": "#FAFAFA",
|
|
|
|
|
+ "100": "#F4F4F5",
|
|
|
|
|
+ "200": "#E4E4E7",
|
|
|
|
|
+ "300": "#D4D4D8",
|
|
|
|
|
+ "400": "#A1A1AA",
|
|
|
|
|
+ "500": "#71717A",
|
|
|
|
|
+ "600": "#52525B",
|
|
|
|
|
+ "700": "#3F3F46",
|
|
|
|
|
+ "800": "#27272A",
|
|
|
|
|
+ "900": "#18181B",
|
|
|
|
|
+ "950": "#09090B"
|
|
|
|
|
+ },
|
|
|
|
|
+ "success": { "500": "#22C55E" },
|
|
|
|
|
+ "warning": { "500": "#F59E0B" },
|
|
|
|
|
+ "error": { "500": "#EF4444" },
|
|
|
|
|
+ "info": { "500": "#3B82F6" }
|
|
|
|
|
+ },
|
|
|
|
|
+ "typography": {
|
|
|
|
|
+ "fontFamily": {
|
|
|
|
|
+ "heading": "Inter, sans-serif",
|
|
|
|
|
+ "body": "Inter, sans-serif",
|
|
|
|
|
+ "mono": "JetBrains Mono, monospace"
|
|
|
|
|
+ },
|
|
|
|
|
+ "fontSize": {
|
|
|
|
|
+ "xs": { "value": "12px", "lineHeight": "16px" },
|
|
|
|
|
+ "sm": { "value": "14px", "lineHeight": "20px" },
|
|
|
|
|
+ "base": { "value": "16px", "lineHeight": "24px" },
|
|
|
|
|
+ "lg": { "value": "18px", "lineHeight": "28px" },
|
|
|
|
|
+ "xl": { "value": "20px", "lineHeight": "28px" },
|
|
|
|
|
+ "2xl": { "value": "24px", "lineHeight": "32px" },
|
|
|
|
|
+ "3xl": { "value": "30px", "lineHeight": "36px" },
|
|
|
|
|
+ "4xl": { "value": "36px", "lineHeight": "40px" },
|
|
|
|
|
+ "5xl": { "value": "48px", "lineHeight": "48px" }
|
|
|
|
|
+ },
|
|
|
|
|
+ "fontWeight": {
|
|
|
|
|
+ "normal": "400",
|
|
|
|
|
+ "medium": "500",
|
|
|
|
|
+ "semibold": "600",
|
|
|
|
|
+ "bold": "700"
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ "spacing": {
|
|
|
|
|
+ "0": "0px",
|
|
|
|
|
+ "0.5": "2px",
|
|
|
|
|
+ "1": "4px",
|
|
|
|
|
+ "1.5": "6px",
|
|
|
|
|
+ "2": "8px",
|
|
|
|
|
+ "3": "12px",
|
|
|
|
|
+ "4": "16px",
|
|
|
|
|
+ "5": "20px",
|
|
|
|
|
+ "6": "24px",
|
|
|
|
|
+ "8": "32px",
|
|
|
|
|
+ "10": "40px",
|
|
|
|
|
+ "12": "48px",
|
|
|
|
|
+ "16": "64px",
|
|
|
|
|
+ "20": "80px"
|
|
|
|
|
+ },
|
|
|
|
|
+ "borderRadius": {
|
|
|
|
|
+ "sm": "6px",
|
|
|
|
|
+ "md": "8px",
|
|
|
|
|
+ "lg": "12px",
|
|
|
|
|
+ "xl": "16px",
|
|
|
|
|
+ "2xl": "24px",
|
|
|
|
|
+ "full": "9999px"
|
|
|
|
|
+ },
|
|
|
|
|
+ "boxShadow": {
|
|
|
|
|
+ "sm": "0 1px 2px rgba(0,0,0,0.4)",
|
|
|
|
|
+ "md": "0 4px 6px -1px rgba(0,0,0,0.4), 0 2px 4px rgba(0,0,0,0.3)",
|
|
|
|
|
+ "lg": "0 10px 15px -3px rgba(0,0,0,0.4), 0 4px 6px rgba(0,0,0,0.3)",
|
|
|
|
|
+ "xl": "0 20px 25px -5px rgba(0,0,0,0.4), 0 8px 10px rgba(0,0,0,0.3)",
|
|
|
|
|
+ "glow": "0 0 20px rgba(99,102,241,0.3)"
|
|
|
|
|
+ },
|
|
|
|
|
+ "duration": {
|
|
|
|
|
+ "fast": "100ms",
|
|
|
|
|
+ "normal": "200ms",
|
|
|
|
|
+ "slow": "300ms",
|
|
|
|
|
+ "slower": "500ms"
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 9. CSS-ПЕРЕМЕННЫЕ
|
|
|
|
|
+
|
|
|
|
|
+```css
|
|
|
|
|
+/* PhotoPlaces Twilight Design System */
|
|
|
|
|
+:root {
|
|
|
|
|
+ /* ========== LIGHT THEME ========== */
|
|
|
|
|
+ --bg: #FAFAFA;
|
|
|
|
|
+ --bg-elevated: #FFFFFF;
|
|
|
|
|
+ --bg-hover: #F4F4F5;
|
|
|
|
|
+ --border: #E4E4E7;
|
|
|
|
|
+ --border-subtle: #F4F4F5;
|
|
|
|
|
+ --text-primary: #18181B;
|
|
|
|
|
+ --text-secondary: #52525B;
|
|
|
|
|
+ --text-muted: #A1A1AA;
|
|
|
|
|
+
|
|
|
|
|
+ /* Shadows */
|
|
|
|
|
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
|
|
|
|
|
+ --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px rgba(0,0,0,0.06);
|
|
|
|
|
+ --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px rgba(0,0,0,0.05);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+[data-theme="dark"] {
|
|
|
|
|
+ /* ========== DARK THEME ========== */
|
|
|
|
|
+ --bg: #09090B;
|
|
|
|
|
+ --bg-elevated: #18181B;
|
|
|
|
|
+ --bg-hover: #27272A;
|
|
|
|
|
+ --border: #3F3F46;
|
|
|
|
|
+ --border-subtle: #27272A;
|
|
|
|
|
+ --text-primary: #FAFAFA;
|
|
|
|
|
+ --text-secondary: #A1A1AA;
|
|
|
|
|
+ --text-muted: #71717A;
|
|
|
|
|
+
|
|
|
|
|
+ /* Shadows */
|
|
|
|
|
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.4);
|
|
|
|
|
+ --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.4), 0 2px 4px rgba(0,0,0,0.3);
|
|
|
|
|
+ --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.4), 0 4px 6px rgba(0,0,0,0.3);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:root {
|
|
|
|
|
+ /* ========== COLORS ========== */
|
|
|
|
|
+ --primary: #6366F1;
|
|
|
|
|
+ --primary-hover: #4F46E5;
|
|
|
|
|
+ --secondary: #F59E0B;
|
|
|
|
|
+ --accent: #06B6D4;
|
|
|
|
|
+
|
|
|
|
|
+ /* Functional */
|
|
|
|
|
+ --success: #22C55E;
|
|
|
|
|
+ --warning: #F59E0B;
|
|
|
|
|
+ --error: #EF4444;
|
|
|
|
|
+ --info: #3B82F6;
|
|
|
|
|
+
|
|
|
|
|
+ /* ========== TYPOGRAPHY ========== */
|
|
|
|
|
+ --font-heading: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
|
|
|
+ --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
|
|
|
+ --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
|
|
|
|
+
|
|
|
|
|
+ /* ========== SPACING ========== */
|
|
|
|
|
+ --space-0: 0px;
|
|
|
|
|
+ --space-1: 4px;
|
|
|
|
|
+ --space-2: 8px;
|
|
|
|
|
+ --space-3: 12px;
|
|
|
|
|
+ --space-4: 16px;
|
|
|
|
|
+ --space-5: 20px;
|
|
|
|
|
+ --space-6: 24px;
|
|
|
|
|
+ --space-8: 32px;
|
|
|
|
|
+ --space-10: 40px;
|
|
|
|
|
+ --space-12: 48px;
|
|
|
|
|
+ --space-16: 64px;
|
|
|
|
|
+ --space-20: 80px;
|
|
|
|
|
+
|
|
|
|
|
+ /* ========== BORDER RADIUS ========== */
|
|
|
|
|
+ --radius-sm: 6px;
|
|
|
|
|
+ --radius-md: 8px;
|
|
|
|
|
+ --radius-lg: 12px;
|
|
|
|
|
+ --radius-xl: 16px;
|
|
|
|
|
+ --radius-2xl: 24px;
|
|
|
|
|
+ --radius-full: 9999px;
|
|
|
|
|
+
|
|
|
|
|
+ /* ========== TRANSITIONS ========== */
|
|
|
|
|
+ --duration-fast: 100ms;
|
|
|
|
|
+ --duration-normal: 200ms;
|
|
|
|
|
+ --duration-slow: 300ms;
|
|
|
|
|
+ --duration-slower: 500ms;
|
|
|
|
|
+
|
|
|
|
|
+ --ease-default: cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
|
|
+ --ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
|
|
|
+ --ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
|
|
|
+ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 10. TAILWIND CONFIG
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+// tailwind.config.js
|
|
|
|
|
+// PhotoPlaces Twilight Design System
|
|
|
|
|
+/** @type {import('tailwindcss').Config} */
|
|
|
|
|
+module.exports = {
|
|
|
|
|
+ content: ['./src/**/*.{ts,tsx}'],
|
|
|
|
|
+ darkMode: ['class', '[data-theme="dark"]'],
|
|
|
|
|
+ theme: {
|
|
|
|
|
+ extend: {
|
|
|
|
|
+ colors: {
|
|
|
|
|
+ primary: {
|
|
|
|
|
+ 50: '#EEF2FF',
|
|
|
|
|
+ 100: '#E0E7FF',
|
|
|
|
|
+ 200: '#C7D2FE',
|
|
|
|
|
+ 300: '#A5B4FC',
|
|
|
|
|
+ 400: '#818CF8',
|
|
|
|
|
+ 500: '#6366F1',
|
|
|
|
|
+ 600: '#4F46E5',
|
|
|
|
|
+ 700: '#4338CA',
|
|
|
|
|
+ 800: '#3730A3',
|
|
|
|
|
+ 900: '#312E81',
|
|
|
|
|
+ },
|
|
|
|
|
+ secondary: {
|
|
|
|
|
+ 500: '#F59E0B',
|
|
|
|
|
+ 600: '#D97706',
|
|
|
|
|
+ },
|
|
|
|
|
+ accent: {
|
|
|
|
|
+ 500: '#06B6D4',
|
|
|
|
|
+ 600: '#0891B2',
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ fontFamily: {
|
|
|
|
|
+ heading: ['Inter', 'sans-serif'],
|
|
|
|
|
+ body: ['Inter', 'sans-serif'],
|
|
|
|
|
+ mono: ['JetBrains Mono', 'monospace'],
|
|
|
|
|
+ },
|
|
|
|
|
+ fontSize: {
|
|
|
|
|
+ 'xs': ['12px', { lineHeight: '16px' }],
|
|
|
|
|
+ 'sm': ['14px', { lineHeight: '20px' }],
|
|
|
|
|
+ 'base': ['16px', { lineHeight: '24px' }],
|
|
|
|
|
+ 'lg': ['18px', { lineHeight: '28px' }],
|
|
|
|
|
+ 'xl': ['20px', { lineHeight: '28px' }],
|
|
|
|
|
+ '2xl': ['24px', { lineHeight: '32px' }],
|
|
|
|
|
+ '3xl': ['30px', { lineHeight: '36px' }],
|
|
|
|
|
+ '4xl': ['36px', { lineHeight: '40px' }],
|
|
|
|
|
+ '5xl': ['48px', { lineHeight: '48px' }],
|
|
|
|
|
+ },
|
|
|
|
|
+ spacing: {
|
|
|
|
|
+ '0.5': '2px',
|
|
|
|
|
+ '1.5': '6px',
|
|
|
|
|
+ '18': '72px',
|
|
|
|
|
+ '88': '352px',
|
|
|
|
|
+ },
|
|
|
|
|
+ borderRadius: {
|
|
|
|
|
+ 'sm': '6px',
|
|
|
|
|
+ 'md': '8px',
|
|
|
|
|
+ 'lg': '12px',
|
|
|
|
|
+ 'xl': '16px',
|
|
|
|
|
+ '2xl': '24px',
|
|
|
|
|
+ },
|
|
|
|
|
+ boxShadow: {
|
|
|
|
|
+ 'glow': '0 0 20px rgba(99,102,241,0.3)',
|
|
|
|
|
+ 'glow-lg': '0 0 40px rgba(99,102,241,0.4)',
|
|
|
|
|
+ },
|
|
|
|
|
+ animation: {
|
|
|
|
|
+ 'fade-in': 'fade-in 0.2s ease-out',
|
|
|
|
|
+ 'slide-up': 'slide-up 0.3s ease-out',
|
|
|
|
|
+ 'slide-down': 'slide-down 0.3s ease-out',
|
|
|
|
|
+ 'scale-in': 'scale-in 0.2s ease-out',
|
|
|
|
|
+ },
|
|
|
|
|
+ keyframes: {
|
|
|
|
|
+ 'fade-in': {
|
|
|
|
|
+ '0%': { opacity: '0' },
|
|
|
|
|
+ '100%': { opacity: '1' },
|
|
|
|
|
+ },
|
|
|
|
|
+ 'slide-up': {
|
|
|
|
|
+ '0%': { transform: 'translateY(10px)', opacity: '0' },
|
|
|
|
|
+ '100%': { transform: 'translateY(0)', opacity: '1' },
|
|
|
|
|
+ },
|
|
|
|
|
+ 'slide-down': {
|
|
|
|
|
+ '0%': { transform: 'translateY(-10px)', opacity: '0' },
|
|
|
|
|
+ '100%': { transform: 'translateY(0)', opacity: '1' },
|
|
|
|
|
+ },
|
|
|
|
|
+ 'scale-in': {
|
|
|
|
|
+ '0%': { transform: 'scale(0.95)', opacity: '0' },
|
|
|
|
|
+ '100%': { transform: 'scale(1)', opacity: '1' },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ plugins: [
|
|
|
|
|
+ require('tailwindcss-animate'),
|
|
|
|
|
+ ],
|
|
|
|
|
+}
|
|
|
|
|
+```
|