Corp/docs/reports/SCSS_REORGANIZATION_PLAN.md

42 KiB
Raw Blame History

План реорганизации SCSS архитектуры

Дата: 15 января 2026
Статус: 📋 План
Приоритет: HIGH
Время выполнения: 6-8 часов (с Bootstrap) / 40-60 часов (без Bootstrap)

🎯 Цель

Преобразовать хаотичную структуру в чистую, поддерживаемую архитектуру с четкой категоризацией и переиспользуемыми компонентами.

⚠️ КРИТИЧЕСКОЕ РЕШЕНИЕ: Bootstrap или нет?

Пользователь запросил: Полный отказ от Bootstrap в пользу собственных стилей.

Это означает:

  • ❌ Удалить зависимость от Bootstrap (~301 KB CSS)
  • ✅ Написать свою систему: Grid, Buttons, Forms, Modals, Cards, Utilities
  • ⏱️ Увеличение времени реализации с 8 часов до 40-60 часов
  • 🎨 Полный контроль над кодом и стилями
  • 📦 Уменьшение итогового размера бандла
  • 🔧 Необходимость поддержки своего UI Kit

См. раздел "БОНУСНЫЙ ЭТАП: Отказ от Bootstrap" в конце документа.


📊 Целевая архитектура

Feature-based структура (подходит под Django структуру):

scss/
├── abstracts/                  # ✅ Оставить как есть
│   ├── _variables.scss         # SCSS переменные
│   ├── _css-variables.scss     # CSS custom properties
│   ├── _mixins.scss            # Миксины
│   └── _index.scss             # Экспорт
│
├── core/                       # ⭐ НОВАЯ ПАПКА - UI Kit
│   ├── _buttons.scss           # Кнопки
│   ├── _forms.scss             # Формы и инпуты
│   ├── _badges.scss            # Один badge компонент (объединить 2)
│   ├── _cards.scss             # Карточки
│   ├── _lists.scss             # ОДИН базовый список
│   ├── _modals.scss            # ОДИН modal (объединить 2)
│   ├── _avatars.scss           # Аватары
│   ├── _search.scss            # Поиск (вместо ios-search)
│   └── _comments.scss          # Комментарии
│
├── layout/                     # Структура приложения
│   ├── _grid.scss              # App grid (из base-app.scss)
│   ├── _header.scss            # Navbar + page-header (объединить)
│   ├── _sidebar.scss           # ✅ Оставить
│   └── _rightbar.scss          # Rightbar + calendar (объединить)
│
├── features/                   # ⭐ НОВАЯ ПАПКА - Feature-specific
│   ├── feed/
│   │   ├── _layout.scss        # Feed layout
│   │   ├── _post-card.scss     # Карточка поста
│   │   └── _post-form.scss     # ✅ Переместить
│   ├── requests/
│   │   ├── _list.scss          # Список заявок
│   │   ├── _detail.scss        # Детали заявки
│   │   └── _picker.scss        # Recipient picker
│   ├── documents/
│   │   └── _list.scss          # Список документов
│   ├── employees/
│   │   ├── _controls.scss      # Department controls
│   │   └── _team-viz.scss      # Team visualization (team-wheel)
│   ├── notifications/
│   │   └── _center.scss        # Notification center
│   └── chat/                   # ✅ Оставить подпапку
│       └── ...                 # 10 файлов как есть
│
└── utilities/                  # Utility классы
    └── _spacing.scss           # Объединить spacing-utils + layout-spacing

📋 Этапы выполнения

Этап 0: Подготовка (30 мин)

0.1 Создать backup

cd backend/static
cp -r scss scss_backup_$(date +%Y%m%d)
git add -A
git commit -m "backup: SCSS before reorganization"

0.2 Создать новые папки

cd scss
mkdir -p core features utilities
mkdir -p features/{feed,requests,documents,employees,notifications}

0.3 Создать tracking файл

# Создать файл для отслеживания прогресса
touch REORGANIZATION_PROGRESS.md

Этап 1: Аудит и группировка (1 час)

1.1 Создать матрицу миграции

Создать MIGRATION_MATRIX.md:

| Старый файл | Новое расположение | Статус | Требуется слияние |
|-------------|-------------------|--------|-------------------|
| _buttons.scss | core/_buttons.scss | ⏳ | Нет |
| _badges-bem.scss | core/_badges.scss | ⏳ | Да (с telegram) |
| _badges-telegram-style.scss | core/_badges.scss | ⏳ | Да (с bem) |
| _ios-search.scss | core/_search.scss | ⏳ | Нет |
| ... | ... | ... | ... |

