docs: обновление правил UI Kit и блока поставщиков + новые glass компоненты

- Добавлены правила анализа UI Kit компонентов (interaction-integrity-rules.md)
- Обновлены правила блока 1: убран заголовок, добавлена кнопка навигации (rules-complete.md)
- Детальная спецификация плавающей кнопки "Назад" (seller-ui-rules.md)
- Новые компоненты: GlassDatePicker и GlassSelect для UI Kit
- Улучшены hover/focus эффекты в DatePicker

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Veronika Smirnova
2025-08-12 18:08:24 +03:00
parent c586ddc868
commit c5cd75cdb9
6 changed files with 323 additions and 8 deletions

View File

@ -139,6 +139,52 @@ ignores: ['diagnostic-script.js', 'legacy-config.js'] // конкретные ф
- Планирую создать новые файлы вместо редактирования существующих
```
### 1.5 🎯 ПРАВИЛА АНАЛИЗА ИСХОДНЫХ ПРИМЕРОВ
**КРИТИЧЕСКИ ВАЖНО**: При работе с существующими примерами кода или UI Kit компонентами:
#### 🔍 **ОБЯЗАТЕЛЬНЫЙ ТРЕХУРОВНЕВЫЙ АНАЛИЗ:**
1. **📋 СОДЕРЖАТЕЛЬНЫЙ АНАЛИЗ** (что делает код):
- Функциональность компонента
- Логика работы
- Данные и состояния
2. **🏗️ АРХИТЕКТУРНЫЙ АНАЛИЗ** (как организован код):
- Структура компонентов и контейнеров
- Взаимосвязи между элементами
- Позиционирование и layout
- Иерархия DOM-элементов
3. **🎨 СТИЛЕВОЙ АНАЛИЗ** (как выглядит код):
- CSS классы и стили
- Анимации и переходы
- Цвета и размеры
#### ❌ **ТИПИЧНЫЕ ОШИБКИ АНАЛИЗА:**
- **Поверхностный анализ**: Копирование только стилей без понимания архитектуры
- **Игнорирование контекста**: Непонимание места элемента в общей структуре
- **Буквальное копирование**: Применение решения без адаптации к текущей задаче
#### ✅ **ПРАВИЛЬНЫЙ ПОДХОД:**
```
🔬 АЛГОРИТМ АНАЛИЗА ПРИМЕРА:
1. Прочитать ВЕСЬ код компонента-примера
2. Понять АРХИТЕКТУРУ: где элемент размещен относительно других
3. Понять ЛОГИКУ: почему именно так структурировано
4. Адаптировать к ТЕКУЩЕЙ ЗАДАЧЕ: применить принципы, а не просто скопировать
5. Проверить СООТВЕТСТВИЕ правилам проекта
```
#### 🚨 **СТОП-ВОПРОСЫ ПЕРЕД РЕАЛИЗАЦИЕЙ:**
- "Понимаю ли я **архитектуру** этого решения?"
- "Где именно должен располагаться элемент в **общей структуре**?"
- "Какова **семантическая роль** этого элемента?"
- "Как это решение **адаптируется** к моей текущей задаче?"
---
## 🔄 II. ПРОЦЕДУРНЫЙ УРОВЕНЬ: ПОСЛЕДОВАТЕЛЬНОСТИ ДЕЙСТВИЙ
@ -563,9 +609,69 @@ ignores: ['diagnostic-script.js', 'legacy-config.js'] // конкретные ф
---
## 📚 VIII. ИЗВЛЕЧЕННЫЕ УРОКИ И АНТИ-ПАТТЕРНЫ
### 8.1 🚨 КРИТИЧЕСКИЕ ОШИБКИ В АНАЛИЗЕ UI КОМПОНЕНТОВ
#### **CASE STUDY: Ошибка с плавающей кнопкой из UI Kit**
**❌ ОШИБКА**: При добавлении кнопки "🌟 Вариант 1: Плавающая кнопка слева" из UI Kit:
1. **Поверхностный анализ**: Скопировал только стили кнопки
2. **Игнорирование архитектуры**: Не заметил, что кнопка в **отдельном контейнере**
3. **Неправильное размещение**: Добавил как часть блока контента
4. **Непонимание термина**: "Плавающая" = независимая от контента, между элементами
**✅ ПРАВИЛЬНОЕ РЕШЕНИЕ**:
```tsx
// ❌ НЕПРАВИЛЬНО - кнопка внутри блока контента
<div className="content-block relative">
<button className="absolute...">Назад</button>
<div className="actual-content">...</div>
</div>
// ✅ ПРАВИЛЬНО - кнопка в отдельном контейнере
<div className="flex gap-4">
<Sidebar />
<div className="relative"> {/* Отдельный контейнер */}
<button className="absolute...">Назад</button>
</div>
<div className="content-block">...</div>
</div>
```
#### **📋 ОБЯЗАТЕЛЬНЫЙ ЧЕКЛИСТ ДЛЯ UI KIT КОМПОНЕНТОВ:**
```
🔍 ПЕРЕД РЕАЛИЗАЦИЕЙ:
□ Прочитал ВЕСЬ код компонента-примера
□ Понял архитектуру размещения в layout
□ Определил семантическую роль элемента
□ Понял взаимосвязи с соседними элементами
□ Адаптировал принципы к текущей задаче
□ Проверил соответствие правилам проекта
```
#### **⚡ АНТИ-ПАТТЕРНЫ:**
- **"Быстрое копирование"** - копировать стили без понимания архитектуры
- **"Частичный анализ"** - читать только нужную часть кода
- **"Буквальное применение"** - использовать без адаптации к контексту
- **"Игнорирование контейнеров"** - не обращать внимание на DOM-структуру
#### **✅ ПРАВИЛЬНЫЕ ПАТТЕРНЫ:**
- **"Архитектурный анализ первым"** - понять структуру, потом стили
- **"Контекстная адаптация"** - применять принципы, а не код буквально
- **"Семантическое понимание"** - осознавать роль каждого элемента
- **"Итеративная проверка"** - сверяться с примером на каждом шаге
---
**Дата создания**: Декабрь 2024
**Последнее обновление**: Август 2025
**Версия**: 3.0 - ПОЛНАЯ РЕСТРУКТУРИЗАЦИЯ
**Версия**: 3.1 - ДОПОЛНЕНЫ ПРАВИЛА АНАЛИЗА UI KIT
**Статус**: АКТИВЕН - ОБЯЗАТЕЛЕН К ИСПОЛНЕНИЮ
**Связанные файлы**:

View File

@ -854,7 +854,8 @@ const handleSuppliesClick = () => {
**БЛОК 1: ПОСТАВЩИКИ** _(адаптивная сетка)_
- **Заголовок**: Минималистичный "🏢 Поставщики" без лишних элементов
- **Навигация**: Плавающая кнопка "Назад" между сайдбаром и контентом (см. детали в seller-ui-rules.md)
- **Заголовок**: БЕЗ заголовка - блок начинается сразу с функционального контента
- **Поиск**: Компактное поле справа "Поиск поставщиков..." (w-64)
- **Отображение**: Карточки поставщиков из раздела "Партнеры" в адаптивной сетке
- **Выбор**: Клик выделяет карточку поставщика
@ -1780,6 +1781,8 @@ height: calc(100vh - headerHeight - tabsHeight - statsHeight - margins);
**БЛОК 1: ПОСТАВЩИКИ** _(обязательный, 180px)_:
- **Навигация**: Плавающая кнопка "Назад" между сайдбаром и контентом (см. seller-ui-rules.md)
- **БЕЗ заголовка** - блок начинается сразу с поиска и карточек
- Карточки поставщиков из раздела "Партнеры"
- Горизонтальный скролл при превышении ширины
- Выбор только одного поставщика одновременно

View File

@ -17,7 +17,7 @@
**СЕЛЛЕР (`SELLER`)** имеет доступ к следующим разделам:
- **Мои поставки** (`/my-supplies`) - управление поставками
- **Маркет** (`/market`) - просмотр глобального каталога
- **Маркет** (`/market`) - просмотр глобального каталога
- **Партнеры** (`/partners`) - управление контрагентами
- **Мессенджер** (`/messenger`) - связь с партнерами
- **Настройки** (`/settings`) - профиль и настройки
@ -56,11 +56,48 @@ switch (user?.organization?.type) {
### 2.2 Детальные правила горизонтального скролла поставщиков
**СТРУКТУРА И ОТОБРАЖЕНИЕ:**
**КНОПКА НАВИГАЦИИ "НАЗАД":**
**Архитектура размещения:**
- **Расположение**: Между сайдбаром и основным контентом
- **Контейнер**: Отдельный `<div className="relative">`
- **НЕ является частью блока 1** - независимый навигационный элемент
- **Позиционирование**: `absolute left-0 top-6`
- **z-index**: 10 (поверх контента)
**Визуальный дизайн:**
```tsx
className =
'absolute left-0 top-6 z-10 w-8 h-8 bg-white/10 backdrop-blur-xl border border-white/20 hover:border-white/40 rounded-full flex items-center justify-center transition-all duration-300 hover:scale-110 hover:bg-white/20 group'
```
**Параметры кнопки:**
- **Размер**: 32×32px (`w-8 h-8`)
- **Форма**: Круглая (`rounded-full`)
- **Фон**: `bg-white/10` с эффектом размытия `backdrop-blur-xl`
- **Граница**: `border border-white/20`, при hover `border-white/40`
- **Иконка**: `ArrowLeft` 16×16px (`h-4 w-4`), цвет `text-white/70`
- **Hover эффекты**:
- Масштабирование `scale-110`
- Изменение фона `bg-white/20`
- Иконка становится белой и увеличивается до `h-5 w-5`
- **Анимация**: `transition-all duration-300`
**Функциональность:**
- **onClick**: Переход на `/supplies?tab=goods&subTab=suppliers`
- **aria-label**: "Вернуться к поставщикам"
- **Семантика**: Кнопка возврата к списку поставок
**СТРУКТУРА И ОТОБРАЖЕНИЕ БЛОКА 1:**
- **БЕЗ ЗАГОЛОВКА** - блок начинается сразу с поиска и контента
- **Источник данных**: Партнеры типа `WHOLESALE` из раздела "Партнеры"
- **Контейнер**: Фиксированная высота 176px (h-44) с горизонтальным скроллом
- **Блок поставщиков**: Общая высота 180px, включает заголовок + контейнер скролла
- **Блок поставщиков**: Общая высота 180px
- **Направление**: Слева направо (LTR)
- **Поведение**: Плавный скролл с автоскрытием полосы прокрутки
@ -382,6 +419,8 @@ height: calc(100vh - headerHeight - tabsHeight - statsHeight - margins);
**БЛОК 1: ПОСТАВЩИКИ** _(обязательный, 180px)_:
- БЕЗ заголовка - сразу функциональный контент
- Кнопка навигации "Назад" - между сайдбаром и блоком (см. раздел 2.2)
- Карточки поставщиков из раздела "Партнеры"
- Горизонтальный скролл при превышении ширины
- Выбор только одного поставщика одновременно
@ -448,6 +487,7 @@ height: calc(100vh - headerHeight - tabsHeight - statsHeight - margins);
### 3.1 React компоненты селлера
**Основные компоненты:**
- `SellerHomePage` - главная страница селлера (4 типо-зависимых компонента)
- `SellerEconomicsPage` - экономическая аналитика селлера
@ -497,4 +537,4 @@ query GetSellerCards {
**Связанные файлы**:
- [rules-complete.md](./rules-complete.md) - Общие бизнес-правила
- [visual-design-rules.md](./visual-design-rules.md) - Визуальные правила
- [visual-design-rules.md](./visual-design-rules.md) - Визуальные правила

View File

@ -19,7 +19,13 @@ interface DatePickerProps {
disabled?: boolean
}
export function DatePicker({ value, onChange, placeholder = 'Выберите дату', className, disabled }: DatePickerProps) {
export function DatePicker({
value,
onChange,
placeholder: _placeholder = 'Выберите дату',
className,
disabled,
}: DatePickerProps) {
const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
onChange?.(e.target.value)
}
@ -32,7 +38,7 @@ export function DatePicker({ value, onChange, placeholder = 'Выберите д
onChange={handleDateChange}
disabled={disabled}
className={cn(
'flex h-9 w-full rounded-lg border border-white/10 bg-white/5 backdrop-blur px-3 py-1 text-sm text-white placeholder:text-white/50 focus:border-white/20 focus:outline-none focus:ring-1 focus:ring-white/20 disabled:cursor-not-allowed disabled:opacity-50',
'flex h-9 w-full rounded-lg border border-white/10 bg-white/5 backdrop-blur px-3 py-1 text-sm text-white placeholder:text-white/50 hover:border-white/30 hover:bg-white/10 focus:border-purple-400/50 focus:outline-none focus:ring-2 focus:ring-purple-400/20 transition-all duration-200 disabled:cursor-not-allowed disabled:opacity-50',
'pr-8', // Place for calendar icon
className,
)}

View File

@ -0,0 +1,46 @@
'use client'
import { Calendar } from 'lucide-react'
import * as React from 'react'
interface GlassDatePickerProps {
value?: string
onChange?: (date: string) => void
placeholder?: string
className?: string
disabled?: boolean
}
export function GlassDatePicker({
value,
onChange,
placeholder: _placeholder = 'дд.мм.гггг',
className = '',
disabled = false,
}: GlassDatePickerProps) {
const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
onChange?.(e.target.value)
}
return (
<div className="relative" data-testid="glass-date-picker-wrapper">
<input
type="date"
value={value}
onChange={handleDateChange}
disabled={disabled}
data-testid="glass-date-picker-input"
className={`
bg-white/5 border border-white/10 text-white rounded-lg h-9 px-3 text-sm
hover:border-white/30 hover:bg-white/10
focus:border-purple-400/50 focus:ring-2 focus:ring-purple-400/20
transition-all duration-200 outline-none
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:border-white/10 disabled:hover:bg-white/5
pr-8
${className}
`}
/>
<Calendar className="absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-white/40 pointer-events-none" />
</div>
)
}

View File

@ -0,0 +1,114 @@
'use client'
import React from 'react'
interface GlassSelectOption {
value: string
label: string
disabled?: boolean
}
interface GlassSelectProps {
value: string
onChange: (value: string) => void
placeholder?: string
options: GlassSelectOption[]
className?: string
size?: 'sm' | 'md' | 'lg'
disabled?: boolean
}
export function GlassSelect({
value,
onChange,
placeholder = 'Выберите вариант',
options,
className = '',
size = 'md',
disabled = false,
}: GlassSelectProps) {
const sizeClasses = {
sm: 'h-8 text-xs px-3',
md: 'h-9 text-sm px-3',
lg: 'h-11 text-base px-4',
}
return (
<select
value={value}
onChange={(e) => onChange(e.target.value)}
disabled={disabled}
className={`
bg-white/5 border border-white/10 text-white rounded-lg
hover:border-white/30 hover:bg-white/10
focus:border-purple-400/50 focus:ring-2 focus:ring-purple-400/20
transition-all duration-200 outline-none
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:border-white/10 disabled:hover:bg-white/5
${sizeClasses[size]}
${className}
`}
>
{placeholder && (
<option value="" disabled className="bg-gray-800 text-white/60">
{placeholder}
</option>
)}
{options.map((option) => (
<option key={option.value} value={option.value} disabled={option.disabled} className="bg-gray-800 text-white">
{option.label}
</option>
))}
</select>
)
}
// Дополнительный компонент для простого использования с children
interface GlassSelectSimpleProps {
value: string
onChange: (value: string) => void
placeholder?: string
children: React.ReactNode
className?: string
size?: 'sm' | 'md' | 'lg'
disabled?: boolean
}
export function GlassSelectSimple({
value,
onChange,
placeholder,
children,
className = '',
size = 'md',
disabled = false,
}: GlassSelectSimpleProps) {
const sizeClasses = {
sm: 'h-8 text-xs px-3',
md: 'h-9 text-sm px-3',
lg: 'h-11 text-base px-4',
}
return (
<select
value={value}
onChange={(e) => onChange(e.target.value)}
disabled={disabled}
className={`
bg-white/5 border border-white/10 text-white rounded-lg
hover:border-white/30 hover:bg-white/10
focus:border-purple-400/50 focus:ring-2 focus:ring-purple-400/20
transition-all duration-200 outline-none
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:border-white/10 disabled:hover:bg-white/5
${sizeClasses[size]}
${className}
`}
>
{placeholder && (
<option value="" disabled className="bg-gray-800 text-white/60">
{placeholder}
</option>
)}
{children}
</select>
)
}