Integrate page_header component across all list pages

- Fix bug in page_header.html: add # to data-bs-target for card create button
- Integrate page_header in department_list.html with search and create card
- Integrate page_header in feed_list.html (no search, staff-only create button)
- Integrate page_header in document_list.html with Mine/All scope toggle
- Integrate page_header in request_list_full.html with filters and scope toggle
- Integrate page_header in chat_list.html with search
- Create _filters.html template for requests_app
- Add page-header.css to all integrated templates for consistent styling
This commit is contained in:
admin i 2025-11-20 09:28:28 +03:00
parent 1b54cbd5f4
commit bedc1f0d32
7 changed files with 54 additions and 154 deletions

View File

@ -7,6 +7,7 @@
{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/components/ios-search.css' %}">
<link rel="stylesheet" href="{% static 'css/components/feed-cards.css' %}">
<link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
{% endblock %}
{% block content %}
@ -14,28 +15,10 @@
<div class="row gx-0">
<div class="col-12">
{# Заголовок + ПОИСК (iOS-стиль) #}
<div class="feed-header d-flex align-items-center">
<i class="bi-chat-dots fs-2 text-primary"></i>
<h2 class="title mb-0">Мои чаты</h2>
{# ===== НОВАЯ ШАПКА С КОМПОНЕНТОМ ===== #}
{% include "includes/components/page_header.html" with icon="bi-chat-dots" title="Мои чаты" search_id="chatSearch" search_placeholder="Поиск по названию или участникам" no_create=True %}
<div class="ms-auto ios-search">
<div class="ios-search">
<i class="bi-search"></i>
<input
type="search"
id="chatSearch"
class="ios-search-input"
placeholder="Поиск по названию или участникам"
autocomplete="off">
<button type="button" class="ios-search-clear" aria-label="Очистить">
<i class="bi-x-lg"></i>
</button>
</div>
</div>
</div>
{# Сегментированный фильтр + КНОПКА справа #}
{# Сегментированный фильтр #}
<div class="feed-new mb-3">
<div class="d-flex align-items-center gap-2 flex-wrap">
<div class="btn-group" role="group" aria-label="Фильтр чатов">

View File

@ -7,44 +7,15 @@
<link rel="stylesheet" href="{% static 'css/components/common.css' %}">
<link rel="stylesheet" href="{% static 'css/components/feed-cards.css' %}">
<link rel="stylesheet" href="{% static 'css/components/ios-search.css' %}">
<link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
<link rel="stylesheet" href="{% static 'css/components/document-list.css' %}">
{% endblock %}
{% block content %}
<div class="container ios-page">
{# ===== Шапка страницы ===== #}
<div class="ios-header feed-header d-flex align-items-center gap-2 flex-wrap">
<i class="bi-file-earmark-text fs-2 text-primary"></i>
<h2 class="title ios-title mb-0">Документы</h2>
{% if can_manage_documents or user.is_staff or user.is_superuser %}
<div class="ms-auto d-flex align-items-center gap-2 flex-wrap">
<!-- Переключатель области (Мои / Все) -->
<div class="btn-group scope-switch" role="group" aria-label="Область">
<a href="{{ scope_urls.mine }}"
class="btn btn-outline-secondary {% if scope == 'mine' %}active{% endif %}">
Мои
</a>
<a href="{{ scope_urls.all }}"
class="btn btn-outline-secondary {% if scope == 'all' %}active{% endif %}">
Все
</a>
</div>
{% if perms.documents.add_document %}
<button type="button"
class="btn btn-primary d-flex align-items-center gap-2"
data-bs-toggle="modal"
data-bs-target="#docCreateModal">
<i class="bi-plus-lg"></i><span>Создать документ</span>
</button>
{% endif %}
</div>
{% else %}
<span class="ms-2 small text-secondary">Показаны ваши документы</span>
{% endif %}
</div>
{# ===== НОВАЯ ШАПКА С КОМПОНЕНТОМ ===== #}
{% include "includes/components/page_header.html" with icon="bi-file-earmark-text" title="Документы" no_search=True scope_urls=scope_urls scope=scope create_modal=perms.documents.add_document|yesno:"#docCreateModal," create_text="Создать документ" create_icon="bi-plus-lg" %}
{# ===== Карточка со списком ===== #}
<div class="feed-card mb-3">

View File

@ -7,6 +7,7 @@
<link rel="stylesheet" href="{% static 'css/components/common.css' %}">
<link rel="stylesheet" href="{% static 'css/components/feed-cards.css' %}">
<link rel="stylesheet" href="{% static 'css/components/ios-search.css' %}">
<link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
<link rel="stylesheet" href="{% static 'css/components/department-list.css' %}">
{% endblock %}
@ -15,31 +16,9 @@
<div class="row gx-0">
<div class="col-12">
<div class="feed-header d-flex align-items-center">
<i class="bi-diagram-3 fs-2 text-primary"></i>
<h2 class="title mb-0">Отделы</h2>
<span class="ms-2 small text-secondary">Всего: {{ departments|length }}</span>
<div class="ms-auto ios-search">
<div class="ios-search">
<i class="bi-search"></i>
<input id="deptFilter" type="search" class="ios-search-input"
placeholder="Поиск по названию или руководителю" autocomplete="off">
<button type="button" class="ios-search-clear" aria-label="Очистить">
<i class="bi-x-lg"></i>
</button>
</div>
</div>
</div>
{% if can_create_departments or perms.employees.add_department or request.user.is_staff or request.user.is_superuser %}
<div class="feed-card mb-2">
<a href="{% url 'employees:department_create' %}"
class="dept-row d-flex w-100 justify-content-center align-items-center gap-2 text-decoration-none"
role="button" aria-label="Создать отдел">
<span class="feed-author">Создать отдел</span>
<i class="bi-plus-lg"></i>
</a>
</div>
{% endif %}
{# ===== НОВАЯ ШАПКА С КОМПОНЕНТОМ ===== #}
{% include "includes/components/page_header.html" with icon="bi-diagram-3" title="Отделы" count=departments|length count_label="Всего:" search_id="deptFilter" search_placeholder="Поиск по названию или руководителю" create_as_card=True create_url=can_create_departments|yesno:"{% url 'employees:department_create' %}," create_text="Создать отдел" %}
<div class="feed-card">
<div id="deptList" class="py-1">
{# поддержка обоих форматов: dict(results) или list #}

View File

@ -5,6 +5,8 @@
{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/components/join-scroller.css' %}">
<link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
<link rel="stylesheet" href="{% static 'css/components/feed-cards.css' %}">
{% endblock %}
{% block content %}
@ -12,16 +14,8 @@
<div class="row gx-0">
<div class="col-12">
<div class="feed-header d-flex align-items-center gap-3">
<i class="bi-megaphone fs-2 text-primary"></i>
<h2 class="title mb-0">Лента</h2>
{% if user.is_authenticated and user.is_staff %}
<a class="btn btn-primary ms-auto" href="{% url 'feed:post_create' %}?type=company">
<i class="bi-plus-circle me-1"></i> Новая публикация
</a>
{% endif %}
</div>
{# ===== НОВАЯ ШАПКА С КОМПОНЕНТОМ ===== #}
{% include "includes/components/page_header.html" with icon="bi-megaphone" title="Лента" no_search=True create_url=user.is_authenticated|yesno:"{% if user.is_staff %}{% url 'feed:post_create' %}?type=company{% endif %}," create_text="Новая публикация" create_icon="bi-plus-circle" %}
{% if new_employees %}
<div class="feed-new mb-3">

View File

@ -109,7 +109,7 @@
<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 }}"
data-bs-target="#{{ create_modal }}"
role="button"
aria-label="{{ create_text|default:'Создать' }}">
<span class="feed-author">{{ create_text|default:"Создать" }}</span>

View File

@ -0,0 +1,34 @@
{# Фильтры для страницы заявлений #}
<form method="get" class="row g-2 align-items-end">
<div class="col-12 col-sm-4">
<label class="form-label mb-1">Тип</label>
<select name="type" class="form-select">
<option value="">— Любой —</option>
<option value="vacation" {% if filters.type == 'vacation' %}selected{% endif %}>Отпуск</option>
<option value="sick_leave" {% if filters.type == 'sick_leave' %}selected{% endif %}>Больничный</option>
<option value="transfer" {% if filters.type == 'transfer' %}selected{% endif %}>Перевод</option>
<option value="dismissal" {% if filters.type == 'dismissal' %}selected{% endif %}>Увольнение</option>
<option value="other" {% if filters.type == 'other' %}selected{% endif %}>Другое</option>
</select>
</div>
<div class="col-12 col-sm-4">
<label class="form-label mb-1">Статус</label>
<select name="status" class="form-select">
<option value="">— Любой —</option>
<option value="draft" {% if filters.status == 'draft' %}selected{% endif %}>Черновик</option>
<option value="pending" {% if filters.status == 'pending' %}selected{% endif %}>На рассмотрении</option>
<option value="approved" {% if filters.status == 'approved' %}selected{% endif %}>Одобрено</option>
<option value="rejected" {% if filters.status == 'rejected' %}selected{% endif %}>Отклонено</option>
<option value="cancelled" {% if filters.status == 'cancelled' %}selected{% endif %}>Отменено</option>
</select>
</div>
<div class="col-12 col-sm-4 d-flex justify-content-end gap-2">
<input type="hidden" name="view" value="{{ scope }}">
<button class="btn btn-outline-primary d-flex align-items-center justify-content-center" type="submit">
<i class="bi-funnel"></i> Применить
</button>
<a class="btn btn-outline-secondary d-flex align-items-center justify-content-center" href="?view={{ scope }}">
<i class="bi-x-lg"></i>
</a>
</div>
</form>

View File

@ -6,76 +6,15 @@
{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/components/request-list.css' %}">
<link rel="stylesheet" href="{% static 'css/components/document-list.css' %}">
<link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
<link rel="stylesheet" href="{% static 'css/components/feed-cards.css' %}">
{% endblock %}
{% block content %}
<div class="container ios-page">
{# ===== Шапка страницы ===== #}
<div class="ios-header feed-header d-flex align-items-center gap-2 flex-wrap">
<i class="bi-clipboard-check fs-2 text-primary"></i>
<h2 class="title ios-title mb-0">Заявления</h2>
<div class="ms-auto d-flex align-items-center gap-2 flex-wrap">
{% if can_process or user.is_staff or user.is_superuser %}
<!-- Переключатель области (Мои / Все) -->
<div class="btn-group scope-switch" role="group" aria-label="Область">
<a href="?view=mine{% if filters.type %}&type={{ filters.type }}{% endif %}{% if filters.status %}&status={{ filters.status }}{% endif %}"
class="btn btn-outline-secondary {% if scope == 'mine' %}active{% endif %}">
Мои
</a>
<a href="?view=all{% if filters.type %}&type={{ filters.type }}{% endif %}{% if filters.status %}&status={{ filters.status }}{% endif %}"
class="btn btn-outline-secondary {% if scope == 'all' %}active{% endif %}">
Все
</a>
</div>
{% endif %}
<!-- Кнопка создания -->
<button type="button"
class="btn btn-primary d-flex align-items-center gap-2"
data-bs-toggle="modal"
data-bs-target="#reqCreateModal">
<i class="bi-plus-lg"></i><span>Новое заявление</span>
</button>
</div>
</div>
{# ===== Фильтры ===== #}
<form class="feed-new mb-3" method="get">
<div class="row g-2 align-items-center">
<div class="col-12 col-sm-4">
<label class="form-label mb-1">Тип</label>
<select name="type" class="form-select">
<option value="">— Любой —</option>
<option value="vacation" {% if filters.type == 'vacation' %}selected{% endif %}>Отпуск</option>
<option value="sick_leave" {% if filters.type == 'sick_leave' %}selected{% endif %}>Больничный</option>
<option value="transfer" {% if filters.type == 'transfer' %}selected{% endif %}>Перевод</option>
<option value="dismissal" {% if filters.type == 'dismissal' %}selected{% endif %}>Увольнение</option>
<option value="other" {% if filters.type == 'other' %}selected{% endif %}>Другое</option>
</select>
</div>
<div class="col-12 col-sm-4">
<label class="form-label mb-1">Статус</label>
<select name="status" class="form-select">
<option value="">— Любой —</option>
<option value="draft" {% if filters.status == 'draft' %}selected{% endif %}>Черновик</option>
<option value="pending" {% if filters.status == 'pending' %}selected{% endif %}>На рассмотрении</option>
<option value="approved" {% if filters.status == 'approved' %}selected{% endif %}>Одобрено</option>
<option value="rejected" {% if filters.status == 'rejected' %}selected{% endif %}>Отклонено</option>
<option value="cancelled" {% if filters.status == 'cancelled' %}selected{% endif %}>Отменено</option>
</select>
</div>
<div class="col-12 col-sm-4 d-flex justify-content-end gap-2">
<input type="hidden" name="view" value="{{ scope }}">
<button class="btn btn-outline-primary d-flex align-items-center justify-content-center" type="submit">
<i class="bi-funnel"></i>
</button>
<a class="btn btn-outline-secondary d-flex align-items-center justify-content-center" href="?view={{ scope }}">
<i class="bi-x-lg"></i>
</a>
</div>
</div>
</form>
{# ===== НОВАЯ ШАПКА С КОМПОНЕНТОМ ===== #}
{% include "includes/components/page_header.html" with icon="bi-clipboard-check" title="Заявления" no_search=True scope_urls=can_process|yesno:"{ 'mine': '?view=mine'|add:filters.type|yesno:'&type='|add:filters.type|add:filters.status|yesno:'&status='|add:filters.status, 'all': '?view=all'|add:filters.type|yesno:'&type='|add:filters.type|add:filters.status|yesno:'&status='|add:filters.status }," scope=scope has_filters=True filters_target="reqFilters" filters_template="requests_app/_filters.html" create_modal="#reqCreateModal" create_text="Новое заявление" create_icon="bi-plus-lg" %}
{# ===== Список ===== #}
<div id="reqList" class="feed-card mb-3">