1.2 Проанализировать зависимости

# Найти все импорты
grep -r "@import" main.scss custom-bootstrap.scss

# Найти использование классов в шаблонах
grep -r "class=" templates/ | grep -E "(ios-|badge-|card-list)"

Этап 2: Core UI Kit (2 часа)

2.1 Простые перемещения (без изменений)

# Buttons - просто переместить
mv components/_buttons.scss core/_buttons.scss

# Cards - переместить
mv components/_cards.scss core/_cards.scss

# Comments - переместить
mv components/_comments.scss core/_comments.scss

# Common - переместить
mv components/_common.scss core/_common.scss

2.2 Переименование файлов

# iOS-search → search
mv components/_ios-search.scss core/_search.scss

# iOS-components разобрать на части или переименовать
mv components/_ios-components.scss core/_ui-elements.scss

Задача: Открыть _ios-components.scss, посмотреть что там, возможно разбить на несколько файлов.

2.3 Объединение badges (ВАЖНО!)

Шаги:

  1. Открыть _badges-bem.scss и _badges-telegram-style.scss
  2. Проанализировать что можно объединить
  3. Создать единый core/_badges.scss:
// core/_badges.scss

// ===== BASE BADGE =====
.badge {
  // Общие стили
}

// ===== BEM VARIANT =====
.badge--bem {
  // BEM специфичные стили
}

// ===== TELEGRAM VARIANT =====
.badge--telegram {
  // Telegram специфичные стили
}

// ===== STATUS VARIANTS =====
.badge--success { }
.badge--danger { }
.badge--pending { }
  1. Удалить старые файлы
  2. Обновить импорты

2.4 Объединение modals

# Объединить modal-overrides в modals
cat components/_modal-overrides.scss >> components/_modals.scss
mv components/_modals.scss core/_modals.scss
rm components/_modal-overrides.scss

Почистить дубли в объединенном файле!

2.5 Создать core/_lists.scss

Проанализировать:

  • _card-list.scss - общие стили списков
  • _list-view.scss - view стили

Объединить общее в core/_lists.scss:

// core/_lists.scss

// ===== BASE LIST =====
.list {
  // Базовые стили списка
}

// ===== LIST ITEM =====
.list__item {
  // Стили элемента списка
}

// ===== VARIANTS =====
.list--compact { }
.list--cards { }

Этап 3: Layout реорганизация (1.5 часа)

3.1 Создать layout/_grid.scss

# Переместить base-app
mv layout/_base-app.scss layout/_grid.scss

Внутри файла переименовать классы:

  • .app-layout → .app-grid
  • Улучшить документацию

3.2 Объединить header компоненты

Анализ:

  • _navbar.scss - навигация
  • _page-header.scss - заголовок страницы

Варианты:

A) Объединить в один файл:

cat components/_navbar.scss components/_page-header.scss > layout/_header.scss

B) Оставить раздельно но переименовать:

mv components/_navbar.scss layout/_navbar.scss
mv components/_page-header.scss layout/_page-header.scss

Рекомендация: Вариант B (раздельно), но добавить комментарий что это части header'а.

3.3 Rightbar + Calendar

# Переместить rightbar-calendar
mv components/_rightbar-calendar.scss layout/_rightbar.scss

Внутри переименовать классы:

  • .rightbar-card → .rightbar__card
  • .calendar-wrap → .rightbar__calendar

Этап 4: Features организация (2 часа)

4.1 Feed feature

# Создать feed папку
mkdir -p features/feed

# Переместить компоненты
mv components/_feed-specific.scss features/feed/_layout.scss
mv components/_post-form.scss features/feed/_post-form.scss
mv components/_join-scroller.scss features/feed/_members-scroller.scss

# Если есть feed-header или подобное - тоже сюда

Создать features/feed/_index.scss:

@forward 'layout';
@forward 'post-form';
@forward 'members-scroller';

4.2 Requests feature

mkdir -p features/requests

mv components/_request-list.scss features/requests/_list.scss
mv components/_request-detail.scss features/requests/_detail.scss
mv components/_recipientPicker.scss features/requests/_recipient-picker.scss

Создать features/requests/_index.scss:

@forward 'list';
@forward 'detail';
@forward 'recipient-picker';

4.3 Documents feature

mkdir -p features/documents

mv components/_document-list.scss features/documents/_list.scss

Создать features/documents/_index.scss:

@forward 'list';

4.4 Employees feature

mkdir -p features/employees

mv components/_department-controls.scss features/employees/_controls.scss
mv components/_team-wheel.scss features/employees/_team-viz.scss

