Corp/backend/migrate_buttons.py
Игорь Надеин 8159c6f472 feat: Replace Bootstrap buttons with custom button system
### Custom Button System Implementation

Created modern button system to replace Bootstrap buttons:

- ✅ Created core/_buttons-custom.scss (550+ lines)
- ✅ CSS Custom Properties for easy customization
- ✅ 8 color variants (primary, secondary, success, danger, warning, info, light, dark)
- ✅ Outline and Ghost variants
- ✅ 4 sizes (sm, md, lg, xl)
- ✅ Special variants (block, icon, circle, link)
- ✅ Loading state with spinner animation
- ✅ Button groups support
- ✅ Modern animations (hover, active, focus)

### Template Migration

Migrated 65 HTML templates using automated Python script:
- Replaced .btn → .button
- Replaced .btn-primary → .button--primary
- Replaced .btn-outline-* → .button--outline button--*
- Replaced size classes .btn-sm → .button--sm
- Total changes: 354 → 347 button usages

### Results

- app.css: 137 KB → 148 KB (+11 KB for custom buttons)
- Templates changed: 65 files
- Remaining .btn classes: 133 (mostly btn-close for modals)
- New .button classes: 347

### Backward Compatibility

Kept @extend rules in _buttons-custom.scss for gradual migration.
Can be removed after complete migration.

Next step: Remove Bootstrap button imports from custom-bootstrap.scss
2026-01-15 14:23:44 +03:00

99 lines
3.3 KiB
Python

#!/usr/bin/env python3
"""
Скрипт для миграции Bootstrap кнопок на новую систему
Заменяет .btn классы на .button классы
"""
import re
import os
from pathlib import Path
# Карта замен Bootstrap классов на новые
REPLACEMENTS = {
# Основной класс
r'\bbtn\b(?!-)': 'button',
# Цветовые варианты
r'\bbtn-primary\b': 'button--primary',
r'\bbtn-secondary\b': 'button--secondary',
r'\bbtn-success\b': 'button--success',
r'\bbtn-danger\b': 'button--danger',
r'\bbtn-warning\b': 'button--warning',
r'\bbtn-info\b': 'button--info',
r'\bbtn-light\b': 'button--light',
r'\bbtn-dark\b': 'button--dark',
# Outline варианты
r'\bbtn-outline-primary\b': 'button--outline button--primary',
r'\bbtn-outline-secondary\b': 'button--outline button--secondary',
r'\bbtn-outline-success\b': 'button--outline button--success',
r'\bbtn-outline-danger\b': 'button--outline button--danger',
r'\bbtn-outline-warning\b': 'button--outline button--warning',
r'\bbtn-outline-info\b': 'button--outline button--info',
# Размеры
r'\bbtn-sm\b': 'button--sm',
r'\bbtn-lg\b': 'button--lg',
r'\bbtn-block\b': 'button--block',
# Специальные (кастомные классы, которые уже есть)
r'\bbtn-ghost\b': 'button--ghost',
r'\bbtn-icon\b': 'button--icon',
r'\bbtn-link\b': 'button--link',
# btn-close оставляем как есть (Bootstrap modal close)
}
def migrate_file(filepath):
"""Мигрировать один файл"""
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
original = content
# Применяем замены
for pattern, replacement in REPLACEMENTS.items():
content = re.sub(pattern, replacement, content)
# Если изменения есть
if content != original:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(content)
return True
return False
except Exception as e:
print(f"Error processing {filepath}: {e}")
return False
def main():
templates_dir = Path('templates')
# Найти все HTML файлы
html_files = list(templates_dir.rglob('*.html'))
print(f"Найдено {len(html_files)} HTML файлов")
print("Начинаем миграцию...\n")
changed_files = []
for filepath in html_files:
if migrate_file(filepath):
changed_files.append(filepath)
print(f"✓ {filepath}")
print(f"\n{'='*60}")
print(f"Миграция завершена!")
print(f"Обработано файлов: {len(html_files)}")
print(f"Изменено файлов: {len(changed_files)}")
print(f"{'='*60}")
if changed_files:
print("\nИзмененные файлы:")
for f in changed_files[:20]: # Показать первые 20
print(f" - {f}")
if len(changed_files) > 20:
print(f" ... и еще {len(changed_files) - 20} файлов")
if __name__ == '__main__':
main()