### 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
120 lines
4.8 KiB
HTML
120 lines
4.8 KiB
HTML
{# Универсальный компонент шапки страницы списка. См. документацию в PAGE_HEADER_SUMMARY.md #}
|
||
|
||
{# ===== ШАПКА СТРАНИЦЫ ===== #}
|
||
<div class="page-header">
|
||
<div class="d-flex align-items-center gap-2">
|
||
{# Иконка #}
|
||
{% if icon %}
|
||
<i class="{{ icon }} fs-2 text-primary flex-shrink-0"></i>
|
||
{% endif %}
|
||
|
||
{# Заголовок #}
|
||
<h2 class="page-title mb-0">{{ title }}</h2>
|
||
|
||
{# Счётчик (если есть) #}
|
||
{% if count is not None %}
|
||
<span class="page-count text-secondary">
|
||
{{ count_label|default:"Всего:" }} <span class="count-value">{{ count }}</span>
|
||
</span>
|
||
{% endif %}
|
||
|
||
{# Правая часть - кнопки и поиск #}
|
||
<div class="ms-auto d-flex align-items-center gap-2">
|
||
{# Дополнительные кнопки (slot) #}
|
||
{% if extra_buttons %}
|
||
{{ extra_buttons }}
|
||
{% endif %}
|
||
|
||
{# Поиск iOS-стиль #}
|
||
{% if not no_search and search_id %}
|
||
<div class="page-search ios-search">
|
||
<i class="bi-search"></i>
|
||
<input type="search"
|
||
id="{{ search_id }}"
|
||
class="ios-search-input"
|
||
placeholder="{{ search_placeholder|default:'Поиск...' }}"
|
||
autocomplete="off">
|
||
<button type="button" class="ios-search-clear" aria-label="Очистить">
|
||
<i class="bi-x-lg"></i>
|
||
</button>
|
||
</div>
|
||
{% endif %}
|
||
|
||
{# Кнопка раскрытия фильтров #}
|
||
{% if has_filters and filters_target %}
|
||
<button class="button button--outline button--secondary btn-circle page-filter-toggle"
|
||
type="button"
|
||
data-bs-toggle="collapse"
|
||
data-bs-target="#{{ filters_target }}"
|
||
aria-expanded="false"
|
||
aria-controls="{{ filters_target }}"
|
||
aria-label="Показать фильтры">
|
||
<i class="bi-funnel"></i>
|
||
</button>
|
||
{% endif %}
|
||
|
||
{# Кнопка создания (только если create_as_card не установлен) #}
|
||
{% if not no_create and not create_as_card %}
|
||
{% if create_modal %}
|
||
<button type="button"
|
||
class="button button--primary button--sm btn-pill button--icon page-create-button"
|
||
data-bs-toggle="modal"
|
||
data-bs-target="#{{ create_modal }}">
|
||
<i class="{{ create_icon|default:'bi-plus-lg' }}"></i>
|
||
<span class="btn-text">{{ create_text|default:"Создать" }}</span>
|
||
</button>
|
||
{% elif create_url %}
|
||
<a href="{{ create_url }}"
|
||
class="button button--primary button--sm btn-pill button--icon page-create-button">
|
||
<i class="{{ create_icon|default:'bi-plus-lg' }}"></i>
|
||
<span class="btn-text">{{ create_text|default:"Создать" }}</span>
|
||
</a>
|
||
{% endif %}
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
{# ===== БЛОК ФИЛЬТРОВ (скрываемый) ===== #}
|
||
{% if has_filters and filters_target %}
|
||
<div class="collapse page-filters-collapse" id="{{ filters_target }}">
|
||
<div class="page-filters">
|
||
{% if filters_template %}
|
||
{# Включаем внешний шаблон фильтров #}
|
||
{% include filters_template %}
|
||
{% else %}
|
||
{# Или используем переданный HTML #}
|
||
{{ filters_html|safe }}
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
{# ===== КНОПКА СОЗДАНИЯ В ВИДЕ КАРТОЧКИ ===== #}
|
||
{% if not no_create and create_as_card %}
|
||
{% if create_modal %}
|
||
<div class="card mb-2">
|
||
<button type="button"
|
||
class="dept-row d-flex w-100 justify-content-center align-items-center gap-2 text-decoration-none border-0 bg-transparent"
|
||
data-bs-toggle="modal"
|
||
data-bs-target="#{{ create_modal }}"
|
||
role="button"
|
||
aria-label="{{ create_text|default:'Создать' }}">
|
||
<span class="card-title">{{ create_text|default:"Создать" }}</span>
|
||
<i class="{{ create_icon|default:'bi-plus-lg' }}"></i>
|
||
</button>
|
||
</div>
|
||
{% elif create_url %}
|
||
<div class="card mb-2">
|
||
<a href="{{ create_url }}"
|
||
class="dept-row d-flex w-100 justify-content-center align-items-center gap-2 text-decoration-none border-0 bg-transparent"
|
||
role="button"
|
||
aria-label="{{ create_text|default:'Создать' }}">
|
||
<span class="card-title">{{ create_text|default:"Создать" }}</span>
|
||
<i class="{{ create_icon|default:'bi-plus-lg' }}"></i>
|
||
</a>
|
||
</div>
|
||
{% endif %}
|
||
{% endif %}
|
||
</div>
|
||
|