Переименовать внутри _team-viz.scss:

  • .team-wheel → .team-viz
  • Обновить комментарии

Создать features/employees/_index.scss:

@forward 'controls';
@forward 'team-viz';

4.5 Notifications feature

mkdir -p features/notifications

mv components/_notifications.scss features/notifications/_center.scss

Создать features/notifications/_index.scss:

@forward 'center';

4.6 Chat feature (оставить как есть)

# Chat уже в подпапке - оставить
# features/chat/ уже существует как components/chat/
# Просто переместить папку целиком
mv components/chat features/chat

4.7 Logout modal (куда деть?)

Варианты:

  1. В features/auth/_logout-modal.scss
  2. В core/_modals.scss (добавить специфичные стили)
  3. Удалить если можно использовать общий modal

Рекомендация: Вариант 2 - добавить .modal--logout в core модалы.

# Слить с core/modals
cat components/_logout-modal.scss >> core/_modals.scss
rm components/_logout-modal.scss

Этап 5: Utilities (30 мин)

5.1 Объединить spacing

# Объединить два spacing файла
cat components/_layout-spacing.scss components/_spacing-utils.scss > utilities/_spacing.scss

# Почистить дубли в объединенном файле
# Удалить старые
rm components/_layout-spacing.scss
rm components/_spacing-utils.scss

5.2 Проверить пустую utilities папку

# Удалить старую пустую папку если осталась
rmdir utilities/ 2>/dev/null || true

Этап 6: Обновление импортов (1.5 часа)

6.1 Создать новый main.scss

Создать main.scss.new:

// =============================================================================
// Main Application SCSS
// =============================================================================
// Главный файл для сборки всех стилей приложения (кроме Bootstrap)
// Компилируется в css/app.css

// =============================================================================
// 1. ABSTRACTS - Переменные, миксины, функции
// =============================================================================
@import 'abstracts/index';

// =============================================================================
// 2. CORE - UI Kit компоненты
// =============================================================================
@import 'core/buttons';
@import 'core/forms';
@import 'core/badges';
@import 'core/cards';
@import 'core/lists';
@import 'core/modals';
@import 'core/avatars';
@import 'core/search';
@import 'core/comments';
@import 'core/common';

// =============================================================================
// 3. LAYOUT - Структура приложения
// =============================================================================
@import 'layout/grid';
@import 'layout/navbar';
@import 'layout/page-header';
@import 'layout/sidebar';
@import 'layout/rightbar';

// =============================================================================
// 4. UTILITIES - Вспомогательные классы
// =============================================================================
@import 'utilities/spacing';

// =============================================================================
// 5. FEATURES - Feature-specific стили
// =============================================================================

// Feed
@import 'features/feed/layout';
@import 'features/feed/post-form';
@import 'features/feed/members-scroller';

// Requests
@import 'features/requests/list';
@import 'features/requests/detail';
@import 'features/requests/recipient-picker';

// Documents
@import 'features/documents/list';

// Employees
@import 'features/employees/controls';
@import 'features/employees/team-viz';

// Notifications
@import 'features/notifications/center';

// Chat
@import 'features/chat/message-inputs';
@import 'features/chat/chat-detail';
@import 'features/chat/chat-date-groups';
@import 'features/chat/chat-list-enhanced';
@import 'features/chat/chat-enhanced';
@import 'features/chat/chat-polls';
@import 'features/chat/chat-new-messages-indicator';
@import 'features/chat/message-selection';
@import 'features/chat/message-context-menu';
@import 'features/chat/message-reactions';

// =============================================================================
// ПРИМЕЧАНИЯ
// =============================================================================
// - Bootstrap подключается отдельно через bootstrap-custom.css
// - CSS переменные (--variable) определены в abstracts/_css-variables.scss
// - SCSS переменные ($variable) определены в abstracts/_variables.scss
// - Порядок импортов критичен для CSS каскада
// - Core компоненты = переиспользуемые UI элементы
// - Features = специфичные для конкретных функций приложения

6.2 Очистить custom-bootstrap.scss

Создать custom-bootstrap.scss.new:

// =============================================================================
// Custom Bootstrap Configuration
// =============================================================================
// Этот файл переопределяет переменные Bootstrap ДО его компиляции

// =============================================================================
// 1. ПЕРЕОПРЕДЕЛЕНИЕ BOOTSTRAP ПЕРЕМЕННЫХ
// =============================================================================

// Система отступов (8px grid)
$spacer: 1rem !default;
$spacers: (
  0: 0,
  1: 0.25rem,    // 4px
  2: 0.5rem,     // 8px
  3: 0.75rem,    // 12px
  4: 1rem,       // 16px
  5: 1.5rem,     // 24px
) !default;

