docs: создать правила для синхронизации данных, layout и статистических компонентов
- DATA_SYNCHRONIZATION_RULES.md - правила синхронизации между компонентами - GRAPHQL_CACHE_RULES.md - настройки кеширования и fetchPolicy - CSS_LAYOUT_SCROLL_RULES.md - решение проблем с overflow и scroll - STATISTICAL_COMPONENTS_RULES.md - правила Master-Detail архитектуры Документация основана на исправлениях в кабинете фулфилмента 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
489
docs/presentation-layer/CSS_LAYOUT_SCROLL_RULES.md
Normal file
489
docs/presentation-layer/CSS_LAYOUT_SCROLL_RULES.md
Normal file
@ -0,0 +1,489 @@
|
||||
# 🎨 ПРАВИЛА CSS LAYOUT И СКРОЛЛА
|
||||
|
||||
> **Цель:** Предотвратить проблемы с overflow, scroll и позиционированием в Next.js 15 + React 19 приложении
|
||||
|
||||
## 📋 **ОСНОВНЫЕ ПРИНЦИПЫ LAYOUT**
|
||||
|
||||
### 1. **БАЗОВАЯ АРХИТЕКТУРА LAYOUT**
|
||||
|
||||
```typescript
|
||||
// ✅ ПРАВИЛЬНАЯ структура для всех страниц приложения
|
||||
<div className="h-screen flex overflow-hidden"> {/* Контейнер полной высоты */}
|
||||
<Sidebar /> {/* Фиксированная боковая панель */}
|
||||
<main className={`
|
||||
flex-1 /* Занимает оставшееся место */
|
||||
${getSidebarMargin()} /* Динамический отступ */
|
||||
px-4 py-3 /* Внутренние отступы */
|
||||
flex flex-col /* Вертикальная компоновка */
|
||||
transition-all duration-300 /* Плавные анимации */
|
||||
overflow-hidden /* Предотвращение двойного скролла */
|
||||
`}>
|
||||
<div className="flex-1 overflow-y-auto space-y-6"> {/* ЕДИНСТВЕННАЯ зона скролла */}
|
||||
{/* Весь контент здесь */}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 2. **КРИТИЧЕСКИЕ ПРАВИЛА OVERFLOW**
|
||||
|
||||
#### **✅ ПРАВИЛЬНО: Один уровень overflow**
|
||||
|
||||
```css
|
||||
/* Родительский контейнер */
|
||||
.container {
|
||||
height: 100vh;
|
||||
overflow: hidden; /* Запрещаем скролл на уровне экрана */
|
||||
}
|
||||
|
||||
/* Дочерний скроллируемый контейнер */
|
||||
.scrollable-content {
|
||||
flex: 1;
|
||||
overflow-y: auto; /* ЕДИНСТВЕННАЯ зона скролла */
|
||||
}
|
||||
```
|
||||
|
||||
#### **❌ НЕПРАВИЛЬНО: Множественные overflow зоны**
|
||||
|
||||
```css
|
||||
/* Создаёт конфликты скролла */
|
||||
.parent {
|
||||
overflow-y: auto; /* Первый скролл */
|
||||
}
|
||||
.child {
|
||||
overflow-y: auto; /* Второй скролл - ПРОБЛЕМА! */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 **ТИПИЧНЫЕ ПРОБЛЕМЫ И РЕШЕНИЯ**
|
||||
|
||||
### **ПРОБЛЕМА 1: Контент смещается вправо**
|
||||
|
||||
**❌ Причина:**
|
||||
|
||||
```jsx
|
||||
<div style={{ minHeight: '200vh' }}>
|
||||
{' '}
|
||||
{/* Принудительная высота */}
|
||||
<div className="overflow-hidden">
|
||||
{' '}
|
||||
{/* Скрывает контент */}
|
||||
{/* Контент не помещается и смещается */}
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**✅ Решение:**
|
||||
|
||||
```jsx
|
||||
<div className="space-y-6">
|
||||
{' '}
|
||||
{/* Простая вертикальная компоновка */}
|
||||
{/* Контент автоматически размещается правильно */}
|
||||
</div>
|
||||
```
|
||||
|
||||
### **ПРОБЛЕМА 2: Скролл не работает**
|
||||
|
||||
**❌ Причина:**
|
||||
|
||||
```jsx
|
||||
<div className="h-screen overflow-hidden">
|
||||
{' '}
|
||||
{/* Блокирует скролл */}
|
||||
<div className="overflow-hidden">
|
||||
{' '}
|
||||
{/* Дублирует блокировку */}
|
||||
<div className="min-h-[200vh]">
|
||||
{' '}
|
||||
{/* Создаёт контент больше экрана */}
|
||||
{/* Контент не скроллится */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**✅ Решение:**
|
||||
|
||||
```jsx
|
||||
<div className="h-screen flex flex-col overflow-hidden">
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
{' '}
|
||||
{/* ЕДИНСТВЕННАЯ зона скролла */}
|
||||
{/* Контент свободно скроллится */}
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### **ПРОБЛЕМА 3: Двойной sidebar в layout**
|
||||
|
||||
**❌ Причина:**
|
||||
|
||||
```jsx
|
||||
// В page.tsx
|
||||
<div className="flex">
|
||||
<Sidebar /> {/* Первый sidebar */}
|
||||
<main>
|
||||
<div className="flex">
|
||||
<Sidebar /> {/* Второй sidebar - ДУБЛИРОВАНИЕ! */}
|
||||
<content />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
```
|
||||
|
||||
**✅ Решение:**
|
||||
|
||||
```jsx
|
||||
// В page.tsx - УБРАТЬ дублирование
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
<Sidebar /> {/* ЕДИНСТВЕННЫЙ sidebar */}
|
||||
<main className={`flex-1 ${getSidebarMargin()} overflow-hidden`}>
|
||||
<div className="flex-1 overflow-y-auto space-y-6">{/* Весь контент */}</div>
|
||||
</main>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ **АРХИТЕКТУРНЫЕ ПАТТЕРНЫ**
|
||||
|
||||
### **ПАТТЕРН 1: Dashboard с статистикой**
|
||||
|
||||
```jsx
|
||||
export function DashboardPage() {
|
||||
return (
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
<Sidebar />
|
||||
<main className={`flex-1 ${getSidebarMargin()} px-4 py-3 flex flex-col overflow-hidden`}>
|
||||
<div className="flex-1 overflow-y-auto space-y-6">
|
||||
{/* Заголовок */}
|
||||
<Header />
|
||||
|
||||
{/* Статистические карточки */}
|
||||
<StatsCards />
|
||||
|
||||
{/* Основное содержимое */}
|
||||
<MainContent />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### **ПАТТЕРН 2: Таблица с фильтрами**
|
||||
|
||||
```jsx
|
||||
export function TablePage() {
|
||||
return (
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
<Sidebar />
|
||||
<main className={`flex-1 ${getSidebarMargin()} px-4 py-3 flex flex-col overflow-hidden`}>
|
||||
<div className="flex-1 overflow-y-auto space-y-6">
|
||||
{/* Фильтры (фиксированные) */}
|
||||
<FiltersPanel />
|
||||
|
||||
{/* Таблица (скроллируемая) */}
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<DataTable />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### **ПАТТЕРН 3: Модальные окна**
|
||||
|
||||
```jsx
|
||||
// ✅ Модалки не должны влиять на основной скролл
|
||||
<Dialog>
|
||||
<div className="max-h-[80vh] overflow-y-auto">
|
||||
{' '}
|
||||
{/* Скролл только внутри модалки */}
|
||||
<ModalContent />
|
||||
</div>
|
||||
</Dialog>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📱 **RESPONSIVE DESIGN ПРАВИЛА**
|
||||
|
||||
### **АДАПТИВНЫЕ КОНТЕЙНЕРЫ**
|
||||
|
||||
```jsx
|
||||
<div
|
||||
className="
|
||||
grid
|
||||
grid-cols-1 /* Мобильные: 1 колонка */
|
||||
md:grid-cols-2 /* Планшеты: 2 колонки */
|
||||
lg:grid-cols-4 /* Десктоп: 4 колонки */
|
||||
xl:grid-cols-6 /* Большие экраны: 6 колонок */
|
||||
gap-4
|
||||
"
|
||||
>
|
||||
{/* Карточки адаптивно размещаются */}
|
||||
</div>
|
||||
```
|
||||
|
||||
### **АДАПТИВНЫЕ ОТСТУПЫ**
|
||||
|
||||
```jsx
|
||||
<main className={`
|
||||
flex-1
|
||||
${getSidebarMargin()} /* Динамический отступ для sidebar */
|
||||
px-4 py-3 /* Базовые отступы */
|
||||
lg:px-6 lg:py-4 /* Увеличенные отступы на больших экранах */
|
||||
overflow-hidden
|
||||
`}>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **СПЕЦИФИЧЕСКИЕ ПРАВИЛА ДЛЯ SFERA**
|
||||
|
||||
### **ПРАВИЛА ДЛЯ ФУЛФИЛМЕНТ КОМПОНЕНТОВ**
|
||||
|
||||
#### **1. Главная страница склада**
|
||||
|
||||
```jsx
|
||||
// src/app/fulfillment-warehouse/page.tsx
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
<Sidebar />
|
||||
<main className={`flex-1 ${getSidebarMargin()} px-4 py-3 flex flex-col overflow-hidden`}>
|
||||
<div className="flex-1 overflow-y-auto space-y-6">
|
||||
<WarehouseHeader />
|
||||
<WarehouseStats /> {/* Статистика - НЕ скроллится */}
|
||||
<WarehouseContent /> {/* Контент - скроллится */}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### **2. Таблицы поставок**
|
||||
|
||||
```jsx
|
||||
// src/components/fulfillment-warehouse/fulfillment-supplies-page.tsx
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
<Sidebar />
|
||||
<main className={`flex-1 ${getSidebarMargin()} px-4 py-3 flex flex-col overflow-hidden`}>
|
||||
<div className="flex-1 overflow-y-auto space-y-6">
|
||||
{' '}
|
||||
{/* ← КЛЮЧЕВОЙ ЭЛЕМЕНТ */}
|
||||
<SuppliesHeader /> {/* Фильтры */}
|
||||
<SuppliesStats /> {/* Статистика */}
|
||||
<SuppliesList /> {/* Основная таблица - скроллируется естественно */}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
```
|
||||
|
||||
#### **3. Раскрывающиеся детали (Master-Detail)**
|
||||
|
||||
```jsx
|
||||
// Детали поставок в раскрывающихся строках
|
||||
<tr className="border-t border-white/10">
|
||||
<td colSpan="100%" className="p-0">
|
||||
<div className="max-h-96 overflow-y-auto bg-white/5">
|
||||
{' '}
|
||||
{/* Локальный скролл */}
|
||||
<DeliveryDetails />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ **ПРОИЗВОДИТЕЛЬНОСТЬ И ОПТИМИЗАЦИЯ**
|
||||
|
||||
### **ВИРТУАЛИЗАЦИЯ ДЛЯ БОЛЬШИХ СПИСКОВ**
|
||||
|
||||
```jsx
|
||||
// Для таблиц с >100 строк
|
||||
import { FixedSizeList as List } from 'react-window'
|
||||
|
||||
;<div className="h-96 overflow-hidden">
|
||||
{' '}
|
||||
{/* Контейнер фиксированной высоты */}
|
||||
<List
|
||||
height={384} // Высота контейнера
|
||||
itemCount={items.length} // Количество элементов
|
||||
itemSize={64} // Высота каждого элемента
|
||||
className="scrollbar-thin" // Кастомный скроллбар
|
||||
>
|
||||
{({ index, style }) => (
|
||||
<div style={style}>
|
||||
<TableRow item={items[index]} />
|
||||
</div>
|
||||
)}
|
||||
</List>
|
||||
</div>
|
||||
```
|
||||
|
||||
### **LAZY LOADING ДЛЯ КОНТЕНТА**
|
||||
|
||||
```jsx
|
||||
const LazyTableSection = lazy(() => import('./TableSection'))
|
||||
|
||||
// В компоненте
|
||||
<div className="flex-1 overflow-y-auto space-y-6">
|
||||
<StatsSection /> {/* Загружается сразу */}
|
||||
<Suspense fallback={<div>Загрузка...</div>}>
|
||||
<LazyTableSection /> {/* Загружается по требованию */}
|
||||
</Suspense>
|
||||
</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 **АНТИ-ПАТТЕРНЫ И ЗАПРЕТЫ**
|
||||
|
||||
### **❌ НИКОГДА НЕ ДЕЛАЙТЕ:**
|
||||
|
||||
#### **1. Принудительные размеры**
|
||||
|
||||
```jsx
|
||||
// ❌ Создаёт проблемы с layout
|
||||
<div style={{ minHeight: '200vh' }}>
|
||||
<div className="h-[2000px]">
|
||||
```
|
||||
|
||||
#### **2. Множественные overflow зоны**
|
||||
|
||||
```jsx
|
||||
// ❌ Конфликты скролла
|
||||
<div className="overflow-y-auto">
|
||||
<div className="overflow-y-auto">
|
||||
<div className="overflow-y-auto">
|
||||
```
|
||||
|
||||
#### **3. Смешивание fixed и sticky позиционирования**
|
||||
|
||||
```jsx
|
||||
// ❌ Непредсказуемое поведение
|
||||
<div className="fixed top-0">
|
||||
<div className="sticky top-0">
|
||||
```
|
||||
|
||||
#### **4. Игнорирование responsive дизайна**
|
||||
|
||||
```jsx
|
||||
// ❌ Не адаптируется к мобильным устройствам
|
||||
<div className="grid grid-cols-6 gap-4"> {/* Сломается на мобильных */}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 **ИНСТРУМЕНТЫ ОТЛАДКИ**
|
||||
|
||||
### **CSS DEBUG КЛАССЫ**
|
||||
|
||||
```css
|
||||
/* Добавьте для визуализации проблем */
|
||||
.debug-borders * {
|
||||
border: 1px solid red !important;
|
||||
}
|
||||
|
||||
.debug-overflow {
|
||||
overflow: visible !important;
|
||||
background: rgba(255, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
.debug-scroll {
|
||||
scrollbar-color: red transparent !important;
|
||||
scrollbar-width: thick !important;
|
||||
}
|
||||
```
|
||||
|
||||
### **REACT DevTools**
|
||||
|
||||
```jsx
|
||||
// Добавьте data-атрибуты для отладки
|
||||
<div
|
||||
className="overflow-y-auto"
|
||||
data-scroll-zone="main-content"
|
||||
data-debug="scroll-container"
|
||||
>
|
||||
```
|
||||
|
||||
### **КОНСОЛЬНЫЕ ЛОГИ ДЛЯ РАЗМЕРОВ**
|
||||
|
||||
```jsx
|
||||
useEffect(() => {
|
||||
const element = ref.current
|
||||
if (element) {
|
||||
console.log('LAYOUT DEBUG:', {
|
||||
scrollHeight: element.scrollHeight,
|
||||
clientHeight: element.clientHeight,
|
||||
offsetHeight: element.offsetHeight,
|
||||
hasOverflow: element.scrollHeight > element.clientHeight,
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 **ЧЕКЛИСТ ПРОВЕРКИ LAYOUT**
|
||||
|
||||
### **Перед релизом:**
|
||||
|
||||
- [ ] Единственная зона скролла на странице
|
||||
- [ ] Нет принудительных высот (`minHeight: '200vh'`)
|
||||
- [ ] Правильная структура с `h-screen` и `overflow-hidden`
|
||||
- [ ] Responsive дизайн для мобильных устройств
|
||||
- [ ] Sidebar не дублируется в компонентах
|
||||
- [ ] Модальные окна не влияют на основной скролл
|
||||
|
||||
### **При проблемах со скроллом:**
|
||||
|
||||
- [ ] Проверить количество `overflow-y-auto` в иерархии
|
||||
- [ ] Убедиться в отсутствии `overflow-hidden` на скроллируемом контейнере
|
||||
- [ ] Проверить наличие `flex-1` у родительского контейнера
|
||||
- [ ] Убрать принудительные размеры (`min-height`, `height: 200vh`)
|
||||
|
||||
---
|
||||
|
||||
## 🎨 **КАСТОМНЫЕ СКРОЛЛБАРЫ**
|
||||
|
||||
### **TAILWIND CLASSES**
|
||||
|
||||
```jsx
|
||||
<div className="
|
||||
overflow-y-auto
|
||||
scrollbar-thin /* Тонкий скроллбар */
|
||||
scrollbar-track-transparent
|
||||
scrollbar-thumb-white/20
|
||||
hover:scrollbar-thumb-white/30
|
||||
">
|
||||
```
|
||||
|
||||
### **CUSTOM CSS**
|
||||
|
||||
```css
|
||||
/* Кастомные скроллбары для SFERA */
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
**Следование этим правилам обеспечит корректную работу layout и скролла во всех компонентах!** 🚀
|
Reference in New Issue
Block a user