Files
sfera-new/docs/presentation-layer/UI_COMPONENT_RULES.md
Veronika Smirnova 12fd8ddf61 feat(supplier-orders): добавить параметры поставки в таблицу заявок
- Добавлены колонки Объём и Грузовые места между Цена товаров и Статус
- Реализованы инпуты для ввода volume и packagesCount в статусе PENDING для роли WHOLESALE
- Добавлена мутация UPDATE_SUPPLY_PARAMETERS с проверками безопасности
- Скрыта строка Поставщик для роли WHOLESALE (поставщик знает свои данные)
- Исправлено выравнивание таблицы при скрытии уровня поставщика
- Реорганизованы документы: legacy-rules/, docs/, docs-and-reports/

ВНИМАНИЕ: Компонент multilevel-supplies-table.tsx (1697 строк) нарушает правило модульной архитектуры (>800 строк требует рефакторинга)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-23 18:47:23 +03:00

1088 lines
34 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UI КОМПОНЕНТЫ СИСТЕМЫ SFERA
## 🎯 ОБЗОР UI СИСТЕМЫ
SFERA использует современную дизайн-систему основанную на **Radix UI**, **Class Variance Authority (CVA)** и **Tailwind CSS** с уникальным **Glass Morphism** стилем. Система включает 36 специализированных UI компонентов с полной типизацией TypeScript.
### Архитектурные принципы:
- **Headless UI** - Radix UI для функциональности + кастомная стилизация
- **Variant-driven** - CVA для типизированных вариантов компонентов
- **Glass Morphism** - Современные полупрозрачные эффекты с backdrop-filter
- **Accessibility First** - Полная поддержка ARIA и клавиатурной навигации
- **TypeScript Native** - Строгая типизация всех props и вариантов
## 📦 ПОЛНЫЙ КАТАЛОГ КОМПОНЕНТОВ (36 компонентов)
### 🔘 1. BUTTON (button.tsx)
**Описание:** Основной интерактивный элемент с множественными вариантами дизайна.
```typescript
interface ButtonProps {
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link' | 'glass' | 'glass-secondary'
size?: 'default' | 'sm' | 'lg' | 'icon'
asChild?: boolean
}
```
**Варианты стилей:**
- **`default`** - основная фиолетовая кнопка `bg-primary text-primary-foreground`
- **`destructive`** - красная кнопка для опасных действий `bg-destructive text-white`
- **`outline`** - кнопка с границей `border bg-background`
- **`secondary`** - вторичная кнопка `bg-secondary text-secondary-foreground`
- **`ghost`** - прозрачная кнопка `hover:bg-accent`
- **`link`** - текстовая ссылка `text-primary underline-offset-4`
- **`glass`** - Glass Morphism стиль с градиентом
- **`glass-secondary`** - полупрозрачная Glass кнопка
**Размеры:**
- **`default`** - `h-9 px-4 py-2` (36px высота)
- **`sm`** - `h-8 px-3` (32px высота)
- **`lg`** - `h-10 px-6` (40px высота)
- **`icon`** - `size-9` (36x36px квадрат)
**Пример использования:**
```typescript
<Button variant="glass" size="lg">
Сохранить изменения
</Button>
```
### 🃏 2. CARD (card.tsx)
**Описание:** Контейнер для группировки связанного контента с составной архитектурой.
```typescript
// Составные компоненты
<Card>
<CardHeader>
<CardTitle>Заголовок карточки</CardTitle>
<CardDescription>Описание содержимого</CardDescription>
<CardAction>Действие</CardAction>
</CardHeader>
<CardContent>
Основное содержимое
</CardContent>
<CardFooter>
Нижняя часть
</CardFooter>
</Card>
```
**CSS классы:**
- **Card**: `bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm`
- **CardHeader**: Использует CSS Grid для автоматического позиционирования
- **CardTitle**: `leading-none font-semibold`
- **CardDescription**: `text-muted-foreground text-sm`
### ⌨️ 3. INPUT (input.tsx)
**Описание:** Поле ввода текста с поддержкой Glass Morphism и состояний фокуса.
```typescript
interface InputProps extends React.ComponentProps<'input'> {
// Стандартные HTML input props
}
// Два варианта стилизации
<Input placeholder="Стандартное поле" />
<GlassInput placeholder="Glass Morphism поле" />
```
**Стили Input:**
- Базовый класс: `h-9 w-full rounded-md border bg-transparent px-3 py-1`
- Фокус: `focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]`
- Ошибка: `aria-invalid:ring-destructive/20 aria-invalid:border-destructive`
**Стили GlassInput:**
- Базовый класс: `glass-input text-white placeholder:text-white/60`
- Размеры: `h-11 rounded-lg px-4 py-3` (больше обычного input)
- Эффекты: полупрозрачный фон с backdrop-filter
### 🏷️ 4. BADGE (badge.tsx)
**Описание:** Небольшие метки для отображения статуса, категорий или счетчиков.
```typescript
interface BadgeProps {
variant?: 'default' | 'secondary' | 'destructive' | 'outline'
asChild?: boolean
}
```
**Варианты:**
- **`default`** - `bg-primary text-primary-foreground`
- **`secondary`** - `bg-secondary text-secondary-foreground`
- **`destructive`** - `bg-destructive text-white`
- **`outline`** - `text-foreground border` (прозрачный фон)
**Базовые стили:**
- Размер: `px-2 py-0.5 text-xs font-medium`
- Форма: `rounded-md border`
- Поддержка иконок: `[&>svg]:size-3 gap-1`
### 📊 5. PROGRESS (progress.tsx)
**Описание:** Индикатор прогресса для отображения выполнения задач.
```typescript
<Progress value={75} className="w-full" />
```
### 📱 6. ALERT (alert.tsx)
**Описание:** Компонент для отображения важных сообщений пользователю.
```typescript
<Alert>
<AlertTitle>Внимание</AlertTitle>
<AlertDescription>Важное сообщение для пользователя</AlertDescription>
</Alert>
```
### 🗂️ 7. TABS (tabs.tsx)
**Описание:** Система вкладок для переключения между разными представлениями.
```typescript
<Tabs defaultValue="tab1">
<TabsList>
<TabsTrigger value="tab1">Вкладка 1</TabsTrigger>
<TabsTrigger value="tab2">Вкладка 2</TabsTrigger>
</TabsList>
<TabsContent value="tab1">Содержимое 1</TabsContent>
<TabsContent value="tab2">Содержимое 2</TabsContent>
</Tabs>
```
**Особенности стилизации:**
- Список вкладок: Glass Morphism фон `background: rgba(255, 255, 255, 0.12)`
- Активная вкладка: `background: rgba(255, 255, 255, 0.2)` с белым текстом
- Hover эффект: `background: rgba(255, 255, 255, 0.1)`
### 📝 8. TEXTAREA (textarea.tsx)
**Описание:** Многострочное поле ввода текста.
```typescript
<Textarea placeholder="Введите текст..." rows={4} />
```
### ☑️ 9. CHECKBOX (checkbox.tsx)
**Описание:** Чекбокс для выбора опций.
```typescript
<Checkbox checked={isChecked} onCheckedChange={setIsChecked} />
```
### 🎚️ 10. SWITCH (switch.tsx)
**Описание:** Переключатель для включения/выключения функций.
```typescript
<Switch checked={isEnabled} onCheckedChange={setIsEnabled} />
```
### 🎚️ 11. SLIDER (slider.tsx)
**Описание:** Ползунок для выбора числовых значений.
```typescript
<Slider defaultValue={[50]} max={100} step={1} />
```
### 📅 12. CALENDAR (calendar.tsx)
**Описание:** Компонент календаря для выбора дат.
```typescript
<Calendar mode="single" selected={date} onSelect={setDate} />
```
### 📅 13. DATE-PICKER (date-picker.tsx)
**Описание:** Поле выбора даты с календарем.
```typescript
<DatePicker value={date} onChange={setDate} />
```
### 📅 14. GLASS-DATE-PICKER (glass-date-picker.tsx)
**Описание:** Date picker в Glass Morphism стиле.
```typescript
<GlassDatePicker value={date} onChange={setDate} />
```
### 📋 15. SELECT (select.tsx)
**Описание:** Выпадающий список для выбора опций.
```typescript
<Select value={value} onValueChange={setValue}>
<SelectTrigger>
<SelectValue placeholder="Выберите опцию" />
</SelectTrigger>
<SelectContent>
<SelectItem value="option1">Опция 1</SelectItem>
<SelectItem value="option2">Опция 2</SelectItem>
</SelectContent>
</Select>
```
### 📋 16. GLASS-SELECT (glass-select.tsx)
**Описание:** Select в Glass Morphism стиле для темных фонов.
### 🏷️ 17. LABEL (label.tsx)
**Описание:** Метки для полей форм с accessibility.
```typescript
<Label htmlFor="email">Email адрес</Label>
<Input id="email" type="email" />
```
### 👤 18. AVATAR (avatar.tsx)
**Описание:** Отображение аватаров пользователей с fallback.
```typescript
<Avatar>
<AvatarImage src="/avatar.jpg" alt="User" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
```
### 🌐 19. DIALOG (dialog.tsx)
**Описание:** Модальные окна для важного контента.
```typescript
<Dialog>
<DialogTrigger>Открыть диалог</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Заголовок</DialogTitle>
<DialogDescription>Описание</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button>Сохранить</Button>
</DialogFooter>
</DialogContent>
</Dialog>
```
### ⚠️ 20. ALERT-DIALOG (alert-dialog.tsx)
**Описание:** Критичные диалоги подтверждения.
```typescript
<AlertDialog>
<AlertDialogTrigger>Удалить</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Подтвердите удаление</AlertDialogTitle>
<AlertDialogDescription>
Это действие нельзя отменить.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Отмена</AlertDialogCancel>
<AlertDialogAction>Удалить</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
```
### 💬 21. POPOVER (popover.tsx)
**Описание:** Всплывающие элементы для дополнительного контента.
```typescript
<Popover>
<PopoverTrigger>Показать информацию</PopoverTrigger>
<PopoverContent>
Дополнительная информация
</PopoverContent>
</Popover>
```
### 📱 22. DROPDOWN-MENU (dropdown-menu.tsx)
**Описание:** Выпадающие меню для действий и навигации.
```typescript
<DropdownMenu>
<DropdownMenuTrigger>Меню</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Действие 1</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Действие 2</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
```
### 23. SEPARATOR (separator.tsx)
**Описание:** Визуальные разделители контента.
```typescript
<Separator orientation="horizontal" />
<Separator orientation="vertical" />
```
### 📱 24. PHONE-INPUT (phone-input.tsx)
**Описание:** Специализированное поле для ввода номеров телефонов.
```typescript
<PhoneInput value={phone} onChange={setPhone} />
```
### 💀 25. SKELETON (skeleton.tsx)
**Описание:** Плейсхолдеры для загружающегося контента.
```typescript
<Skeleton className="h-4 w-full" />
<Skeleton className="h-8 w-8 rounded-full" />
```
### 🛒 26. PRODUCT-CARD-SKELETON (product-card-skeleton.tsx)
**Описание:** Специализированный скелетон для карточек товаров.
```typescript
<ProductCardSkeleton />
```
### ⏳ 27. LOADING-FALLBACK (loading-fallback.tsx)
**Описание:** Компонент загрузки для асинхронного контента.
```typescript
<LoadingFallback text="Загрузка данных..." />
```
## 🎵 МЕДИА КОМПОНЕНТЫ
### 🎤 28. VOICE-RECORDER (voice-recorder.tsx)
**Описание:** Запись голосовых сообщений с реального времени UI.
```typescript
<VoiceRecorder onRecordingComplete={handleRecording} />
```
### ▶️ 29. VOICE-PLAYER (voice-player.tsx)
**Описание:** Воспроизведение аудио сообщений с прогресс-баром.
```typescript
<VoicePlayer audioUrl="/audio.mp3" duration={30} />
```
### 🖼️ 30. IMAGE-MESSAGE (image-message.tsx)
**Описание:** Отображение изображений в сообщениях.
```typescript
<ImageMessage src="/image.jpg" alt="Сообщение" />
```
### 🔍 31. IMAGE-LIGHTBOX (image-lightbox.tsx)
**Описание:** Полноэкранный просмотр изображений.
```typescript
<ImageLightbox images={imageUrls} initialIndex={0} />
```
### 📄 32. FILE-MESSAGE (file-message.tsx)
**Описание:** Отображение файловых вложений.
```typescript
<FileMessage fileName="document.pdf" fileSize={1024000} fileUrl="/file.pdf" />
```
### 📤 33. FILE-UPLOADER (file-uploader.tsx)
**Описание:** Загрузка файлов с drag & drop.
```typescript
<FileUploader onFileSelect={handleFiles} accept=".pdf,.doc,.docx" />
```
### 😀 34. EMOJI-PICKER (emoji-picker.tsx)
**Описание:** Выбор эмодзи для сообщений.
```typescript
<EmojiPicker onEmojiSelect={handleEmojiSelect} />
```
### 📊 35. CHART (chart.tsx)
**Описание:** Компоненты для отображения графиков и диаграмм.
```typescript
<Chart data={chartData} type="line" />
```
### 🔔 36. SONNER (sonner.tsx)
**Описание:** Система toast уведомлений.
```typescript
import { toast } from 'sonner'
toast.success('Операция выполнена успешно')
toast.error('Произошла ошибка')
toast.info('Информационное сообщение')
```
## 📊 КАСТОМНЫЕ ТАБЛИЦЫ СИСТЕМЫ
### 🏷️ 37. MULTILEVEL SUPPLIES TABLE (multilevel-supplies-table.tsx)
**Описание:** Многоуровневая таблица поставок для кабинета селлера в разделе "Мои поставки".
**Интерфейсы:**
```typescript
interface MultiLevelSuppliesTableProps {
supplies?: SupplyOrderFromGraphQL[]
loading?: boolean
userRole?: 'SELLER' | 'WHOLESALE' | 'FULFILLMENT' | 'LOGIST'
onSupplyAction?: (supplyId: string, action: string) => void
}
interface SupplyOrderFromGraphQL {
id: string
organizationId: string
partnerId: string
partner: {
id: string
name?: string
fullName?: string
inn: string
address?: string
type: string
}
deliveryDate: string
status: string
totalAmount: number
totalItems: number
fulfillmentCenter?: {
id: string
name?: string
address?: string
}
routes: Route[]
items: SupplyItem[]
createdAt: string
}
```
**Особенности:**
- Трехуровневая структура: Поставка → Маршруты → Товары
- Раскрываемые/сворачиваемые уровни
- Различные представления для разных ролей пользователей
- Glass morphism дизайн с полупрозрачными карточками
**Использование:**
```typescript
<MultiLevelSuppliesTable
supplies={suppliesData}
loading={isLoading}
userRole="SELLER"
onSupplyAction={(id, action) => handleSupplyAction(id, action)}
/>
```
### 📦 38. GOODS SUPPLIES TABLE (goods-supplies-table.tsx)
**Описание:** Таблица товарных поставок с детальной структурой.
**Интерфейсы:**
```typescript
interface GoodsSuppliesTableProps {
supplies?: GoodsSupply[]
loading?: boolean
onActionClick?: (supplyId: string, action: string) => void
}
interface GoodsSupply {
id: string
number: string
creationMethod: 'cards' | 'suppliers' // 📱 карточки / 🏢 поставщик
date: string
status: SupplyStatus
totalAmount: number
routes: GoodsSupplyRoute[]
}
interface GoodsSupplyRoute {
id: string
from: string
fromAddress: string
to: string
toAddress: string
wholesalers: GoodsSupplyWholesaler[]
totalProductPrice: number
fulfillmentServicePrice: number
logisticsPrice: number
totalAmount: number
}
interface GoodsSupplyProduct {
id: string
name: string
sku: string
category: string
plannedQty: number
actualQty: number
defectQty: number
productPrice: number
parameters: ProductParameter[]
}
```
**Особенности:**
- Четырехуровневая структура: Поставка → Маршрут → Поставщик → Товар
- Детальная информация по каждому уровню
- Цветовая индикация статусов
- Расчет итоговых сумм на каждом уровне
- Поддержка параметров товаров
**Статусы поставок:**
```typescript
type SupplyStatus =
| 'new' // Новая
| 'confirmed' // Подтверждена
| 'in_transit' // В пути
| 'at_fulfillment' // На фулфилменте
| 'in_processing' // В обработке
| 'completed' // Завершена
| 'cancelled' // Отменена
| 'issue' // Проблема
```
**Использование:**
```typescript
<GoodsSuppliesTable
supplies={goodsSupplies}
loading={isLoading}
onActionClick={(id, action) => {
if (action === 'view') navigateToDetails(id)
if (action === 'cancel') cancelSupply(id)
}}
/>
```
## 🎨 ДИЗАЙН-СИСТЕМА КОМПОНЕНТОВ
### Унифицированные props:
```typescript
// Большинство компонентов поддерживают:
interface CommonProps {
className?: string // Дополнительные CSS классы
asChild?: boolean // Использование как Slot от Radix
'data-slot'?: string // Автоматический слот для идентификации
}
```
### Паттерн CVA (Class Variance Authority):
```typescript
const componentVariants = cva(
'базовые-классы', // Общие стили для всех вариантов
{
variants: {
variant: {
// Варианты дизайна
default: 'стили-по-умолчанию',
secondary: 'вторичные-стили',
},
size: {
// Размеры
sm: 'маленький-размер',
lg: 'большой-размер',
},
},
defaultVariants: {
// Значения по умолчанию
variant: 'default',
size: 'default',
},
},
)
```
### Accessibility Features:
- **ARIA Support** - все компоненты поддерживают ARIA атрибуты
- **Keyboard Navigation** - полная навигация с клавиатуры
- **Focus Management** - логичное управление фокусом
- **Screen Reader** - совместимость с программами чтения экрана
### Glass Morphism Effects:
```css
.glass-card {
background: rgba(255, 255, 255, 0.12);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(168, 85, 247, 0.18);
}
.glass-input {
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.15);
}
.glass-button {
background: linear-gradient(135deg, rgba(168, 85, 247, 0.9) 0%, rgba(59, 130, 246, 0.85) 100%);
backdrop-filter: blur(20px);
}
```
## 🔧 ПРАВИЛА ИСПОЛЬЗОВАНИЯ
### 1. Типизация компонентов
```typescript
// ✅ Правильно - с типизацией
<Button variant="glass" size="lg" onClick={handleClick}>
Действие
</Button>
// ❌ Неправильно - без типизации
<button className="some-custom-class">
Действие
</button>
```
### 2. Композиция сложных компонентов
```typescript
// ✅ Правильно - составная структура
<Card>
<CardHeader>
<CardTitle>Заказ #1234</CardTitle>
<CardAction>
<Button size="sm">Детали</Button>
</CardAction>
</CardHeader>
<CardContent>
<p>Описание заказа</p>
</CardContent>
</Card>
// ❌ Неправильно - плоская структура
<div className="card">
<h3>Заказ #1234</h3>
<p>Описание заказа</p>
</div>
```
### 3. Glass Morphism для темных фонов
```typescript
// ✅ Правильно - Glass компоненты на темном фоне
<div className="bg-gradient-cosmic">
<GlassInput placeholder="Поиск..." />
<Button variant="glass">Найти</Button>
</div>
// ❌ Неправильно - обычные компоненты на темном фоне
<div className="bg-black">
<Input placeholder="Поиск..." /> {/* Не видно */}
</div>
```
### 4. Accessibility обязателен
```typescript
// ✅ Правильно - с accessibility
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
aria-describedby="email-error"
aria-invalid={hasError}
/>
{hasError && <span id="email-error">Неверный формат email</span>}
// ❌ Неправильно - без accessibility
<span>Email</span>
<input type="email" />
```
### 5. Состояния загрузки
```typescript
// ✅ Правильно - скелетоны для загрузки
{loading ? (
<ProductCardSkeleton />
) : (
<ProductCard data={product} />
)}
// ❌ Неправильно - пустая область
{loading ? null : <ProductCard data={product} />}
```
## 🏪 КОМПОНЕНТЫ КАБИНЕТА ПОСТАВЩИКА (WHOLESALE)
### АРХИТЕКТУРА КОМПОНЕНТОВ ПОСТАВЩИКА:
```typescript
src/components/
├── warehouse/ # Компоненты склада поставщика
├── warehouse-dashboard.tsx # Главный dashboard склада
├── product-card.tsx # Карточка товара
├── product-form.tsx # Форма создания/редактирования товара
└── warehouse-statistics.tsx # Статистика склада
├── supplier-orders/ # Компоненты обработки заказов
├── supplier-orders-dashboard.tsx # Главный dashboard заказов
├── supplier-order-card.tsx # Карточка заказа
├── supplier-orders-tabs.tsx # Табы по статусам заказов
├── supplier-orders-search.tsx # Поиск и фильтры
└── supplier-order-stats.tsx # Статистика заказов
└── economics/ # Экономическая аналитика
└── wholesale-economics-page.tsx # Финансовая отчетность
```
### 🏢 КАРТОЧКА ПОСТАВЩИКА В ИНТЕРФЕЙСЕ:
**Структура карточки:**
```jsx
<div className="supplier-card glass-card">
<div className="flex items-start gap-2">
{/* Аватар организации */}
<OrganizationAvatar organization={supplier} size="sm" />
<div className="flex-1 min-w-0">
{/* Название поставщика */}
<h4 className="text-white font-medium text-sm truncate">{supplier.name || supplier.fullName}</h4>
{/* ИНН и рынок */}
<div className="flex items-center gap-2 mt-1">
<p className="text-white/60 text-xs font-mono">ИНН: {supplier.inn}</p>
{supplier.market && <Badge className="market-badge">{getMarketLabel(supplier.market)}</Badge>}
</div>
</div>
</div>
</div>
```
**Визуальные правила карточки поставщика:**
- **Аватар**: Размер `sm`, позиционирование слева от текста
- **Название**: Приоритет `name` над `fullName`, с усечением `truncate`
- **ИНН**: Моноширинный шрифт `font-mono`, цвет `text-white/60`
- **Рынок**: Badge компонент с индивидуальными цветовыми схемами
- **Glass эффект**: `glass-card` класс с полупрозрачным фоном
### 🔍 ПОИСКОВЫЙ ИНТЕРФЕЙС ПОСТАВЩИКОВ:
```jsx
<Input
placeholder="Поиск поставщиков..."
className="bg-white/5 border-white/10 text-white placeholder:text-white/50 pl-10 h-9"
onChange={(e) => handleSupplierSearch(e.target.value)}
/>
```
**Особенности поиска:**
- Glass эффект: `bg-white/5 border-white/10`
- Плейсхолдер: `placeholder:text-white/50`
- Левый отступ для иконки: `pl-10`
- Высота: `h-9` (36px)
### 🎨 ЦВЕТОВЫЕ СХЕМЫ РЫНКОВ ПОСТАВЩИКОВ:
```typescript
// Примеры цветовых схем для физических рынков
const marketColors = {
sadovod: 'bg-green-500/20 text-green-300 border-green-500/30',
'tyak-moscow': 'bg-blue-500/20 text-blue-300 border-blue-500/30',
default: 'bg-gray-500/20 text-gray-300 border-gray-500/30',
}
// Функция получения метки рынка
function getMarketLabel(market: string): string {
const labels = {
sadovod: 'Садовод',
'tyak-moscow': 'ТЯК Москва',
default: 'Рынок',
}
return labels[market] || labels.default
}
```
### 📦 БЛОКИ ПОСТАВЩИКОВ В СЕЛЛЕР ИНТЕРФЕЙСЕ:
**Правила горизонтальной прокрутки:**
```jsx
{
/* Контейнер с горизонтальной прокруткой */
}
;<div className="flex gap-3 overflow-x-auto scrollbar-hide pb-2">
{suppliers.map((supplier) => (
<div
key={supplier.id}
className="flex-none w-64" // Фиксированная ширина 256px
>
<SupplierCard supplier={supplier} />
</div>
))}
</div>
```
**Требования к горизонтальным блокам:**
- Фиксированная ширина карточек: `w-64` (256px)
- Отсутствие сжатия: `flex-none`
- Скрытие скроллбара: `scrollbar-hide`
- Отступ от низа: `pb-2` для визуального комфорта
### 🚨 CRITICAL UI RULES ДЛЯ ПОСТАВЩИКОВ:
#### **1. СТАТУСЫ vs КНОПКИ ДЕЙСТВИЙ:**
```jsx
{
/* ❌ НЕПРАВИЛЬНО: Показывать статус поставщику */
}
{
user.organization.type === 'WHOLESALE' && <StatusBadge status={order.status}>Ожидает подтверждения</StatusBadge>
}
{
/* ✅ ПРАВИЛЬНО: Только кнопки действий для поставщика */
}
{
user.organization.type === 'WHOLESALE' && order.status === 'PENDING' && (
<div className="flex gap-2">
<Button variant="glass" size="sm" onClick={() => approveOrder(order.id)}>
Одобрить
</Button>
<Button variant="outline" size="sm" onClick={() => rejectOrder(order.id)}>
Отклонить
</Button>
</div>
)
}
```
#### **2. ОПЦИОНАЛЬНЫЕ ПАРАМЕТРЫ ПОСТАВКИ ПРИ ОДОБРЕНИИ:**
```jsx
{
/* ОПЦИОНАЛЬНЫЕ параметры поставки для поставщика - отображаются при одобрении заказа */
}
;<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="packagesCount">Количество грузовых мест</Label>
<Input
id="packagesCount"
type="number"
placeholder="Введите количество (опционально)"
aria-describedby="packages-help"
/>
<p id="packages-help" className="text-xs text-white/60 mt-1">
Параметр поставки для логистических расчетов
</p>
</div>
<div>
<Label htmlFor="volume">Объем груза (м³)</Label>
<Input id="volume" type="number" step="0.01" placeholder="0.00 (опционально)" aria-describedby="volume-help" />
<p id="volume-help" className="text-xs text-white/60 mt-1">
Параметр поставки для планирования маршрутов
</p>
</div>
<div>
<Label htmlFor="deliveryDate">Дата поставки</Label>
<GlassDatePicker
id="deliveryDate"
placeholder="Выберите дату поставки"
aria-describedby="delivery-help"
/>
<p id="delivery-help" className="text-xs text-white/60 mt-1">
Основной параметр поставки - когда товары должны быть доставлены
</p>
</div>
<div>
<Label htmlFor="totalAmount">Общая стоимость товаров</Label>
<Input id="totalAmount" type="number" readOnly className="bg-white/5" />
<p className="text-xs text-white/60 mt-1">
Ключевой параметр поставки - автоматически рассчитывается
</p>
</div>
<div className="col-span-2">
<Label htmlFor="readyDate">Дата готовности к отгрузке</Label>
<GlassDatePicker
id="readyDate"
value={readyDate}
onChange={setReadyDate}
placeholder="Выберите дату (опционально)"
aria-describedby="ready-date-help"
/>
<p id="ready-date-help" className="text-xs text-white/60 mt-1">
Когда товары будут готовы к передаче логистике
</p>
</div>
<div className="col-span-2">
<Label htmlFor="notes">Комментарии для логистики</Label>
<Textarea id="notes" placeholder="Дополнительная информация (опционально)" aria-describedby="notes-help" />
<p id="notes-help" className="text-xs text-white/60 mt-1">
Особые требования к транспортировке или упаковке
</p>
</div>
</div>
{
/* ВАЖНО: Поля показываются на 1-м уровне визуализации поставки */
}
;<div className="mt-4">
<p className="text-sm text-white/80"> Все поля опциональны, но рекомендуются для точного планирования логистики</p>
</div>
```
#### **3. ARIA LABELS ДЛЯ КОМПОНЕНТОВ ПОСТАВЩИКА:**
```jsx
// Кнопки действий с описательными ARIA-атрибутами
<Button
variant="glass"
aria-label={`Одобрить заказ №${order.number} от ${order.organization.name}`}
onClick={() => approveOrder(order.id)}
>
Одобрить
</Button>
// Поля ввода с полными описаниями
<Input
aria-label="Количество грузовых мест для логистического расчета"
aria-required="true"
aria-describedby="packages-error packages-help"
/>
```
#### **4. СПЕЦИАЛЬНЫЕ РАЗМЕРЫ ДЛЯ КАБИНЕТА ПОСТАВЩИКА:**
```typescript
// Размеры карточек в кабинете поставщика
const wholesaleSizes = {
supplierCard: 'h-[164px] w-64', // 164px высота, 256px ширина
orderCard: 'min-h-[120px]', // Минимум 120px для заказов
productCard: 'h-[180px]', // 180px для товарных карточек
containerWithPadding: 'h-[196px]', // 164 + 32px отступы сверху/снизу
}
```
### 📐 ФОРМУЛА РАСЧЕТА РАЗМЕРОВ КОНТЕЙНЕРОВ:
```typescript
// ОБЯЗАТЕЛЬНАЯ формула для всех контейнеров поставщика
const containerHeight = {
formula: 'Высота контента + padding-top + padding-bottom',
example: {
content: '164px', // Высота карточки поставщика
paddingTop: '16px',
paddingBottom: '16px',
totalContainer: '196px' // 164 + 16 + 16 = 196px
}
}
// ❌ ЗАПРЕЩЕНО: Произвольные размеры без расчета
<div className="h-200"> {/* Откуда 200px? */}
// ✅ ПРАВИЛЬНО: С математическим обоснованием
<div className="h-[196px]"> {/* 164px + 32px отступы */}
```
## 📱 АДАПТИВНОСТЬ
### Responsive Breakpoints:
- **`sm`** - `640px` и выше
- **`md`** - `768px` и выше
- **`lg`** - `1024px` и выше
- **`xl`** - `1280px` и выше
### Mobile-First подход:
```typescript
// ✅ Правильно
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
{items.map(item => <Card key={item.id}>{item.name}</Card>)}
</div>
// ❌ Неправильно
<div className="grid-cols-3"> {/* Не адаптивно */}
```
## 🚀 ПРОИЗВОДИТЕЛЬНОСТЬ
### Lazy Loading компонентов:
```typescript
const HeavyComponent = lazy(() => import('./heavy-component'))
// Использование с Suspense
<Suspense fallback={<LoadingFallback />}>
<HeavyComponent />
</Suspense>
```
### Мемоизация дорогих вычислений:
```typescript
const ExpensiveComponent = memo(({ data }) => {
const processedData = useMemo(() =>
processLargeDataset(data), [data]
)
return <Chart data={processedData} />
})
```
---
_UI компоненты задокументированы на основе анализа 36 файлов в src/components/ui/_
_Версия документа: 2025-08-21_
_Основа: Radix UI + CVA + Tailwind CSS + Glass Morphism_