// Grid
$grid-gutter-width: 0.5rem !default;

// Cards
$card-spacer-y: 1rem !default;
$card-spacer-x: 1rem !default;
$card-border-radius: 14px !default;

// Buttons
$btn-padding-y: 0.5rem !default;
$btn-padding-x: 1rem !default;

// Inputs
$input-padding-y: 0.5rem !default;
$input-padding-x: 1rem !default;

// =============================================================================
// 2. ИМПОРТ ABSTRACTS
// =============================================================================
@import "abstracts/variables";
@import "abstracts/mixins";

// =============================================================================
// 3. ИМПОРТ BOOTSTRAP
// =============================================================================
@import "../node_modules/bootstrap/scss/bootstrap";

// =============================================================================
// 4. CSS ПЕРЕМЕННЫЕ (RUNTIME)
// =============================================================================
@import "abstracts/css-variables";

// =============================================================================
// ВСЕ! Никаких компонентов здесь!
// Все компоненты в main.scss → app.css
// =============================================================================

6.3 Тестовая компиляция

cd backend/static

# Backup старых файлов
mv scss/main.scss scss/main.scss.old
mv scss/custom-bootstrap.scss scss/custom-bootstrap.scss.old

# Применить новые
mv scss/main.scss.new scss/main.scss
mv scss/custom-bootstrap.scss.new scss/custom-bootstrap.scss

# Попробовать собрать
npm run build:app 2>&1 | tee build_errors.log

# Если ошибки - смотреть build_errors.log

6.4 Исправление ошибок импортов

# Найти все missing imports
grep -i "can't find" build_errors.log

# Найти старые пути в файлах
grep -r "@import.*components/" scss/

# Исправить пути

Этап 7: Cleanup (30 мин)

7.1 Удалить старую components папку

# Проверить что components пуста
ls -la scss/components/

# Если пусто - удалить
rm -rf scss/components/

# Оставить только .gitkeep или удалить совсем

7.2 Удалить BUTTONS_README.md из старого места

# Переместить в новое место
mv scss/components/BUTTONS_README.md docs/guides/BUTTONS_COMPONENT.md

# Или в core папку
mv scss/components/BUTTONS_README.md scss/core/README_BUTTONS.md

7.3 Проверить дубликаты

# Найти дублирующиеся селекторы
grep -r "^\.badge" scss/ | sort | uniq -d

# Найти дублирующиеся @import
grep -r "@import" scss/main.scss scss/custom-bootstrap.scss | sort | uniq -d

Этап 8: Тестирование (1 час)

8.1 Сборка финальных CSS

# Собрать все
npm run build:app
npm run build:bootstrap

# Проверить размеры
ls -lh css/app.css css/bootstrap-custom.css

# Сравнить с backup
ls -lh css_backup/app.css css_backup/bootstrap-custom.css

8.2 Визуальное тестирование

Проверить страницы:

  1. Главная / feed
  2. Список заявок
  3. Детали заявки
  4. Список документов
  5. Список сотрудников
  6. Уведомления
  7. Чат
  8. Logout modal
  9. Search
  10. Forms

Чек-лист для каждой страницы:

  • Стили загружаются
  • Нет визуальных багов
  • Кнопки работают
  • Формы выглядят нормально
  • Responsive работает

8.3 Проверка консоли браузера

// В DevTools Console
// Проверить нет ли 404 на CSS
// Проверить размер загруженных CSS
performance.getEntriesByType('resource')
  .filter(r => r.name.includes('.css'))

Этап 9: Документация (30 мин)

9.1 Создать scss/README.md

# SCSS Architecture

## Structure

### Core (UI Kit)
Переиспользуемые UI компоненты: buttons, cards, badges, modals, etc.

### Layout
Структура приложения: grid, header, sidebar, rightbar.

### Features
Feature-specific стили, организованные по функциям приложения.

### Utilities
Utility классы: spacing, helpers, etc.

## Build
`npm run build:app` - компилирует main.scss → app.css
`npm run build:bootstrap` - компилирует bootstrap-custom.scss → bootstrap-custom.css

## Adding New Components
1. Core component → `core/_component.scss`
2. Feature component → `features/feature/_component.scss`
3. Add import to `main.scss`
4. Run `npm run build:app`

9.2 Обновить docs/guides/SCSS_QUICK_REFERENCE.md

Обновить пути и структуру в quick reference.

9.3 Создать отчет о реорганизации

