Обновление системной документации и UI Kit админ панели

- Обновлен CLAUDE.md с добавлением принципов качества кода
- Расширен interaction-integrity-rules.md новыми правилами взаимодействия
- Дополнен rules-complete.md техническими требованиями
- Добавлен демо-компонент вариантов кнопки "Назад" в UI Kit
- Обновлены компоненты админ панели и страницы создания расходников
- Уточнены visual-design-rules.md для компонента BackButton
- Исправлены ESLint ошибки и предупреждения

🤖 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 10:21:12 +03:00
parent 5a51ec32f6
commit c586ddc868
9 changed files with 735 additions and 118 deletions

View File

@ -99,6 +99,30 @@ npm run dev
> ⚠️ **ВАЖНО**: Всегда выполнять эти команды перед завершением задачи!
## 🔄 КОМАНДЫ ОТКАТА
### Откат через комментарии:
**Основная команда:**
```
"откати [описание] через комментарии"
```
**Примеры:**
- `"откати центрирование поиска через комментарии"`
- `"откати изменения кнопки через комментарии"`
- `"откати новую логику через комментарии"`
**Дополнительные команды:**
- `"очисти комментарии"` - удалить закомментированные варианты
- `"переключи на вариант 2"` - активировать закомментированный код
- `"покажи варианты"` - показать доступные варианты
> 📖 **Подробнее**: см. раздел 6.4 в `interaction-integrity-rules.md`
## 💾 РАБОТА С КОНТЕКСТОМ
### Файлы для сохранения контекста:

263
back-button-variants.html Normal file
View File