docs/reports/SCSS_REORGANIZATION_COMPLETE.md с:

  • Что было изменено
  • Новая структура
  • Метрики (файлы, размеры, время)

Этап 10: Git commit (15 мин)

# Добавить все изменения
git add -A

# Коммит
git commit -m "refactor: Complete SCSS architecture reorganization

- Restructured 51 SCSS files into logical categories
- Created core/ (UI Kit), layout/, features/, utilities/ folders
- Merged duplicate components: badges (2→1), modals (2→1), spacing (2→1)
- Renamed files: ios-search→search, team-wheel→team-viz, etc.
- Cleaned custom-bootstrap.scss from component imports
- Moved chat components from bootstrap to main.scss
- Updated all imports in main.scss and custom-bootstrap.scss

Structure:
- core/ (9 files) - Reusable UI components
- layout/ (5 files) - App structure
- features/ (16 files in 6 folders) - Feature-specific styles
- utilities/ (1 file) - Utility classes

Benefits:
- Clear categorization
- No duplicate imports
- Logical feature grouping
- Easier maintenance
- Clean architecture

Breaking changes: None (CSS class names unchanged)
"

# Push
git push

📊 Метрики успеха

До реорганизации:

components/ - 30 файлов (хаос)
layout/ - 2 файла
utilities/ - пуста
Дублирующиеся импорты: 8 компонентов
Странные названия: ios-, telegram-, -specific, team-wheel

После реорганизации:

core/ - 9-10 файлов (UI Kit)
layout/ - 4-5 файлов (структура)
features/ - 16 файлов в 6 папках (по функциям)
utilities/ - 1 файл (spacing)
Дублирующиеся импорты: 0
Понятные названия: search, badges, team-viz

Улучшения:

  • ✅ Четкая категоризация
  • ✅ Нет дубликатов
  • ✅ Логичная группировка
  • ✅ Легче найти нужный файл
  • ✅ Понятные названия
  • ✅ Масштабируемая структура

⚠️ Риски и как их минимизировать

Риск 1: Сломать стили

Минимизация:

  • Делать backup перед каждым этапом
  • Тестировать после каждого этапа
  • Не менять CSS классы, только структуру файлов
  • Использовать git для отката

Риск 2: Забыть обновить импорт

Минимизация:

  • Вести матрицу миграции
  • Проверять build errors
  • Grep поиск старых путей
  • Тестовая компиляция после каждого шага

Риск 3: Потерять изменения

Минимизация:

  • Git commit после каждого этапа
  • Backup папка
  • Документировать прогресс

Риск 4: Слишком долго

Минимизация:

  • Разбить на этапы
  • Можно делать частями (по 2-3 этапа в день)
  • Приоритет: сначала core, потом features

🎯 Альтернативный подход (если мало времени)

Минимальный рефакторинг (2 часа):

  1. Убрать дубликаты из custom-bootstrap (30 мин)
  2. Переместить chat в main.scss (15 мин)
  3. Объединить badges (20 мин)
  4. Объединить modals (15 мин)
  5. Объединить spacing (20 мин)
  6. Переименовать ios- файлы* (20 мин)

Остальное оставить как есть. Будет лучше но не идеально.


📚 Дополнительные ресурсы



🚨 БОНУСНЫЙ ЭТАП: Полный отказ от Bootstrap

⚠️ ВНИМАНИЕ: Этот этап увеличивает время реализации в 5-7 раз!

Зачем отказываться от Bootstrap?

Плюсы:

  • ✅ Полный контроль над кодом
  • ✅ Уменьшение размера бандла (~300 KB → ~100 KB)
  • ✅ Нет неиспользуемого кода
  • ✅ Точная семантика под наше приложение
  • ✅ Легче кастомизация
  • ✅ Современный CSS (Grid, Custom Properties, Container Queries)

Минусы:

  • ❌ Нужно написать свой UI Kit с нуля
  • ❌ Время: 40-60 часов вместо 8 часов
  • ❌ Нужно поддерживать свой код
  • ❌ Протестировать все компоненты
  • ❌ Обеспечить кроссбраузерность
  • ❌ Документировать систему

Что нужно переписать?

Bootstrap предоставляет (~180 компонентов):

  1. Grid System - 12-колоночная сетка
  2. Typography - заголовки, параграфы, списки
  3. Buttons - 9 вариантов кнопок + sizes + states
  4. Forms - inputs, selects, checkboxes, radio, validation
  5. Cards - карточки с header/body/footer
  6. Modals - модальные окна с backdrop
  7. Alerts - уведомления
  8. Badges - бейджи
  9. Breadcrumbs - хлебные крошки
  10. Dropdowns - выпадающие меню
  11. Navbar - навигация
  12. Pagination - пагинация
  13. Progress - прогресс-бары
  14. Spinners - загрузчики
  15. Tooltips - подсказки
  16. Popovers - всплывающие окна
  17. Utilities - margin, padding, flex, display, colors...

Используется в проекте (по grep):

# Найти что реально используется
grep -r "class=" templates/ | grep -oE '\.(btn|card|modal|form-|input-|alert|badge|nav|dropdown|pagination|container|row|col-|d-|m-|p-|text-|bg-|border-)' | sort | uniq -c

Этап 0: Аудит использования Bootstrap (4 часа)

0.1 Собрать статистику использования

cd backend

# Создать скрипт для анализа
cat > analyze_bootstrap_usage.py << 'EOF'
import re
from pathlib import Path
from collections import Counter

# Bootstrap классы
BS_PATTERNS = [
    r'\bbtn-\w+', r'\bcard-\w+', r'\bmodal-\w+', r'\bform-\w+',
    r'\balert-\w+', r'\bbadge-\w+', r'\bnav-\w+', r'\bcol-\w+',
    r'\brow\b', r'\bcontainer\b', r'\bd-\w+', r'\bm[tblrxy]?-\d',
    r'\bp[tblrxy]?-\d', r'\btext-\w+', r'\bbg-\w+', r'\bborder-\w+'
]

templates_dir = Path('templates')
all_classes = Counter()

for html_file in templates_dir.rglob('*.html'):
    content = html_file.read_text(encoding='utf-8')
    for pattern in BS_PATTERNS:
        matches = re.findall(pattern, content)
        all_classes.update(matches)

print("=== TOP 50 BOOTSTRAP CLASSES ===")
for cls, count in all_classes.most_common(50):
    print(f"{cls:30} - {count:4} uses")

print(f"\n=== TOTAL: {len(all_classes)} unique Bootstrap classes ===")
EOF

.venv/Scripts/python analyze_bootstrap_usage.py > bootstrap_usage_report.txt

0.2 Создать матрицу замены

BOOTSTRAP_REPLACEMENT_MATRIX.md:

| Bootstrap класс | Использований | Наш класс | Статус |
|-----------------|---------------|-----------|--------|
| .btn-primary | 150 | .button--primary | ⏳ |
| .card | 120 | .card | ⏳ |
| .modal | 45 | .modal | ⏳ |
| .form-control | 200 | .input | ⏳ |
| .container | 80 | .container | ⏳ |
| .row | 100 | .grid | ⏳ |
| .col-* | 300 | .grid__col | ⏳ |

0.3 Оценить объем работы

# Посчитать templates с Bootstrap
find templates/ -name "*.html" -exec grep -l "btn\|card\|modal\|form-control" {} \; | wc -l

# Посчитать строк кода
find templates/ -name "*.html" | xargs wc -l

Этап B1: Создать свою Grid систему (6 часов)

B1.1 Создать core/_grid.scss

// core/_grid.scss

// =============================================================================
// GRID SYSTEM
// =============================================================================
// Своя grid система на CSS Grid (не flexbox как Bootstrap)

// Переменные
$grid-columns: 12;
$grid-gap: 1rem;
$grid-container-max: 1200px;

// Container
.container {
  width: 100%;
  max-width: $grid-container-max;
  margin: 0 auto;
  padding: 0 1rem;
}

.container--fluid {
  max-width: 100%;
}

// Grid
.grid {
  display: grid;
  grid-template-columns: repeat($grid-columns, 1fr);
  gap: $grid-gap;
  
  // Responsive gaps
  &--gap-sm { gap: 0.5rem; }
  &--gap-lg { gap: 2rem; }
}

// Grid columns
@for $i from 1 through $grid-columns {
  .grid__col-#{$i} {
    grid-column: span $i;
  }
}

// Responsive
@media (max-width: 768px) {
  .grid__col-12-mobile {
    grid-column: span 12;
  }
}