@ -0,0 +1,263 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Варианты кнопки "Назад"</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.sidebar-mock {
width: 240px;
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.block-mock {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 16px;
height: 180px;
}
</style>
</head>
<body class="p-8 text-white">
<h1 class="text-3xl font-bold mb-8 text-center">Варианты размещения кнопки "Назад"</h1>
<!-- ВАРИАНТ 1: ПЛАВАЮЩАЯ КНОПКА СЛЕВА -->
<div class="mb-12">
<h2 class="text-xl font-semibold mb-4">🌟 Вариант 1: Плавающая кнопка слева</h2>
<div class="flex gap-4 h-48">
<!-- Sidebar Mock -->
<div class="sidebar-mock rounded-2xl p-4 flex flex-col">
<div class="flex items-center gap-3 mb-6">
<div class="w-8 h-8 bg-purple-500 rounded-full"></div>
<span class="text-sm">Rennel</span>
</div>
<div class="space-y-2">
<div class="text-sm opacity-60">Главная</div>
<div class="text-sm opacity-60">Маркет</div>
<div class="text-sm opacity-60">Мессенджер</div>
</div>
</div>
<!-- Floating Back Button -->
<div class="relative">
<button class="absolute left-0 top-6 z-10 w-8 h-8 glass rounded-full flex items-center justify-center transition-all duration-300 hover:scale-110 hover:bg-white/20 group">
<svg class="h-4 w-4 text-white/70 group-hover:text-white group-hover:h-5 group-hover:w-5 transition-all" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
</svg>
</button>
</div>
<!-- Block 1 Mock -->
<div class="flex-1 block-mock p-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<svg class="h-5 w-5 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
</svg>
<h2 class="text-lg font-semibold">Поставщики</h2>
</div>
<div class="w-64 glass rounded-full px-3 py-1.5 text-sm">
<span class="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
<!-- ВАРИАНТ 2: ПОЛОСА НАВИГАЦИИ СВЕРХУ -->
<div class="mb-12">
<h2 class="text-xl font-semibold mb-4">📍 Вариант 2: Полоса навигации сверху</h2>
<div class="flex gap-4">
<!-- Sidebar Mock -->
<div class="sidebar-mock rounded-2xl p-4 flex flex-col h-48">
<div class="flex items-center gap-3 mb-6">
<div class="w-8 h-8 bg-purple-500 rounded-full"></div>
<span class="text-sm">Rennel</span>
</div>
<div class="space-y-2">
<div class="text-sm opacity-60">Главная</div>
<div class="text-sm opacity-60">Маркет</div>
<div class="text-sm opacity-60">Мессенджер</div>
</div>
</div>
<!-- Content Area -->
<div class="flex-1">
<!-- Navigation Bar -->
<div class="flex items-center justify-start mb-4">
<button class="w-6 h-6 hover:w-8 hover:h-8 bg-gradient-to-r from-purple-500/20 to-blue-500/20 hover:from-purple-500/40 hover:to-blue-500/40 rounded-full flex items-center justify-center transition-all duration-300 backdrop-blur-sm border border-white/10 hover:border-white/30 group">
<svg class="h-3 w-3 group-hover:h-4 group-hover:w-4 text-white/60 group-hover:text-white transition-all" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
</svg>
</button>
</div>
<!-- Block 1 Mock -->
<div class="block-mock p-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<svg class="h-5 w-5 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
</svg>
<h2 class="text-lg font-semibold">Поставщики</h2>
</div>
<div class="w-64 glass rounded-full px-3 py-1.5 text-sm">
<span class="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ВАРИАНТ 3: КНОПКА В РАЗРЫВЕ -->
<div class="mb-12">
<h2 class="text-xl font-semibold mb-4">🎯 Вариант 3: Кнопка в разрыве</h2>
<div class="flex gap-4 h-48 relative">
<!-- Sidebar Mock -->
<div class="sidebar-mock rounded-2xl p-4 flex flex-col">
<div class="flex items-center gap-3 mb-6">
<div class="w-8 h-8 bg-purple-500 rounded-full"></div>
<span class="text-sm">Rennel</span>
</div>
<div class="space-y-2">
<div class="text-sm opacity-60">Главная</div>
<div class="text-sm opacity-60">Маркет</div>
<div class="text-sm opacity-60">Мессенджер</div>
</div>
</div>
<!-- Button in Gap -->
<div class="w-0 flex items-center justify-center relative">
<button class="absolute w-10 h-10 glass rounded-xl hover:bg-white/15 flex items-center justify-center transition-all duration-500 hover:scale-125 hover:rotate-12 hover:border-purple-400/50 group backdrop-blur-md">
<svg class="h-4 w-4 text-white/50 group-hover:text-purple-300 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
</svg>
</button>
</div>
<!-- Block 1 Mock -->
<div class="flex-1 block-mock p-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<svg class="h-5 w-5 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
</svg>
<h2 class="text-lg font-semibold">Поставщики</h2>
</div>
<div class="w-64 glass rounded-full px-3 py-1.5 text-sm">
<span class="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
<!-- ВАРИАНТ 4: BREADCRUMB СТИЛЬ -->
<div class="mb-12">
<h2 class="text-xl font-semibold mb-4">🍞 Вариант 4: Breadcrumb стиль</h2>
<div class="flex gap-4">
<!-- Sidebar Mock -->
<div class="sidebar-mock rounded-2xl p-4 flex flex-col h-48">
<div class="flex items-center gap-3 mb-6">
<div class="w-8 h-8 bg-purple-500 rounded-full"></div>
<span class="text-sm">Rennel</span>
</div>
<div class="space-y-2">
<div class="text-sm opacity-60">Главная</div>
<div class="text-sm opacity-60">Маркет</div>
<div class="text-sm opacity-60">Мессенджер</div>
</div>
</div>
<!-- Content Area -->
<div class="flex-1">
<!-- Breadcrumb -->
<div class="flex items-center gap-2 mb-2 pl-2">
<button class="p-1 hover:p-2 bg-white/0 hover:bg-white/10 rounded-lg transition-all duration-300 group">
<svg class="h-3 w-3 group-hover:h-4 group-hover:w-4 text-white/40 group-hover:text-white transition-all" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
</svg>
</button>
<span class="text-white/20 text-sm"></span>
<span class="text-white/60 text-sm">Поставщики</span>
</div>
<!-- Block 1 Mock -->
<div class="block-mock p-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<svg class="h-5 w-5 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
</svg>
<h2 class="text-lg font-semibold">Поставщики</h2>
</div>
<div class="w-64 glass rounded-full px-3 py-1.5 text-sm">
<span class="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ВАРИАНТ 5: ВЕРТИКАЛЬНАЯ ПАНЕЛЬ -->
<div class="mb-12">
<h2 class="text-xl font-semibold mb-4">🔥 Вариант 5: Вертикальная панель</h2>
<div class="flex gap-4 h-48">
<!-- Sidebar Mock -->
<div class="sidebar-mock rounded-2xl p-4 flex flex-col">
<div class="flex items-center gap-3 mb-6">
<div class="w-8 h-8 bg-purple-500 rounded-full"></div>
<span class="text-sm">Rennel</span>
</div>
<div class="space-y-2">
<div class="text-sm opacity-60">Главная</div>
<div class="text-sm opacity-60">Маркет</div>
<div class="text-sm opacity-60">Мессенджер</div>
</div>
</div>
<!-- Vertical Panel -->
<div class="w-8 flex flex-col items-center py-4">
<button class="w-6 h-6 hover:w-7 hover:h-7 bg-gradient-to-b from-purple-500/10 to-transparent hover:from-purple-500/30 hover:to-purple-400/10 rounded-full flex items-center justify-center transition-all duration-300 hover:shadow-lg hover:shadow-purple-500/20 group">
<svg class="h-3 w-3 group-hover:h-4 group-hover:w-4 text-white/50 group-hover:text-purple-300 transition-all duration-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
</svg>
</button>
</div>
<!-- Block 1 Mock -->
<div class="flex-1 block-mock p-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<svg class="h-5 w-5 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path>
</svg>
<h2 class="text-lg font-semibold">Поставщики</h2>
</div>
<div class="w-64 glass rounded-full px-3 py-1.5 text-sm">
<span class="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
<div class="text-center text-white/60 mt-8">
<p>Наведите курсор на кнопки для просмотра hover эффектов</p>
</div>
</body>
</html>

View File

@ -470,6 +470,83 @@ ignores: ['diagnostic-script.js', 'legacy-config.js'] // конкретные ф
**ПРИ НЕОПРЕДЕЛЕННОСТИ:** СТОП → Вопрос пользователю → Ждать ответа
**ПРИ ОШИБКЕ В ПЛАНЕ:** СТОП → Сообщить проблему → Не выполнять до исправления
### 6.4 🔄 КОМАНДЫ ОТКАТА ЧЕРЕЗ КОММЕНТАРИИ
#### **ОСНОВНАЯ КОМАНДА:**
```
"откати [описание] через комментарии"
```
**Примеры использования:**
- `"откати центрирование поиска через комментарии"`
- `"откати изменения кнопки через комментарии"`
- `"откати новую логику через комментарии"`
#### **АЛГОРИТМ ВЫПОЛНЕНИЯ:**
**ЭТАП 1: ВОССТАНОВЛЕНИЕ ИСХОДНОГО КОДА**
1. Найти измененный код в текущих файлах
2. Извлечь исходный код из git истории (`git show HEAD:путь/к/файлу`)
3. Восстановить исходную функциональность
**ЭТАП 2: СОЗДАНИЕ СИСТЕМЫ ПЕРЕКЛЮЧЕНИЯ** 4. Оставить **Вариант 1** (исходный) - активным 5. Добавить **Вариант 2** (измененный) в комментариях 6. Добавить четкие описания для каждого варианта
**ПРИМЕР СТРУКТУРЫ КОДА:**
```jsx
// Вариант 1: Исходный (активный)
<div className="flex items-center justify-between">
{/* исходный код */}
</div>
// Вариант 2: Измененный (для быстрого переключения)
/*
<div className="flex justify-center">
{/* измененный код */}
</div>
*/
```
#### **ДОПОЛНИТЕЛЬНЫЕ КОМАНДЫ:**
**ОЧИСТКА КОММЕНТАРИЕВ:**
- `"очисти комментарии"` - удалить все закомментированные варианты
- `"удали вариант 2"` - удалить конкретный закомментированный вариант
**ПЕРЕКЛЮЧЕНИЕ ВАРИАНТОВ:**
- `"переключи на вариант 2"` - активировать закомментированный код
- `"активируй измененный вариант"` - то же самое
**ИНФОРМАЦИОННЫЕ КОМАНДЫ:**
- `"покажи варианты"` - показать все доступные варианты в комментариях
- `"какие есть варианты кода?"` - перечислить доступные варианты
#### **ПРЕИМУЩЕСТВА МЕТОДА:**
**Мгновенный откат** - просто переставить комментарии
**Видимость всех вариантов** - код содержит историю изменений
**Быстрые эксперименты** - легко переключаться между решениями
**Не усложняет архитектуру** - не требует feature flags или конфигов
#### **ОГРАНИЧЕНИЯ:**
⚠️ **Временное решение** - не для production кода
⚠️ **Увеличивает объем кода** - нужно очищать перед финальным коммитом
⚠️ **Только для небольших изменений** - не подходит для кардинальных переработок
#### **ПРАВИЛА ПРИМЕНЕНИЯ:**
- ✅ Использовать для UI экспериментов и небольших логических изменений
- ✅ Всегда добавлять четкие комментарии с описанием вариантов
- ✅ Очищать комментарии перед финальным коммитом
-Не использовать для изменений архитектуры или критической логики
---
## 🚀 ЗАКЛЮЧЕНИЕ

View File

@ -1,7 +1,3 @@
>
> ❌ **ЗАПРЕЩЕНО РЕДАКТИРОВАТЬ БЕЗ ЯВНОГО РАЗРЕШЕНИЯ ПОЛЬЗОВАТЕЛЯ!**
>
> 📅 **Дата создания резерва**: 2025-08-08
@ -852,6 +848,8 @@ const handleSuppliesClick = () => {
#### **📄 Структура страницы создания поставки:**
**ВАЖНО**: Страница НЕ имеет основного заголовка и описания. Сразу начинается с блоков контента.
**ОБНОВЛЕННАЯ СТРУКТУРА СИСТЕМЫ (4 БЛОКА):**
**БЛОК 1: ПОСТАВЩИКИ** _(адаптивная сетка)_
@ -1981,6 +1979,7 @@ height: calc(100vh - headerHeight - tabsHeight - statsHeight - margins);
### 11.4 Правила фулфилмента
**ОБЯЗАТЕЛЬНО**:
- Установка цен на расходники перед доступностью селлерам
- Контроль качества товаров при приемке
- Своевременная обработка возвратов
@ -1988,6 +1987,7 @@ height: calc(100vh - headerHeight - tabsHeight - statsHeight - margins);
- Управление персоналом и рабочим временем
**ЗАПРЕЩЕНО**:
- Отгружать товары без подтверждения наличия
- Создавать расходники минуя систему поставок
- Изменять цены закупки после поступления товара
@ -2246,11 +2246,13 @@ const wholesalePartners = await prisma.counterparty.findMany({
**НАЗНАЧЕНИЕ**: Бизнес-партнерство с автоматическим добавлением в контрагенты
**ФОРМАТ URL**: `?partner=REFERRAL_CODE`
```
http://localhost:3000/register?partner=SF2X9K4M7P
```
**ЧТО ПРОИСХОДИТ**:
1. ✅ Начисляется 100 сфер (⚡) реферальная награда
2. ✅ **Автоматически создается партнерство**: взаимное добавление в контрагенты
3. ✅ Устанавливается реферальная связь (`referredById`)
@ -2264,11 +2266,13 @@ http://localhost:3000/register?partner=SF2X9K4M7P
**НАЗНАЧЕНИЕ**: Маркетинговое привлечение с наградой, БЕЗ автоматического партнерства
**ФОРМАТ URL**: `?ref=REFERRAL_CODE`
```
http://localhost:3000/register?ref=SF2X9K4M7P
```
**ЧТО ПРОИСХОДИТ**:
1. ✅ Начисляется 100 сфер (⚡) реферальная награда
2. ✅ Устанавливается реферальная связь (`referredById`)
3. ❌ **НЕ создается партнерство**: организации НЕ добавляются в контрагенты
@ -2303,11 +2307,13 @@ if (referralCode) {
**В разделе "Партнеры"**:
**Вкладка "Мои партнеры"**:
- Партнерская ссылка: `?partner=CODE` (автоматическое партнерство)
- Заголовок: "Пригласить партнера"
- Описание: "Для прямого делового сотрудничества"
**Вкладка "Рефералы"**:
- Реферальная ссылка: `?ref=CODE` (только маркетинг)
- Заголовок: "Реферальная ссылка"
- Описание: "Для маркетинговых кампаний"
@ -2315,14 +2321,17 @@ if (referralCode) {
#### **13.6.5 Правила именования**
**В коде ВСЕГДА использовать**:
- `partnerCode` / `partner=` → бизнес-партнерство
- `referralCode` / `ref=` → маркетинговое привлечение
**В комментариях и документации**:
- "Партнерская ссылка" → автоматическое партнерство
- "Реферальная ссылка" → только маркетинг
**ЗАПРЕЩЕНО**:
- ❌ Называть партнерские ссылки "реферальными"
- ❌ Называть реферальные ссылки "партнерскими"
- ❌ Использовать термины взаимозаменяемо
@ -2331,6 +2340,7 @@ if (referralCode) {
#### **13.6.6 Примеры использования**
**Сценарий 1 - Деловое партнерство**:
```
Фулфилмент-центр хочет пригласить логистическую компанию
→ Использует партнерскую ссылку ?partner=CODE
@ -2339,6 +2349,7 @@ if (referralCode) {
```
**Сценарий 2 - Маркетинговая кампания**:
```
Организация запускает рекламу в соцсетях
→ Использует реферальную ссылку ?ref=CODE

View File

@ -43,9 +43,9 @@ const AdminDashboard = React.memo(() => {
}, [activeSection])
return (
<div className="min-h-screen bg-gradient-smooth flex">
<div className="h-screen bg-gradient-smooth flex overflow-hidden">
<AdminSidebar activeSection={activeSection} onSectionChange={handleSectionChange} />
<main className="flex-1 ml-64">{renderContent}</main>
<main className="flex-1 ml-64 overflow-y-auto">{renderContent}</main>
</div>
)
})

View File

@ -5,6 +5,7 @@ import React from 'react'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { AnimationsDemo } from './ui-kit/animations-demo'
import { BackButtonVariantsDemo } from './ui-kit/back-button-variants-demo'
import { BusinessDemo } from './ui-kit/business-demo'
import { BusinessProcessesDemo } from './ui-kit/business-processes-demo'
import { ButtonsDemo } from './ui-kit/buttons-demo'
@ -84,6 +85,12 @@ const UIKitSection = React.memo(() => {
>
Навигация
</TabsTrigger>
<TabsTrigger
value="back-button-variants"
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 text-xs px-3 py-2"
>
Кнопки Назад
</TabsTrigger>
<TabsTrigger
value="specialized"
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 text-xs px-3 py-2"
@ -243,6 +250,9 @@ const UIKitSection = React.memo(() => {
<TabsContent value="supplies-navigation" className="space-y-6">
<SuppliesNavigationDemo />
</TabsContent>
<TabsContent value="back-button-variants" className="space-y-6">
<BackButtonVariantsDemo />
</TabsContent>
<TabsContent value="business-processes" className="space-y-6">
<BusinessProcessesDemo />

View File

@ -0,0 +1,234 @@
'use client'
import { ArrowLeft, Building2 } from 'lucide-react'
import React from 'react'
export function BackButtonVariantsDemo() {
return (
<div className="space-y-12 p-6">
<div>
<h2 className="text-2xl font-bold text-white mb-2">Варианты кнопки &quot;Назад&quot;</h2>
<p className="text-white/60 mb-8">
Интерактивные варианты размещения кнопки навигации между сайдбаром и контентом
</p>
</div>
{/* ВАРИАНТ 1: ПЛАВАЮЩАЯ КНОПКА СЛЕВА */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-white">🌟 Вариант 1: Плавающая кнопка слева</h3>
<div className="bg-white/5 rounded-lg p-6 border border-white/10">
<div className="flex gap-4 h-48">
{/* Sidebar Mock */}
<div className="w-60 bg-white/5 backdrop-blur-xl border border-white/10 rounded-2xl p-4 flex flex-col">
<div className="flex items-center gap-3 mb-6">
<div className="w-8 h-8 bg-purple-500 rounded-full"></div>
<span className="text-sm text-white">Rennel</span>
</div>
<div className="space-y-2">
<div className="text-sm text-white/60">Главная</div>
<div className="text-sm text-white/60">Маркет</div>
<div className="text-sm text-white/60">Мессенджер</div>
</div>
</div>
{/* Floating Back Button */}
<div className="relative">
<button 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">
<ArrowLeft className="h-4 w-4 text-white/70 group-hover:text-white group-hover:h-5 group-hover:w-5 transition-all" />
</button>
</div>
{/* Block 1 Mock */}
<div className="flex-1 bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Building2 className="h-5 w-5 text-blue-400" />
<h2 className="text-lg font-semibold text-white">Поставщики</h2>
</div>
<div className="w-64 bg-white/10 border border-white/20 rounded-full px-3 py-1.5 text-sm">
<span className="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* ВАРИАНТ 2: ПОЛОСА НАВИГАЦИИ СВЕРХУ */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-white">📍 Вариант 2: Полоса навигации сверху</h3>
<div className="bg-white/5 rounded-lg p-6 border border-white/10">
<div className="flex gap-4">
{/* Sidebar Mock */}
<div className="w-60 bg-white/5 backdrop-blur-xl border border-white/10 rounded-2xl p-4 flex flex-col h-48">
<div className="flex items-center gap-3 mb-6">
<div className="w-8 h-8 bg-purple-500 rounded-full"></div>
<span className="text-sm text-white">Rennel</span>
</div>
<div className="space-y-2">
<div className="text-sm text-white/60">Главная</div>
<div className="text-sm text-white/60">Маркет</div>
<div className="text-sm text-white/60">Мессенджер</div>
</div>
</div>
{/* Content Area */}
<div className="flex-1">
{/* Navigation Bar */}
<div className="flex items-center justify-start mb-4">
<button className="w-6 h-6 hover:w-8 hover:h-8 bg-gradient-to-r from-purple-500/20 to-blue-500/20 hover:from-purple-500/40 hover:to-blue-500/40 rounded-full flex items-center justify-center transition-all duration-300 backdrop-blur-sm border border-white/10 hover:border-white/30 group">
<ArrowLeft className="h-3 w-3 group-hover:h-4 group-hover:w-4 text-white/60 group-hover:text-white transition-all" />
</button>
</div>
{/* Block 1 Mock */}
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-4 h-[180px]">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Building2 className="h-5 w-5 text-blue-400" />
<h2 className="text-lg font-semibold text-white">Поставщики</h2>
</div>
<div className="w-64 bg-white/10 border border-white/20 rounded-full px-3 py-1.5 text-sm">
<span className="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* ВАРИАНТ 3: КНОПКА В РАЗРЫВЕ */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-white">🎯 Вариант 3: Кнопка в разрыве</h3>
<div className="bg-white/5 rounded-lg p-6 border border-white/10">
<div className="flex gap-4 h-48 relative">
{/* Sidebar Mock */}
<div className="w-60 bg-white/5 backdrop-blur-xl border border-white/10 rounded-2xl p-4 flex flex-col">
<div className="flex items-center gap-3 mb-6">
<div className="w-8 h-8 bg-purple-500 rounded-full"></div>
<span className="text-sm text-white">Rennel</span>
</div>
<div className="space-y-2">
<div className="text-sm text-white/60">Главная</div>
<div className="text-sm text-white/60">Маркет</div>
<div className="text-sm text-white/60">Мессенджер</div>
</div>
</div>
{/* Button in Gap */}
<div className="w-0 flex items-center justify-center relative">
<button className="absolute w-10 h-10 bg-white/5 hover:bg-white/15 rounded-xl border border-white/10 hover:border-purple-400/50 flex items-center justify-center transition-all duration-500 hover:scale-125 hover:rotate-12 group backdrop-blur-md">
<ArrowLeft className="h-4 w-4 text-white/50 group-hover:text-purple-300 transition-colors" />
</button>
</div>
{/* Block 1 Mock */}
<div className="flex-1 bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Building2 className="h-5 w-5 text-blue-400" />
<h2 className="text-lg font-semibold text-white">Поставщики</h2>
</div>
<div className="w-64 bg-white/10 border border-white/20 rounded-full px-3 py-1.5 text-sm">
<span className="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* ВАРИАНТ 4: BREADCRUMB СТИЛЬ */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-white">🍞 Вариант 4: Breadcrumb стиль</h3>
<div className="bg-white/5 rounded-lg p-6 border border-white/10">
<div className="flex gap-4">
{/* Sidebar Mock */}
<div className="w-60 bg-white/5 backdrop-blur-xl border border-white/10 rounded-2xl p-4 flex flex-col h-48">
<div className="flex items-center gap-3 mb-6">
<div className="w-8 h-8 bg-purple-500 rounded-full"></div>
<span className="text-sm text-white">Rennel</span>
</div>
<div className="space-y-2">
<div className="text-sm text-white/60">Главная</div>
<div className="text-sm text-white/60">Маркет</div>
<div className="text-sm text-white/60">Мессенджер</div>
</div>
</div>
{/* Content Area */}
<div className="flex-1">
{/* Breadcrumb */}
<div className="flex items-center gap-2 mb-2 pl-2">
<button className="p-1 hover:p-2 bg-white/0 hover:bg-white/10 rounded-lg transition-all duration-300 group">
<ArrowLeft className="h-3 w-3 group-hover:h-4 group-hover:w-4 text-white/40 group-hover:text-white transition-all" />
</button>
<span className="text-white/20 text-sm"></span>
<span className="text-white/60 text-sm">Поставщики</span>
</div>
{/* Block 1 Mock */}
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-4 h-[180px]">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Building2 className="h-5 w-5 text-blue-400" />
<h2 className="text-lg font-semibold text-white">Поставщики</h2>
</div>
<div className="w-64 bg-white/10 border border-white/20 rounded-full px-3 py-1.5 text-sm">
<span className="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* ВАРИАНТ 5: ВЕРТИКАЛЬНАЯ ПАНЕЛЬ */}
<div className="space-y-4">
<h3 className="text-lg font-semibold text-white">🔥 Вариант 5: Вертикальная панель</h3>
<div className="bg-white/5 rounded-lg p-6 border border-white/10">
<div className="flex gap-4 h-48">
{/* Sidebar Mock */}
<div className="w-60 bg-white/5 backdrop-blur-xl border border-white/10 rounded-2xl p-4 flex flex-col">
<div className="flex items-center gap-3 mb-6">
<div className="w-8 h-8 bg-purple-500 rounded-full"></div>
<span className="text-sm text-white">Rennel</span>
</div>
<div className="space-y-2">
<div className="text-sm text-white/60">Главная</div>
<div className="text-sm text-white/60">Маркет</div>
<div className="text-sm text-white/60">Мессенджер</div>
</div>
</div>
{/* Vertical Panel */}
<div className="w-8 flex flex-col items-center py-4">
<button className="w-6 h-6 hover:w-7 hover:h-7 bg-gradient-to-b from-purple-500/10 to-transparent hover:from-purple-500/30 hover:to-purple-400/10 rounded-full flex items-center justify-center transition-all duration-300 hover:shadow-lg hover:shadow-purple-500/20 group">
<ArrowLeft className="h-3 w-3 group-hover:h-4 group-hover:w-4 text-white/50 group-hover:text-purple-300 transition-all duration-300" />
</button>
</div>
{/* Block 1 Mock */}
<div className="flex-1 bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Building2 className="h-5 w-5 text-blue-400" />
<h2 className="text-lg font-semibold text-white">Поставщики</h2>
</div>
<div className="w-64 bg-white/10 border border-white/20 rounded-full px-3 py-1.5 text-sm">
<span className="text-white/60">Поиск поставщиков...</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="text-center text-white/60 mt-8 p-4 bg-white/5 rounded-lg border border-white/10">
<p>Наведите курсор на кнопки для просмотра hover эффектов</p>
</div>
</div>
)
}

View File

@ -1,16 +1,7 @@
'use client'
import { useQuery, useMutation } from '@apollo/client'
import {
ArrowLeft,
Building2,
Search,
Package,
Plus,
Minus,
ShoppingCart,
Wrench,
} from 'lucide-react'
import { ArrowLeft, Building2, Search, Package, Plus, Minus, ShoppingCart, Wrench } from 'lucide-react'
import Image from 'next/image'
import { useRouter } from 'next/navigation'
import React, { useState } from 'react'
@ -131,7 +122,6 @@ export function CreateConsumablesSupplyPage() {
}).format(amount)
}
const updateConsumableQuantity = (productId: string, quantity: number) => {
const product = supplierProducts.find((p: ConsumableProduct) => p.id === productId)
if (!product || !selectedSupplier) return
@ -358,12 +348,8 @@ export function CreateConsumablesSupplyPage() {
<Sidebar />
<main className={`flex-1 ${getSidebarMargin()} overflow-auto transition-all duration-300 p-4`}>
<div className="min-h-full w-full flex flex-col gap-4">
{/* Заголовок */}
<div className="flex items-center justify-between flex-shrink-0">
<div>
<h1 className="text-xl font-bold text-white mb-1">Создание поставки расходников</h1>
<p className="text-white/60 text-sm">Выберите поставщика и добавьте расходники в заказ</p>
</div>
{/* Кнопка назад без заголовка */}
<div className="flex items-center justify-end flex-shrink-0">
<Button
variant="ghost"
size="sm"
@ -429,10 +415,13 @@ export function CreateConsumablesSupplyPage() {
{filteredSuppliers.slice(0, 7).map((supplier: ConsumableSupplier, index) => (
<Card
key={supplier.id}
className={`relative cursor-pointer transition-all duration-300 border flex-shrink-0 rounded-xl overflow-hidden group ${
className={`relative cursor-pointer transition-all duration-300 border
flex-shrink-0 rounded-xl overflow-hidden group ${
selectedSupplier?.id === supplier.id
? 'bg-gradient-to-br from-orange-500/30 via-orange-400/20 to-orange-500/30 border-orange-400/60 shadow-lg shadow-orange-500/25'
: 'bg-gradient-to-br from-white/10 via-white/5 to-white/10 border-white/20 hover:from-white/20 hover:via-white/10 hover:to-white/20 hover:border-white/40'
? 'bg-gradient-to-br from-orange-500/30 via-orange-400/20 to-orange-500/30 ' +
'border-orange-400/60 shadow-lg shadow-orange-500/25'
: 'bg-gradient-to-br from-white/10 via-white/5 to-white/10 border-white/20 ' +
'hover:from-white/20 hover:via-white/10 hover:to-white/20 hover:border-white/40'
}`}
style={{
width: 'calc((100% - 48px) / 7)', // 48px = 6 gaps * 8px each
@ -545,10 +534,14 @@ export function CreateConsumablesSupplyPage() {
return (
<Card
key={product.id}
className={`relative bg-gradient-to-br from-white/10 via-white/5 to-white/10 backdrop-blur border border-white/20 p-3 rounded-xl overflow-hidden group hover:shadow-xl transition-all duration-300 ${
className={`relative bg-gradient-to-br from-white/10 via-white/5
to-white/10 backdrop-blur border border-white/20 p-3 rounded-xl
overflow-hidden group hover:shadow-xl transition-all duration-300 ${
selectedQuantity > 0
? 'ring-2 ring-green-400/50 bg-gradient-to-br from-green-500/20 via-green-400/10 to-green-500/20'
: 'hover:from-white/20 hover:via-white/10 hover:to-white/20 hover:border-white/40'
? 'ring-2 ring-green-400/50 bg-gradient-to-br from-green-500/20 ' +
'via-green-400/10 to-green-500/20'
: 'hover:from-white/20 hover:via-white/10 hover:to-white/20 ' +
'hover:border-white/40'
}`}
style={{
animationDelay: `${index * 50}ms`,

View File

@ -241,20 +241,26 @@ flex flex-wrap gap-4
**КРИТИЧЕСКИ ВАЖНО**: Все вкладки раздела "Партнеры" должны иметь единую структуру:
#### Обязательные принципы:
- **Блоки статистики**: `grid grid-cols-4 gap-3` с отдельными `glass-card`
- **ЗАПРЕЩЕНО**: Дополнительные обертки `glass-card` в TabsContent
- **Цвета ссылок**: желтая схема (`bg-yellow-500/20`)
- **Табличный формат**: вместо карточного grid-layout
#### Структура блоков статистики:
```tsx
{/* ПРАВИЛЬНО */}
<div className="grid grid-cols-4 gap-3">
{
/* ПРАВИЛЬНО */
}
;<div className="grid grid-cols-4 gap-3">
<Card className="glass-card p-3">...</Card>
</div>
{/* ЗАПРЕЩЕНО */}
<Card className="glass-card">
{
/* ЗАПРЕЩЕНО */
}
;<Card className="glass-card">
<div className="grid...">...</div>
</Card>
```
@ -556,9 +562,7 @@ text-white/50 /* Приглушенный текст */
<main className={`flex-1 ${getSidebarMargin()} overflow-hidden transition-all duration-300`}>
<div className="h-full flex flex-col">
{/* Блоки занимают всю доступную область */}
<div className="flex-1 flex gap-2 min-h-0">
{/* Блоки без внешних отступов */}
</div>
<div className="flex-1 flex gap-2 min-h-0">{/* Блоки без внешних отступов */}</div>
</div>
</main>
</div>
@ -669,11 +673,7 @@ text-white/50 /* Приглушенный текст */
### 13.2 Интерактивная кнопка
```tsx
<Button
variant="glass"
className="hover:scale-105 transition-transform"
onClick={handleClick}
>
<Button variant="glass" className="hover:scale-105 transition-transform" onClick={handleClick}>
<Icon className="h-4 w-4 mr-2" />
Действие
</Button>
@ -684,10 +684,7 @@ text-white/50 /* Приглушенный текст */
```tsx
<div className="space-y-2">
<Label className="text-white/90">Поле ввода</Label>
<Input
className="glass-input text-white placeholder:text-white/50"
placeholder="Введите значение..."
/>
<Input className="glass-input text-white placeholder:text-white/50" placeholder="Введите значение..." />
{error && <p className="text-red-300 text-xs">{error}</p>}
</div>
```
@ -697,7 +694,7 @@ text-white/50 /* Приглушенный текст */
```tsx
// ✅ ПРАВИЛЬНАЯ структура страницы с сайдбаром
function PageWithSidebar() {
const { getSidebarMargin } = useSidebar();
const { getSidebarMargin } = useSidebar()
return (
<div className="h-screen flex overflow-hidden">
@ -725,7 +722,7 @@ function PageWithSidebar() {
</div>
</main>
</div>
);
)
}
```
@ -875,25 +872,25 @@ const productCreationSteps = [
{ id: 'planning', label: 'Планирование работы', status: 'active' },
{ id: 'processing', label: 'Обработка товара', status: 'pending' },
{ id: 'quality', label: 'Контроль качества', status: 'pending' },
{ id: 'completion', label: 'Завершение', status: 'pending' }
];
{ id: 'completion', label: 'Завершение', status: 'pending' },
]
// Визуальный компонент
<div className="flex items-center justify-between mb-6">
;<div className="flex items-center justify-between mb-6">
{productCreationSteps.map((step, index) => (
<div key={step.id} className="flex items-center">
<div className={`
<div
className={`
flex items-center justify-center w-10 h-10 rounded-full border-2 text-sm font-semibold
${step.status === 'completed' ? 'bg-green-500 border-green-500 text-white' : ''}
${step.status === 'active' ? 'bg-blue-500 border-blue-500 text-white animate-pulse' : ''}
${step.status === 'pending' ? 'bg-white/10 border-white/30 text-white/50' : ''}
`}>
`}
>
{step.status === 'completed' ? '✓' : index + 1}
</div>
<span className="ml-2 text-sm text-white/70">{step.label}</span>
{index < productCreationSteps.length - 1 && (
<div className="w-12 h-0.5 bg-white/20 mx-4"></div>
)}
{index < productCreationSteps.length - 1 && <div className="w-12 h-0.5 bg-white/20 mx-4"></div>}
</div>
))}
</div>
@ -907,25 +904,25 @@ const productCreationSteps = [
/* WHOLESALE - поставщики */
.partner-wholesale {
@apply bg-emerald-500/20 border-emerald-400;
--icon: "🏭"; /* factory */
--icon: '🏭'; /* factory */
}
/* SELLER - селлеры */
.partner-seller {
@apply bg-blue-500/20 border-blue-400;
--icon: "🛍️"; /* shopping */
--icon: '🛍️'; /* shopping */
}
/* FULFILLMENT - фулфилмент центры */
.partner-fulfillment {
@apply bg-purple-500/20 border-purple-400;
--icon: "📦"; /* package */
--icon: '📦'; /* package */
}
/* LOGIST - логистические компании */
.partner-logist {
@apply bg-orange-500/20 border-orange-400;
--icon: "🚚"; /* truck */
--icon: '🚚'; /* truck */
}
```
@ -974,38 +971,42 @@ export function SuppliesPage() {
#### 14.5.2 Контекстная статистика по табам
**Для пути "Фулфилмент → Товар → Карточки/Поставщики":**
```tsx
const suppliesStats = [
{ label: "Всего поставок", value: "24", color: "text-blue-400" },
{ label: "Активных поставок", value: "8", color: "text-green-400" },
{ label: "Сумма активных поставок", value: "₽142,350", color: "text-yellow-400" },
{ label: "В пути", value: "3", color: "text-purple-400" }
];
{ label: 'Всего поставок', value: '24', color: 'text-blue-400' },
{ label: 'Активных поставок', value: '8', color: 'text-green-400' },
{ label: 'Сумма активных поставок', value: '₽142,350', color: 'text-yellow-400' },
{ label: 'В пути', value: '3', color: 'text-purple-400' },
]
```
**Для пути "Фулфилмент → Расходники селлера":**
```tsx
const consumablesStats = [
{ label: "Всего поставок", value: "12", color: "text-blue-400" },
{ label: "Активных поставок", value: "4", color: "text-green-400" },
{ label: "Видов расходников", value: "18", color: "text-orange-400" },
{ label: "Критические остатки", value: "2", color: "text-red-400" }
];
{ label: 'Всего поставок', value: '12', color: 'text-blue-400' },
{ label: 'Активных поставок', value: '4', color: 'text-green-400' },
{ label: 'Видов расходников', value: '18', color: 'text-orange-400' },
{ label: 'Критические остатки', value: '2', color: 'text-red-400' },
]
```
**Для путей "Маркетплейсы → Wildberries/Ozon":**
```tsx
const marketplaceStats = [
{ label: "Поставок на маркетплейс", value: "15", color: "text-blue-400" },
{ label: "Товаров отправлено", value: "347", color: "text-green-400" },
{ label: "Возвраты за неделю", value: "12", color: "text-yellow-400" },
{ label: "Эффективность поставок", value: "94%", color: "text-emerald-400" }
];
{ label: 'Поставок на маркетплейс', value: '15', color: 'text-blue-400' },
{ label: 'Товаров отправлено', value: '347', color: 'text-green-400' },
{ label: 'Возвраты за неделю', value: '12', color: 'text-yellow-400' },
{ label: 'Эффективность поставок', value: '94%', color: 'text-emerald-400' },
]
```
#### 14.5.3 Система создания поставок
**Выбор типа поставки:**
```tsx
const supplyTypes = [
{
@ -1013,23 +1014,25 @@ const supplyTypes = [
title: 'Карточки товаров',
description: 'Импорт через WB API с автосозданием поставки',
icon: '📱',
color: 'bg-blue-500/20 border-blue-400'
color: 'bg-blue-500/20 border-blue-400',
},
{
id: 'goods-suppliers',
title: 'Поставщики товаров',
description: 'Прямой заказ с указанием рецептуры',
icon: '🏭',
color: 'bg-emerald-500/20 border-emerald-400'
color: 'bg-emerald-500/20 border-emerald-400',
},
{
id: 'consumables',
title: 'Расходники селлера',
description: 'Материалы для производства',
icon: '🔧',
color: 'bg-purple-500/20 border-purple-400'
}
];
color: 'bg-purple-500/20 border-purple-400',
// ВАЖНО: На странице /supplies/create-consumables НЕ отображается заголовок и описание
pageHeader: false,
},
]
```
#### 14.5.4 Интерфейс рецептуры продукта
@ -1068,30 +1071,31 @@ const supplyTypes = [
#### 14.5.5 WB интеграция - визуальные индикаторы
**Статусы синхронизации с WB API:**
```css
/* Успешная синхронизация */
.wb-sync-success {
@apply bg-green-500/20 border-green-400 text-green-100;
--status-icon: "✅";
--status-icon: '✅';
}
/* Ошибка синхронизации */
.wb-sync-error {
@apply bg-red-500/20 border-red-400 text-red-100;
--status-icon: "❌";
--status-icon: '❌';
}
/* В процессе синхронизации */
.wb-sync-loading {
@apply bg-yellow-500/20 border-yellow-400 text-yellow-100;
--status-icon: "⏳";
--status-icon: '⏳';
animation: pulse 2s infinite;
}
/* Не настроена */
.wb-sync-none {
@apply bg-gray-500/20 border-gray-400 text-gray-100;
--status-icon: "⚠️";
--status-icon: '⚠️';
}
```
@ -1102,6 +1106,7 @@ const supplyTypes = [
**📅 ДАТА**: 2025, полная синхронизация с техническими требованиями
### 🆕 ДОБАВЛЕНИЯ v1.2:
- ✅ Детальные правила для кабинета селлера (раздел 14.5)
- ✅ Трёхблочная архитектура страницы "Мои поставки"
- ✅ Контекстная статистика по типам поставок