// Auto-fit grid
.grid--auto {
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

B1.2 Создать миграционный скрипт

# scripts/replace_bootstrap_grid.py
import re
from pathlib import Path

def replace_bootstrap_grid(content):
    # .row → .grid
    content = re.sub(r'\brow\b', 'grid', content)
    
    # .col-{n} → .grid__col-{n}
    content = re.sub(r'\bcol-(\d+)', r'grid__col-\1', content)
    
    # .container → .container (оставить)
    
    return content

templates_dir = Path('templates')
for html_file in templates_dir.rglob('*.html'):
    content = html_file.read_text(encoding='utf-8')
    new_content = replace_bootstrap_grid(content)
    if content != new_content:
        html_file.write_text(new_content, encoding='utf-8')
        print(f"Updated: {html_file}")

Этап B2: Создать свою Button систему (4 часа)

// core/_buttons.scss

.button {
  // Base styles
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 0.375rem;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.5;
  cursor: pointer;
  transition: all 0.2s;
  
  &:hover { opacity: 0.85; }
  &:active { transform: scale(0.98); }
  &:disabled { opacity: 0.5; cursor: not-allowed; }
  
  // Variants
  &--primary { background: var(--color-primary); color: white; }
  &--secondary { background: var(--color-secondary); color: white; }
  &--success { background: var(--color-success); color: white; }
  &--danger { background: var(--color-danger); color: white; }
  &--outline { background: transparent; border: 1px solid currentColor; }
  
  // Sizes
  &--sm { padding: 0.25rem 0.5rem; font-size: 0.875rem; }
  &--lg { padding: 0.75rem 1.5rem; font-size: 1.125rem; }
  
  // Full width
  &--block { width: 100%; }
}

// Миграция: .btn-primary → .button.button--primary

Этап B3: Создать Form систему (8 часов)

// core/_forms.scss

.form-group {
  margin-bottom: 1rem;
}

.label {
  display: block;
  margin-bottom: 0.25rem;
  font-weight: 500;
  font-size: 0.875rem;
}

.input,
.textarea,
.select {
  width: 100%;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: 0.375rem;
  font-size: 1rem;
  transition: border-color 0.2s;
  
  &:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.1);
  }
  
  &--error {
    border-color: var(--color-danger);
  }
  
  &:disabled {
    background: var(--color-gray-100);
    cursor: not-allowed;
  }
}

.textarea {
  resize: vertical;
  min-height: 100px;
}

.checkbox,
.radio {
  // Кастомные checkbox/radio
  appearance: none;
  width: 1.25rem;
  height: 1.25rem;
  border: 2px solid var(--color-border);
  border-radius: 0.25rem;
  cursor: pointer;
  
  &:checked {
    background: var(--color-primary);
    border-color: var(--color-primary);
  }
}

.radio {
  border-radius: 50%;
}

Этап B4: Utilities система (4 часа)

// utilities/_spacing.scss

// Margin и Padding генератор
$spacers: (
  0: 0,
  1: 0.25rem,
  2: 0.5rem,
  3: 0.75rem,
  4: 1rem,
  5: 1.5rem,
  6: 2rem,
);

@each $key, $value in $spacers {
  // Margin
  .m-#{$key} { margin: $value; }
  .mt-#{$key} { margin-top: $value; }
  .mb-#{$key} { margin-bottom: $value; }
  .ml-#{$key} { margin-left: $value; }
  .mr-#{$key} { margin-right: $value; }
  .mx-#{$key} { margin-left: $value; margin-right: $value; }
  .my-#{$key} { margin-top: $value; margin-bottom: $value; }
  
  // Padding
  .p-#{$key} { padding: $value; }
  .pt-#{$key} { padding-top: $value; }
  .pb-#{$key} { padding-bottom: $value; }
  .pl-#{$key} { padding-left: $value; }
  .pr-#{$key} { padding-right: $value; }
  .px-#{$key} { padding-left: $value; padding-right: $value; }
  .py-#{$key} { padding-top: $value; padding-bottom: $value; }
}

// Display utilities
.d-none { display: none; }
.d-block { display: block; }
.d-flex { display: flex; }
.d-grid { display: grid; }
.d-inline { display: inline; }
.d-inline-block { display: inline-block; }

// Flexbox utilities
.flex-row { flex-direction: row; }
.flex-column { flex-direction: column; }
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.justify-end { justify-content: flex-end; }
.align-center { align-items: center; }
.align-start { align-items: flex-start; }
.gap-1 { gap: 0.25rem; }
.gap-2 { gap: 0.5rem; }
.gap-3 { gap: 1rem; }

// Text utilities
.text-left { text-align: left; }
.text-center { text-align: center; }
.text-right { text-align: right; }
.text-bold { font-weight: bold; }
.text-sm { font-size: 0.875rem; }
.text-lg { font-size: 1.125rem; }

Этап B5: Cards, Modals, Alerts (6 часов)

Написать свои версии этих компонентов.

Этап B6: Массовая замена в templates (12 часов)

# scripts/migrate_all_bootstrap_classes.py

REPLACEMENTS = {
    # Buttons
    r'\bbtn\b': 'button',
    r'\bbtn-primary\b': 'button--primary',
    r'\bbtn-secondary\b': 'button--secondary',
    r'\bbtn-sm\b': 'button--sm',
    r'\bbtn-lg\b': 'button--lg',
    
    # Forms
    r'\bform-control\b': 'input',
    r'\bform-group\b': 'form-group',
    r'\bform-label\b': 'label',
    
    # Grid
    r'\brow\b': 'grid',
    r'\bcol-(\d+)': r'grid__col-\1',
    
    # Cards
    r'\bcard\b': 'card',
    r'\bcard-body\b': 'card__body',
    r'\bcard-header\b': 'card__header',
    
    # Utilities
    r'\bd-flex\b': 'd-flex',
    r'\bjustify-content-center\b': 'justify-center',
    # ... еще сотни замен
}

def migrate_template(filepath):
    content = filepath.read_text(encoding='utf-8')
    for old, new in REPLACEMENTS.items():
        content = re.sub(old, new, content)
    filepath.write_text(content, encoding='utf-8')

# Запустить на всех templates
for html_file in Path('templates').rglob('*.html'):
    migrate_template(html_file)

Этап B7: Удаление Bootstrap (1 час)

# Удалить из package.json
npm uninstall bootstrap

# Удалить custom-bootstrap.scss
rm scss/custom-bootstrap.scss

# Удалить из templates
grep -r "bootstrap-custom.css" templates/ 
# Заменить на только app.css

# Обновить build скрипты
# Оставить только npm run build:app

Этап B8: Тестирование (8 часов)

Протестировать каждую страницу:

  • Визуальная регрессия
  • Responsive
  • Кроссбраузерность
  • Формы работают
  • Модалы открываются
  • И т.д.

📊 Сравнение подходов

Вариант А: С Bootstrap (рекомендуется сейчас)

Плюсы:

  • ⏱️ Быстро: 6-8 часов
  • ✅ Проверенное решение
  • ✅ Хорошая документация
  • ✅ Обновления безопасности
  • ✅ Кроссбраузерность из коробки

Минусы:

  • 📦 Размер бандла: ~300 KB
  • 🔧 Ограничения кастомизации
  • 📚 Неиспользуемый код

Итоговый размер:

  • bootstrap-custom.css: ~280 KB
  • app.css: ~95 KB
  • ИТОГО: ~375 KB

Вариант Б: Без Bootstrap (требует времени)

Плюсы:

  • 📦 Размер бандла: ~100 KB (в 3 раза меньше!)
  • 🎨 Полный контроль
  • 🚀 Только нужный код
  • 💅 Современный CSS

Минусы:

  • ⏱️ Долго: 40-60 часов
  • 🔧 Нужна поддержка
  • 🐛 Больше багов
  • 📚 Нужна документация

Итоговый размер:

  • app.css: ~100 KB
  • ИТОГО: ~100 KB

🎯 Рекомендуемая стратегия

Поэтапный отказ от Bootstrap:

  1. Этап 1-10 (6-8 часов): Реорганизация SCSS с Bootstrap
  2. Использовать проект 2-3 месяца
  3. Этап B (40-60 часов): Постепенная замена Bootstrap своими стилями
    • Сначала Grid → готово за выходные
    • Потом Buttons → неделя
    • Потом Forms → неделя
    • Постепенно все остальное
  4. Тестирование на продакшене
  5. Удаление Bootstrap когда все заменено

Преимущества поэтапного подхода:

  • ✅ Не ломаем текущий проект
  • ✅ Можно тестировать части
  • ✅ Откатиться легко
  • ✅ Меньше риска

🤔 Мое мнение

Для корпоративного Django приложения:

👍 ЗА отказ от Bootstrap:

  • Полный контроль над кодом
  • Меньше размер
  • Современные CSS возможности
  • Нет jQuery зависимостей (если используете Bootstrap JS)

👎 ПРОТИВ отказа от Bootstrap:

  • Огромная работа (40-60 часов)
  • Нужно поддерживать свой код
  • Риск багов
  • Уже работает хорошо

Мой совет:

  1. Сейчас сделать реорганизацию С Bootstrap (8 часов)
  2. Использовать 1-2 месяца
  3. Если реально чувствуете ограничения - начать постепенно заменять
  4. Если все работает нормально - оставить Bootstrap

Большинство крупных проектов используют Bootstrap/Tailwind/Foundation - это нормально и правильно.


Готов начать? Какой вариант выбираем?

A) Реорганизация с Bootstrap (8 часов, безопасно) Б) Полный отказ от Bootstrap (60 часов, амбициозно) В) Поэтапная замена (8 часов сейчас + 40 часов потом)