mirror of
https://github.com/avecms/AVE.cms.git
synced 2026-08-01 08:45:44 +00:00
252 lines
52 KiB
Twig
252 lines
52 KiB
Twig
{% extends '@adminx/main.twig' %}
|
||
{% block title %}Пользователи сайта{% endblock %}
|
||
{% block content %}
|
||
<nav class="breadcrumbs" aria-label="Хлебные крошки"><a href="{{ ADMINX_BASE }}/">Главная</a><i class="ti ti-chevron-right"></i><span>Пользователи сайта</span></nav>
|
||
|
||
<div class="page-header"><div><h1>Пользователи сайта</h1><p class="text-secondary">Публичные аккаунты, профили и способы входа</p></div></div>
|
||
|
||
<div class="ax-summary customers-summary">
|
||
<div class="card stat-tile"><div class="stat-ico"><i class="ti ti-users"></i></div><div><div class="stat-val">{{ stats.total }}</div><div class="stat-label">Всего</div></div></div>
|
||
<div class="card stat-tile"><div class="stat-ico is-green"><i class="ti ti-user-check"></i></div><div><div class="stat-val">{{ stats.active }}</div><div class="stat-label">Активные</div></div></div>
|
||
<div class="card stat-tile"><div class="stat-ico is-blue"><i class="ti ti-mail-check"></i></div><div><div class="stat-val">{{ stats.verified }}</div><div class="stat-label">Email подтверждён</div></div></div>
|
||
<div class="card stat-tile"><div class="stat-ico is-violet"><i class="ti ti-forms"></i></div><div><div class="stat-val">{{ stats.fields }}</div><div class="stat-label">Доп. полей</div></div></div>
|
||
</div>
|
||
|
||
<nav class="tabs customers-tabs">
|
||
<a class="tab{{ tab=='customers'?' active':'' }}" href="{{ ADMINX_BASE }}/system/customers?tab=customers"><i class="ti ti-users"></i>Пользователи</a>
|
||
<a class="tab{{ tab=='fields'?' active':'' }}" href="{{ ADMINX_BASE }}/system/customers?tab=fields"><i class="ti ti-forms"></i>Поля профиля</a>
|
||
<a class="tab{{ tab=='auth'?' active':'' }}" href="{{ ADMINX_BASE }}/system/customers?tab=auth"><i class="ti ti-user-cog"></i>Регистрация</a>
|
||
<a class="tab{{ tab=='pages'?' active':'' }}" href="{{ ADMINX_BASE }}/system/customers?tab=pages"><i class="ti ti-browser"></i>Страницы входа</a>
|
||
</nav>
|
||
|
||
{% if tab=='customers' %}
|
||
<div class="section-header ax-panel-header"><div class="section-icon"><i class="ti ti-user-search"></i></div><div><div class="section-eyebrow">Аккаунты сайта</div><h2>Пользователи</h2></div><div class="section-header-right"><form class="customers-filter"><input type="hidden" name="tab" value="customers"><div class="input-wrap"><i class="ti ti-search"></i><input class="input" type="search" name="q" value="{{ q|e }}" placeholder="Имя, email, телефон"></div><button class="btn btn-secondary"><i class="ti ti-filter"></i>Найти</button></form></div></div>
|
||
<div class="card ax-list-card">
|
||
<div class="ax-list-head"><div class="ax-list-title"><span class="icon-tile" style="--tile-bg:var(--green-100);--tile-fg:var(--green-600)"><i class="ti ti-users-group"></i></span><div><h2>Публичные аккаунты</h2><p class="text-secondary">Посетители, зарегистрированные на сайте, их контакты и доступ к личному кабинету.</p></div></div><span class="badge badge-blue">{{ customers|length }}</span></div>
|
||
<div class="table-scroll"><table class="table customers-table"><thead><tr><th>ID</th><th>Пользователь</th><th>Контакты</th><th>Компания</th><th>Регистрация</th><th>Статус</th>{% if can_manage %}<th class="customers-actions-col">Действия</th>{% endif %}</tr></thead><tbody>
|
||
{% for customer in customers %}<tr data-customer-row data-id="{{ customer.id }}"><td class="mono text-muted">{{ customer.id }}</td><td data-customer-name><b>{{ (customer.firstname ~ ' ' ~ customer.lastname)|trim ?: customer.user_name }}</b><small class="mono">{{ customer.user_name }}</small></td><td data-customer-contacts><span>{{ customer.email ?: customer.phone }}</span>{% if customer.email and customer.phone %}<small>{{ customer.phone }}</small>{% endif %}</td><td data-customer-company>{{ customer.company ?: '—' }}</td><td class="mono text-sm">{{ customer.reg_time ? customer.reg_time|date('d.m.Y') : '—' }}</td><td>{% if can_manage %}<label class="switch" data-tooltip="{{ customer.id==current_public_user_id ? 'Собственную учётную запись нельзя отключить' : 'Изменить активность' }}"><input type="checkbox" data-customer-toggle data-url="{{ ADMINX_BASE }}/system/customers/{{ customer.id }}/toggle"{{ customer.status=='1'?' checked':'' }}{{ customer.id==current_public_user_id?' disabled':'' }}><span></span></label>{% else %}<span class="badge {{ customer.status=='1'?'badge-green':'badge-gray' }}">{{ customer.status=='1'?'Активен':'Отключён' }}</span>{% endif %}</td>{% if can_manage %}<td><button class="btn btn-icon btn-ghost ax-act ax-act-edit" type="button" data-customer-edit data-url="{{ ADMINX_BASE }}/system/customers/users/{{ customer.id }}" data-tooltip="Редактировать" aria-label="Редактировать"><i class="ti ti-pencil"></i></button>{% if customer.id==current_public_user_id %}<button class="btn btn-icon btn-ghost ax-act" type="button" disabled data-tooltip="Собственную учётную запись удалить нельзя" aria-label="Удаление недоступно"><i class="ti ti-lock"></i></button>{% else %}<button class="btn btn-icon btn-ghost ax-act ax-act-danger" type="button" data-customer-delete data-url="{{ ADMINX_BASE }}/system/customers/users/{{ customer.id }}/delete" data-tooltip="Удалить" aria-label="Удалить"><i class="ti ti-trash"></i></button>{% endif %}</td>{% endif %}</tr>
|
||
{% else %}<tr><td colspan="{{ can_manage ? 7 : 6 }}"><div class="empty-state">Пользователи не найдены</div></td></tr>{% endfor %}
|
||
</tbody></table></div>
|
||
</div>
|
||
{% elseif tab=='fields' %}
|
||
<div class="section-header ax-panel-header customers-fields-head"><div class="section-icon"><i class="ti ti-forms"></i></div><div><div class="section-eyebrow">Форма профиля</div><h2>Конструктор дополнительных полей</h2><p class="section-desc">Порядок и состояние сохраняются без перезагрузки; справа показана итоговая форма пользователя.</p></div>{% if can_manage %}<div class="section-header-right"><button class="btn btn-primary" data-field-new data-open-drawer="customerFieldDrawer"><i class="ti ti-plus"></i>Добавить поле</button></div>{% endif %}</div>
|
||
|
||
<div class="customers-field-builder">
|
||
<section class="card ax-list-card customers-field-structure">
|
||
<div class="ax-list-head"><div class="ax-list-title"><span class="icon-tile" style="--tile-bg:var(--violet-100);--tile-fg:var(--violet-600)"><i class="ti ti-list-details"></i></span><div><h2>Структура профиля</h2><p class="text-secondary">Перетаскивайте поля за маркер, чтобы изменить порядок.</p></div></div><span class="badge badge-blue">{{ fields|length }}</span></div>
|
||
<div class="customers-field-list" data-fields-sortable data-reorder-url="{{ ADMINX_BASE }}/system/customers/fields/reorder">
|
||
{% for field in fields %}
|
||
<article class="customers-field-item{{ field.is_active ? '' : ' is-disabled' }}" data-field-id="{{ field.id }}" data-field='{{ field|json_encode|e('html_attr') }}'>
|
||
{% if can_manage %}<button class="customers-field-handle" type="button" draggable="true" aria-label="Изменить порядок" data-tooltip-right="Перетащить"><i class="ti ti-grip-vertical"></i></button>{% endif %}
|
||
<span class="icon-tile customers-field-icon"><i class="ti {{ field.type_icon }}"></i></span>
|
||
<div class="customers-field-copy"><b>{{ field.name }}</b><span><span class="mono">{{ field.code }}</span> · {{ field.type_label }}{% if field.is_required %} · обязательное{% endif %}</span><span class="customers-field-places">{% if field.show_registration %}<span class="badge badge-blue">Регистрация</span>{% endif %}{% if field.show_profile %}<span class="badge badge-green">Профиль</span>{% endif %}{% if not field.show_registration and not field.show_profile %}<span class="badge badge-gray">Не размещено</span>{% endif %}</span></div>
|
||
{% if can_manage %}<label class="switch customers-field-toggle" data-tooltip="Показывать поле"><input type="checkbox" data-field-toggle data-url="{{ ADMINX_BASE }}/system/customers/fields/{{ field.id }}/toggle"{{ field.is_active ? ' checked' : '' }}><span></span></label>{% else %}<span class="badge badge-{{ field.is_active ? 'green' : 'gray' }}">{{ field.is_active ? 'Включено' : 'Скрыто' }}</span>{% endif %}
|
||
{% if can_manage %}<div class="customers-field-actions"><button class="btn btn-icon btn-ghost ax-act ax-act-edit" data-field-edit data-open-drawer="customerFieldDrawer" data-tooltip="Редактировать" aria-label="Редактировать"><i class="ti ti-pencil"></i></button><button class="btn btn-icon btn-ghost ax-act ax-act-danger" data-field-delete data-url="{{ ADMINX_BASE }}/system/customers/fields/{{ field.id }}/delete" data-tooltip="Удалить" aria-label="Удалить"><i class="ti ti-trash"></i></button></div>{% endif %}
|
||
</article>
|
||
{% else %}<div class="empty-state"><i class="ti ti-forms"></i><b>Дополнительных полей пока нет</b><span>Добавьте первое поле профиля.</span></div>{% endfor %}
|
||
</div>
|
||
</section>
|
||
|
||
<aside class="card customers-profile-preview">
|
||
<div class="ax-list-head"><div class="ax-list-title"><span class="icon-tile" style="--tile-bg:var(--cyan-100);--tile-fg:var(--cyan-600)"><i class="ti ti-eye"></i></span><div><h2>Предпросмотр формы</h2><p class="text-secondary">Так активные поля увидит пользователь.</p></div></div></div>
|
||
<div class="customers-preview-form" data-fields-preview>
|
||
{% for field in fields %}
|
||
<label class="field" data-preview-field="{{ field.id }}"{{ field.is_active and field.show_profile ? '' : ' hidden' }}><span class="field-label">{{ field.name }}{% if field.is_required %} <span class="text-danger">*</span>{% endif %}</span>
|
||
{% if field.type == 'textarea' %}<textarea class="textarea" rows="3" disabled></textarea>
|
||
{% elseif field.type == 'select' %}<select class="select" disabled><option>Выберите значение</option></select>
|
||
{% elseif field.type == 'checkbox' %}<span class="switch"><input type="checkbox" disabled><span>Да / нет</span></span>
|
||
{% else %}<input class="input" type="{{ field.type in ['date','number','email','tel'] ? field.type : 'text' }}" disabled>{% endif %}
|
||
</label>
|
||
{% else %}<div class="empty-state">Добавьте поля, чтобы увидеть форму</div>{% endfor %}
|
||
</div>
|
||
</aside>
|
||
</div>
|
||
{% elseif tab=='auth' %}
|
||
<div class="section-header ax-panel-header customers-auth-head"><div class="section-icon"><i class="ti ti-user-cog"></i></div><div><div class="section-eyebrow">Публичный аккаунт</div><h2>Регистрация и личный кабинет</h2><p class="section-desc">Единые правила создания аккаунта пользователя, его активации и восстановления доступа.</p></div>{% if can_manage %}<div class="section-header-right"><button class="btn btn-primary" type="submit" form="customerAuthForm"><i class="ti ti-device-floppy"></i>Сохранить</button></div>{% endif %}</div>
|
||
|
||
<div class="alert alert-info customers-auth-note"><span class="icon-tile" style="--tile-bg:var(--blue-100);--tile-fg:var(--blue-600)"><i class="ti ti-info-circle"></i></span><div><b>Одна учётная запись для сайта и панели</b><p>Публичная группа определяет возможности на сайте. Этому же пользователю можно разрешить работу в панели управления; отдельная регистрация и второй вход не потребуются.</p></div></div>
|
||
|
||
<form class="customers-auth-form" id="customerAuthForm" data-customer-auth data-base="{{ ADMINX_BASE }}">
|
||
<section class="card customers-auth-section">
|
||
<div class="ax-list-head"><div class="ax-list-title"><span class="icon-tile" style="--tile-bg:var(--green-100);--tile-fg:var(--green-600)"><i class="ti ti-user-plus"></i></span><div><h2>Создание аккаунта</h2><p class="text-secondary">Кто может зарегистрироваться и когда станет доступен вход.</p></div></div><label class="switch" data-tooltip="Разрешить регистрацию"><input type="checkbox" name="registration_enabled" value="1"{{ auth_settings.registration_enabled ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></label></div>
|
||
<div class="customers-auth-settings-grid">
|
||
<label class="field"><span class="field-label">Активация аккаунта</span><select class="select" name="registration_mode" data-registration-mode{{ can_manage ? '' : ' disabled' }}><option value="email"{{ auth_settings.registration_mode=='email' ? ' selected' : '' }}>После подтверждения email</option><option value="now"{{ auth_settings.registration_mode=='now' ? ' selected' : '' }}>Сразу после регистрации</option><option value="byadmin"{{ auth_settings.registration_mode=='byadmin' ? ' selected' : '' }}>После одобрения администратором</option></select><span class="field-hint">Для режима одобрения включите пользователя в первом табе.</span></label>
|
||
<label class="field"><span class="field-label">Группа после регистрации</span><select class="select" name="default_group"{{ can_manage ? '' : ' disabled' }}>{% for group in customer_groups %}<option value="{{ group.id }}"{{ auth_settings.default_group==group.id ? ' selected' : '' }}>#{{ group.id }} · {{ group.name }} · {{ group.permissions_count }} разрешений</option>{% endfor %}</select><span class="field-hint">Вы сами выбираете группу, которая будет назначаться новым пользователям сайта.</span></label>
|
||
<div class="field customers-auth-fixed"><span class="field-label">Канал регистрации</span><div class="customers-auth-fixed-value"><i class="ti ti-mail"></i><span><b>Email</b><small>Телефон и SMS подключаются отдельным гейтом.</small></span></div></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="card customers-auth-section">
|
||
<div class="ax-list-head"><div class="ax-list-title"><span class="icon-tile" style="--tile-bg:var(--cyan-100);--tile-fg:var(--cyan-600)"><i class="ti ti-forms"></i></span><div><h2>Поля формы регистрации</h2><p class="text-secondary">Базовые данные аккаунта. Дополнительные поля подключаются в соседнем табе.</p></div></div></div>
|
||
<div class="customers-auth-fields" data-auth-fields>
|
||
<div class="customers-auth-fields-head"><span>Поле</span><span>Показывать</span><span>Обязательное</span></div>
|
||
<div class="customers-auth-field-row"><span><i class="ti ti-mail"></i><span><b>Email</b><small>Логин и канал подтверждения</small></span></span><span class="badge badge-blue">Всегда</span><span class="badge badge-blue">Всегда</span></div>
|
||
<div class="customers-auth-field-row"><span><i class="ti ti-user"></i><span><b>Имя</b><small>Основное имя пользователя</small></span></span><span class="badge badge-blue">Всегда</span><label class="switch"><input type="checkbox" name="require_firstname" value="1"{{ auth_settings.require_firstname ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></label></div>
|
||
<div class="customers-auth-field-row" data-auth-field-row><span><i class="ti ti-id"></i><span><b>Фамилия</b><small>Дополняет отображаемое имя</small></span></span><label class="switch"><input type="checkbox" name="show_lastname" value="1" data-auth-show{{ auth_settings.show_lastname ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></label><label class="switch"><input type="checkbox" name="require_lastname" value="1" data-auth-required{{ auth_settings.require_lastname ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></label></div>
|
||
<div class="customers-auth-field-row" data-auth-field-row><span><i class="ti ti-phone"></i><span><b>Телефон</b><small>Контакт для заказов и доставки</small></span></span><label class="switch"><input type="checkbox" name="show_phone" value="1" data-auth-show{{ auth_settings.show_phone ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></label><label class="switch"><input type="checkbox" name="require_phone" value="1" data-auth-required{{ auth_settings.require_phone ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></label></div>
|
||
<div class="customers-auth-field-row" data-auth-field-row><span><i class="ti ti-building"></i><span><b>Компания</b><small>Для корпоративных профилей</small></span></span><label class="switch"><input type="checkbox" name="show_company" value="1" data-auth-show{{ auth_settings.show_company ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></label><label class="switch"><input type="checkbox" name="require_company" value="1" data-auth-required{{ auth_settings.require_company ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></label></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="card customers-auth-section">
|
||
<div class="ax-list-head"><div class="ax-list-title"><span class="icon-tile" style="--tile-bg:var(--amber-100);--tile-fg:var(--amber-600)"><i class="ti ti-shield-lock"></i></span><div><h2>Пароль и подтверждение</h2><p class="text-secondary">Срок действия одноразовых ссылок и требования к паролю.</p></div></div></div>
|
||
<div class="customers-auth-settings-grid">
|
||
<label class="field"><span class="field-label">Минимальная длина пароля</span><input class="input" type="number" name="password_min_length" min="8" max="72" value="{{ auth_settings.password_min_length }}"{{ can_manage ? '' : ' disabled' }}></label>
|
||
<label class="field" data-auth-email-only><span class="field-label">Ссылка подтверждения, часов</span><input class="input" type="number" name="verification_hours" min="1" max="168" value="{{ auth_settings.verification_hours }}"{{ can_manage ? '' : ' disabled' }}></label>
|
||
<label class="field"><span class="field-label">Ссылка восстановления, часов</span><input class="input" type="number" name="reset_hours" min="1" max="168" value="{{ auth_settings.reset_hours }}"{{ can_manage ? '' : ' disabled' }}></label>
|
||
<label class="customers-switch-card customers-auth-reset"><span><b>Восстановление пароля</b><small>Показывать форму «Забыли пароль» и отправлять ссылку на email.</small></span><span class="switch"><input type="checkbox" name="password_reset_enabled" value="1"{{ auth_settings.password_reset_enabled ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></span></label>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="card customers-auth-section customers-checkout-registration">
|
||
<div class="ax-list-head"><div class="ax-list-title"><span class="icon-tile" style="--tile-bg:var(--violet-100);--tile-fg:var(--violet-600)"><i class="ti ti-shopping-bag-check"></i></span><div><h2>Аккаунт после заказа</h2><p class="text-secondary">Покупатель может создать тот же личный кабинет прямо при оформлении.</p></div></div><label class="switch" data-tooltip="Предлагать регистрацию в корзине"><input type="checkbox" name="checkout_registration_enabled" value="1"{{ auth_settings.checkout_registration_enabled ? ' checked' : '' }}{{ can_manage ? '' : ' disabled' }}><span></span></label></div>
|
||
<div class="customers-checkout-body">
|
||
<div class="alert alert-info customers-checkout-note"><i class="ti ti-lock-check"></i><p>Пароль по почте не отправляется. После заказа пользователь сразу входит в аккаунт и получает одноразовую ссылку, чтобы задать пароль самостоятельно.</p></div>
|
||
<div class="customers-auth-restrictions">
|
||
<label class="field"><span class="field-label">URL политики</span><span class="input-wrap"><i class="ti ti-link"></i><input class="input" name="checkout_policy_url" value="{{ auth_settings.checkout_policy_url }}" placeholder="/privacy-policy"{{ can_manage ? '' : ' disabled' }}></span><span class="field-hint">Только внутренний адрес сайта.</span></label>
|
||
<label class="field"><span class="field-label">Текст согласия</span><input class="input" name="checkout_policy_label" value="{{ auth_settings.checkout_policy_label }}" maxlength="300"{{ can_manage ? '' : ' disabled' }}></label>
|
||
</div>
|
||
<label class="field"><span class="field-label">Тема письма после заказа</span><input class="input" name="checkout_access_subject" value="{{ auth_settings.checkout_access_subject }}" maxlength="190"{{ can_manage ? '' : ' disabled' }}></label>
|
||
<div class="customers-checkout-template-head"><div><b>Письмо с доступом</b><small>HTML и Twig. Нажмите тег, чтобы вставить его в позицию курсора.</small></div>{% if can_manage %}<button class="btn btn-icon btn-ghost" type="button" data-checkout-template-default data-template="{{ checkout_access_template_default|e('html_attr') }}" data-tooltip="Вернуть штатный шаблон" aria-label="Вернуть штатный шаблон"><i class="ti ti-restore"></i></button>{% endif %}</div>
|
||
<textarea class="textarea mono" name="checkout_access_template" data-code-editor data-mode="htmlmixed" data-height="320"{{ can_manage ? '' : ' disabled' }}>{{ auth_settings.checkout_access_template }}</textarea>
|
||
<span class="code-template-tags customers-checkout-template-tags" data-code-editor-tags="checkout_access_template">
|
||
{% for value,description in {'{{ user.firstname }}':'Имя пользователя','{{ user.lastname }}':'Фамилия','{{ user.email }}':'Email и логин','{{ order.id }}':'Номер заказа','{{ order.total }}':'Сумма заказа','{{ access_url }}':'Одноразовая ссылка задания пароля','{{ expires_hours }}':'Срок ссылки в часах'} %}<button type="button" data-code-editor-tag="{{ value|e('html_attr') }}" data-tooltip="{{ description }}"><code>{{ value }}</code><span>{{ description }}</span></button>{% endfor %}
|
||
</span>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="card customers-auth-section">
|
||
<div class="ax-list-head"><div class="ax-list-title"><span class="icon-tile" style="--tile-bg:var(--red-100);--tile-fg:var(--red-600)"><i class="ti ti-shield-x"></i></span><div><h2>Ограничения регистрации</h2><p class="text-secondary">Один email или домен на строку. Проверка не зависит от регистра букв.</p></div></div></div>
|
||
<div class="customers-auth-restrictions"><label class="field"><span class="field-label">Запрещённые домены</span><textarea class="textarea mono" name="deny_domains" rows="5" placeholder="example.org mail.invalid"{{ can_manage ? '' : ' disabled' }}>{{ auth_settings.deny_domains|e }}</textarea></label><label class="field"><span class="field-label">Запрещённые адреса</span><textarea class="textarea mono" name="deny_emails" rows="5" placeholder="blocked@example.org"{{ can_manage ? '' : ' disabled' }}>{{ auth_settings.deny_emails|e }}</textarea></label></div>
|
||
</section>
|
||
|
||
{% if can_manage %}<div class="customers-auth-actions"><button class="btn btn-primary" type="submit"><i class="ti ti-device-floppy"></i>Сохранить настройки</button></div>{% endif %}
|
||
</form>
|
||
|
||
{% if oauth_modules %}
|
||
<div class="section-header customers-social-head">
|
||
<div class="section-icon"><i class="ti ti-login-2"></i></div>
|
||
<div><div class="section-eyebrow">Авторизация</div><h2>Подключённые способы входа</h2><p class="section-desc">OAuth и вход по одноразовому коду используют одну учётную запись сайта.</p></div>
|
||
<div class="section-header-right"><span class="badge badge-blue">{{ oauth_modules|length }} подключено</span></div>
|
||
</div>
|
||
<div class="customers-social-grid">
|
||
{% for provider in oauth_modules %}
|
||
<section class="card customers-social-card">
|
||
<div class="ax-list-head">
|
||
<div class="ax-list-title"><span class="customers-social-mark {{ provider.brand }}">{{ provider.mark }}</span><div><h3>{{ provider.label }}</h3><p class="text-secondary">{{ provider.description }}</p></div></div>
|
||
<span class="badge {{ provider.state.badge }}">{{ provider.state.label }}</span>
|
||
</div>
|
||
<div class="customers-social-status">
|
||
<div class="customers-social-checks">
|
||
<span class="{{ provider.module_enabled ? 'is-ready' : '' }}"><i class="ti {{ provider.module_enabled ? 'ti-circle-check' : 'ti-circle-x' }}"></i>Модуль включён</span>
|
||
<span class="{{ provider.configured ? 'is-ready' : '' }}"><i class="ti {{ provider.configured ? 'ti-key' : 'ti-key-off' }}"></i>Ключи настроены</span>
|
||
<span class="{{ provider.allow_registration ? 'is-ready' : '' }}"><i class="ti ti-user-plus"></i>Регистрация {{ provider.allow_registration ? 'разрешена' : 'выключена' }}</span>
|
||
</div>
|
||
{% if provider.can_open %}<a class="btn btn-secondary btn-sm" href="{{ ADMINX_BASE }}{{ provider.url }}"><i class="ti ti-settings"></i>Настроить</a>{% endif %}
|
||
</div>
|
||
</section>
|
||
{% endfor %}
|
||
</div>
|
||
{% else %}
|
||
<div class="alert alert-info customers-auth-note"><span class="icon-tile" style="--tile-bg:var(--blue-100);--tile-fg:var(--blue-600)"><i class="ti ti-plug-connected"></i></span><div><b>Дополнительные способы входа устанавливаются модулями</b><p>Яндекс, VK ID и SMSC настраиваются отдельно в разделе «Модули». Удаление пакета физически убирает его код и форму настроек.</p></div><a class="btn btn-secondary" href="{{ ADMINX_BASE }}/modules"><i class="ti ti-puzzle"></i>Открыть модули</a></div>
|
||
{% endif %}
|
||
{% else %}
|
||
<div class="section-header ax-panel-header customers-pages-head"><div class="section-icon"><i class="ti ti-browser"></i></div><div><div class="section-eyebrow">Публичный сайт</div><h2>Страницы личного кабинета</h2><p class="section-desc">Каждая страница имеет редактируемый Twig-шаблон и выводится через `[tag:maincontent]` внутри выбранного шаблона сайта.</p></div>{% if can_manage %}<div class="section-header-right"><button class="btn btn-primary" type="submit" form="customerPagesForm"><i class="ti ti-device-floppy"></i>Сохранить</button></div>{% endif %}</div>
|
||
|
||
<div class="alert alert-info customers-auth-note"><span class="icon-tile" style="--tile-bg:var(--cyan-100);--tile-fg:var(--cyan-600)"><i class="ti ti-route"></i></span><div><b>Старые адреса продолжат работать</b><p>После смены URL системные `/login`, `/register`, `/remember`, `/password/reset` и `/personal` останутся совместимыми алиасами. Новые ссылки в интерфейсе и письмах сразу начнут использовать заданные адреса.</p></div></div>
|
||
|
||
<form class="customers-pages-form" id="customerPagesForm" data-customer-pages data-base="{{ ADMINX_BASE }}">
|
||
<div class="customers-pages-grid">
|
||
{% for key in ['login','register','remember','reset','overview','profile','password'] %}
|
||
{% set settings = auth_settings.pages[key] %}{% set form_meta = auth_forms[key] %}
|
||
<section class="card customers-page-card">
|
||
<div class="customers-page-card-head"><span class="icon-tile" style="--tile-bg:var(--{{ form_meta.tile }}-100);--tile-fg:var(--{{ form_meta.tile }}-600)"><i class="ti {{ form_meta.icon }}"></i></span><div class="customers-page-card-copy"><h3>{{ form_meta.label }}</h3><span>{{ form_meta.description }}</span></div><div class="customers-page-card-actions">{% if can_manage %}<button class="btn btn-icon btn-ghost ax-act ax-act-edit" type="button" data-auth-form-edit="{{ key }}" data-tooltip="Редактировать форму" aria-label="Редактировать форму"><i class="ti ti-code"></i></button>{% endif %}<a class="btn btn-icon btn-ghost ax-act ax-act-view" href="{{ settings.path }}?_auth_preview=1" target="_blank" rel="noopener" data-tooltip="Предпросмотр" aria-label="Открыть предпросмотр"><i class="ti ti-external-link"></i></a></div></div>
|
||
<div class="customers-page-fields"><label class="field"><span class="field-label">Публичный URL</span><span class="input-wrap"><i class="ti ti-link"></i><input class="input mono" name="pages[{{ key }}][path]" value="{{ settings.path }}" required></span></label><label class="field"><span class="field-label">Шаблон сайта</span><select class="select" name="pages[{{ key }}][template_id]" required>{% for template in page_templates %}<option value="{{ template.id }}"{{ template.id == settings.template_id ? ' selected' : '' }}>#{{ template.id }} · {{ template.title }}</option>{% endfor %}</select></label><label class="field"><span class="field-label">Заголовок</span><input class="input" name="pages[{{ key }}][title]" value="{{ settings.title }}" required></label><label class="field"><span class="field-label">Кнопка</span><input class="input" name="pages[{{ key }}][submit_label]" value="{{ settings.submit_label }}" required></label><label class="field"><span class="field-label">Описание</span><textarea class="textarea" name="pages[{{ key }}][description]" rows="2">{{ settings.description }}</textarea></label></div>
|
||
</section>
|
||
{% endfor %}
|
||
</div>
|
||
<section class="card customers-auth-section customers-service-routes"><div class="ax-list-head"><div class="ax-list-title"><span class="icon-tile" style="--tile-bg:var(--gray-100);--tile-fg:var(--gray-700)"><i class="ti ti-code"></i></span><div><h2>Служебные маршруты</h2><p class="text-secondary">Подтверждение email, выход и общий шаблон системных результатов.</p></div></div>{% if can_manage %}<div class="customers-service-actions"><button class="btn btn-secondary btn-sm" type="button" data-auth-form-edit="message"><i class="ti ti-message-circle-check"></i>Сообщения</button></div>{% endif %}</div><div class="customers-auth-restrictions"><label class="field"><span class="field-label">Подтверждение email</span><span class="input-wrap"><i class="ti ti-link"></i><input class="input mono" name="pages[verify][path]" value="{{ auth_settings.pages.verify.path }}" required></span><input type="hidden" name="pages[verify][title]" value=""><input type="hidden" name="pages[verify][description]" value=""><input type="hidden" name="pages[verify][submit_label]" value=""><input type="hidden" name="pages[verify][template_id]" value="1"></label><label class="field"><span class="field-label">Выход</span><span class="input-wrap"><i class="ti ti-link"></i><input class="input mono" name="pages[logout][path]" value="{{ auth_settings.pages.logout.path }}" required></span><input type="hidden" name="pages[logout][title]" value=""><input type="hidden" name="pages[logout][description]" value=""><input type="hidden" name="pages[logout][submit_label]" value=""><input type="hidden" name="pages[logout][template_id]" value="1"></label></div></section>
|
||
{% if can_manage %}<div class="customers-auth-actions"><button class="btn btn-primary" type="submit"><i class="ti ti-device-floppy"></i>Сохранить страницы</button></div>{% endif %}
|
||
</form>
|
||
{% endif %}
|
||
|
||
{% if can_manage %}
|
||
<aside class="drawer drawer-right customer-editor-drawer" id="customerEditorDrawer" role="dialog" aria-modal="true" aria-labelledby="customerEditorTitle" hidden>
|
||
<div class="drawer-header"><div><h3 id="customerEditorTitle" data-customer-editor-title>Пользователь сайта</h3><p>Профиль, доступ и данные личного кабинета</p></div><button class="btn btn-icon btn-ghost" type="button" data-close-drawer aria-label="Закрыть"><i class="ti ti-x"></i></button></div>
|
||
<form data-customer-editor data-base="{{ ADMINX_BASE }}" data-can-manage-admin-access="{{ can_manage_admin_access ? '1' : '0' }}">
|
||
<div class="drawer-body">
|
||
<div class="customers-editor-meta"><span><i class="ti ti-id"></i><b data-customer-meta-id>#—</b></span><span><i class="ti ti-user-plus"></i><b data-customer-meta-created>—</b><small>Регистрация</small></span><span><i class="ti ti-clock"></i><b data-customer-meta-visit>—</b><small>Последний вход</small></span></div>
|
||
<div class="customers-editor-sections">
|
||
<section class="customers-form-section"><div class="customers-form-section-head"><span class="icon-tile" style="--tile-bg:var(--blue-100);--tile-fg:var(--blue-600)"><i class="ti ti-user"></i></span><div><b>Основные данные</b><span>Имя, контакты и данные организации.</span></div></div><div class="form-grid"><label class="field col-6"><span class="field-label">Имя</span><span class="input-wrap customers-editor-input"><i class="ti ti-user"></i><input class="input" name="firstname" maxlength="50"></span></label><label class="field col-6"><span class="field-label">Фамилия</span><span class="input-wrap customers-editor-input"><i class="ti ti-user"></i><input class="input" name="lastname" maxlength="50"></span></label><label class="field col-6"><span class="field-label">Email</span><span class="input-wrap customers-editor-input"><i class="ti ti-mail"></i><input class="input" type="email" name="email" maxlength="100" required></span></label><label class="field col-6"><span class="field-label">Логин</span><span class="input-wrap customers-editor-input"><i class="ti ti-at"></i><input class="input mono" name="user_name" maxlength="50" required></span><span class="field-hint">Можно использовать для входа наравне с email.</span></label><label class="field col-6"><span class="field-label">Телефон</span><span class="input-wrap customers-editor-input"><i class="ti ti-phone"></i><input class="input" type="tel" name="phone" maxlength="50"></span></label><label class="field col-6"><span class="field-label">Компания</span><span class="input-wrap customers-editor-input"><i class="ti ti-building"></i><input class="input" name="company" maxlength="255"></span></label><label class="field col-4"><span class="field-label">Дата рождения</span><span class="input-wrap customers-editor-input"><i class="ti ti-calendar"></i><input class="input" type="date" name="birthday"></span></label><label class="field col-8"><span class="field-label">О пользователе</span><textarea class="textarea" name="description" rows="2"></textarea></label></div></section>
|
||
<section class="customers-form-section"><div class="customers-form-section-head"><span class="icon-tile" style="--tile-bg:var(--cyan-100);--tile-fg:var(--cyan-600)"><i class="ti ti-map-pin"></i></span><div><b>Адрес</b><span>Данные для профиля и предзаполнения заказов.</span></div></div><div class="form-grid"><label class="field col-4"><span class="field-label">Город</span><span class="input-wrap customers-editor-input"><i class="ti ti-building-community"></i><input class="input" name="city"></span></label><label class="field col-4"><span class="field-label">Улица</span><span class="input-wrap customers-editor-input"><i class="ti ti-road"></i><input class="input" name="street"></span></label><label class="field col-2"><span class="field-label">Дом</span><span class="input-wrap customers-editor-input"><i class="ti ti-home"></i><input class="input" name="street_nr"></span></label><label class="field col-2"><span class="field-label">Индекс</span><span class="input-wrap customers-editor-input"><i class="ti ti-mailbox"></i><input class="input" name="zipcode"></span></label></div></section>
|
||
<section class="customers-form-section">
|
||
<div class="customers-form-section-head"><span class="icon-tile" style="--tile-bg:var(--green-100);--tile-fg:var(--green-600)"><i class="ti ti-shield-check"></i></span><div><b>Доступ</b><span>Публичная группа, состояние аккаунта и роль в панели управления.</span></div></div>
|
||
<div class="form-grid">
|
||
<label class="field col-6"><span class="field-label">Группа публичных пользователей</span><select class="select" name="user_group" required>{% for group in customer_groups %}<option value="{{ group.id }}">#{{ group.id }} · {{ group.name }} · {{ group.permissions_count }} разрешений</option>{% endfor %}</select><span class="field-hint" data-customer-group-hint>Определяет права пользователя на публичной части сайта.</span></label>
|
||
<label class="field col-6" data-customer-admin-role><span class="field-label">Роль в панели управления</span><select class="select" name="admin_role"{{ can_manage_admin_access ? '' : ' disabled' }}>{% for code, label in admin_roles %}<option value="{{ code }}">{{ label }}</option>{% endfor %}</select><span class="field-hint" data-customer-admin-role-hint>Права роли настраиваются в разделе «Роли и права».</span></label>
|
||
</div>
|
||
<div class="customers-switch-grid customers-editor-access">
|
||
<label class="customers-switch-card" data-customer-account-card><span><b>Аккаунт включён</b><small data-customer-account-hint>Может входить на сайт и в личный кабинет.</small></span><span class="switch"><input type="checkbox" name="status" value="1"><span></span></span></label>
|
||
<label class="customers-switch-card" data-customer-admin-card><span><b>Доступ в панель управления</b><small data-customer-admin-hint>{{ can_manage_admin_access ? 'Та же учётная запись сможет работать в административном интерфейсе.' : 'Изменение требует права управления системными пользователями.' }}</small></span><span class="switch"><input type="checkbox" name="admin_access" value="1" data-customer-admin-access{{ can_manage_admin_access ? '' : ' disabled' }}><span></span></span></label>
|
||
<label class="customers-switch-card"><span><b>Email подтверждён</b><small>Администратор может изменить статус вручную.</small></span><span class="switch"><input type="checkbox" name="email_verified" value="1"><span></span></span></label>
|
||
<label class="customers-switch-card"><span><b>Телефон подтверждён</b><small>Подготовлено для будущего SMS-гейта.</small></span><span class="switch"><input type="checkbox" name="phone_verified" value="1"><span></span></span></label>
|
||
</div>
|
||
</section>
|
||
{% if fields %}<section class="customers-form-section"><div class="customers-form-section-head"><span class="icon-tile" style="--tile-bg:var(--violet-100);--tile-fg:var(--violet-600)"><i class="ti ti-forms"></i></span><div><b>Дополнительные поля</b><span>Активные поля из конструктора публичного профиля.</span></div></div><div class="form-grid">{% for field in fields %}{% if field.is_active %}<label class="field col-6"><span class="field-label">{{ field.name }}{% if field.is_required %} <span class="text-danger">*</span>{% endif %}</span>{% if field.type=='textarea' %}<textarea class="textarea" name="extra[{{ field.id }}]" rows="3"{{ field.is_required?' required':'' }}></textarea>{% elseif field.type=='select' %}<select class="select" name="extra[{{ field.id }}]"{{ field.is_required?' required':'' }}><option value="">Выберите значение</option>{% for choice in field.choices %}<option value="{{ choice|e('html_attr') }}">{{ choice }}</option>{% endfor %}</select>{% elseif field.type=='checkbox' %}<span class="customers-editor-checkbox"><span class="switch"><input type="checkbox" name="extra[{{ field.id }}]" value="1"><span></span></span><span>Да / нет</span></span>{% else %}<input class="input" type="{{ field.type in ['date','number','email','tel'] ? field.type : 'text' }}" name="extra[{{ field.id }}]"{{ field.is_required?' required':'' }}>{% endif %}<span class="field-hint mono">{{ field.code }}</span></label>{% endif %}{% endfor %}</div></section>{% endif %}
|
||
<section class="customers-form-section"><div class="customers-form-section-head"><span class="icon-tile" style="--tile-bg:var(--red-100);--tile-fg:var(--red-600)"><i class="ti ti-key"></i></span><div><b>Безопасность</b><span>Пароль изменится, только если заполнить поле.</span></div></div><label class="field customers-editor-password"><span class="field-label">Новый пароль</span><span class="input-wrap customers-editor-input"><i class="ti ti-lock"></i><input class="input" type="password" name="password" autocomplete="new-password" placeholder="Оставьте пустым, чтобы не менять"></span><span class="field-hint">При смене пароля будут отозваны remember-сессии и ссылки восстановления.</span></label></section>
|
||
</div>
|
||
</div>
|
||
<footer class="drawer-footer"><button class="btn btn-secondary" type="button" data-close-drawer>Закрыть</button><button class="btn btn-primary" type="submit"><i class="ti ti-device-floppy"></i>Сохранить</button></footer>
|
||
</form>
|
||
</aside>
|
||
|
||
<aside class="drawer drawer-right customer-field-drawer" id="customerFieldDrawer" role="dialog" aria-modal="true" hidden>
|
||
<div class="drawer-header"><div><h3 data-field-title>Новое поле</h3><p>Настройка поля публичного профиля</p></div><button class="btn btn-icon btn-ghost" data-close-drawer aria-label="Закрыть"><i class="ti ti-x"></i></button></div>
|
||
<form data-customer-field data-base="{{ ADMINX_BASE }}">
|
||
<div class="drawer-body"><div class="customers-field-form">
|
||
<section class="customers-form-section"><div class="customers-form-section-head"><span class="icon-tile"><i class="ti ti-forms"></i></span><div><b>Основные параметры</b><span>Название, системный код и способ ввода.</span></div></div><div class="form-grid"><label class="field col-6"><span class="field-label">Название</span><input class="input" name="name" required></label><label class="field col-6"><span class="field-label">Код</span><input class="input mono" name="code" pattern="[a-z][a-z0-9_]+" required><span class="field-hint">Используется в API и шаблонах.</span></label><label class="field col-6"><span class="field-label">Тип поля</span><select class="select" name="type"><option value="text">Однострочный текст</option><option value="textarea">Многострочный текст</option><option value="select">Список значений</option><option value="checkbox">Переключатель</option><option value="date">Дата</option><option value="number">Число</option><option value="email">Email</option><option value="tel">Телефон</option></select></label><label class="field col-3"><span class="field-label">Порядок</span><input class="input" type="number" name="position" min="0" value="0"></label></div></section>
|
||
<section class="customers-form-section" data-field-options-section hidden><div class="customers-form-section-head"><span class="icon-tile" style="--tile-bg:var(--amber-100);--tile-fg:var(--amber-600)"><i class="ti ti-list"></i></span><div><b>Варианты списка</b><span>Каждый вариант отображается отдельной строкой.</span></div><button class="btn btn-secondary btn-sm" type="button" data-field-option-add><i class="ti ti-plus"></i>Вариант</button></div><input type="hidden" name="options"><div class="customers-options" data-field-options></div></section>
|
||
<section class="customers-form-section"><div class="customers-form-section-head"><span class="icon-tile" style="--tile-bg:var(--green-100);--tile-fg:var(--green-600)"><i class="ti ti-adjustments"></i></span><div><b>Поведение</b><span>Правила заполнения и области показа поля.</span></div></div><div class="customers-switch-grid"><label class="customers-switch-card"><span><b>Обязательное поле</b><small>Значение потребуется во всех выбранных формах.</small></span><span class="switch"><input type="checkbox" name="is_required" value="1"><span></span></span></label><label class="customers-switch-card"><span><b>Поле включено</b><small>Отключённое поле скрывается во всех формах.</small></span><span class="switch"><input type="checkbox" name="is_active" value="1" checked><span></span></span></label><label class="customers-switch-card"><span><b>Показывать при регистрации</b><small>Собрать значение во время создания аккаунта.</small></span><span class="switch"><input type="checkbox" name="show_registration" value="1"><span></span></span></label><label class="customers-switch-card"><span><b>Показывать в профиле</b><small>Разрешить заполнение и изменение в личном кабинете.</small></span><span class="switch"><input type="checkbox" name="show_profile" value="1" checked><span></span></span></label></div></section>
|
||
</div></div>
|
||
<footer class="drawer-footer"><button class="btn btn-secondary" type="button" data-close-drawer>Закрыть</button><button class="btn btn-primary" type="submit"><i class="ti ti-device-floppy"></i>Сохранить</button></footer>
|
||
</form>
|
||
</aside>
|
||
|
||
<aside class="drawer drawer-right customer-auth-form-drawer" id="customerAuthFormDrawer" role="dialog" aria-modal="true" hidden>
|
||
<div class="drawer-header"><div><h3 data-auth-form-title>Шаблон страницы</h3><p data-auth-form-description>Публичная Twig-разметка</p></div><button class="btn btn-icon btn-ghost" type="button" data-close-drawer aria-label="Закрыть"><i class="ti ti-x"></i></button></div>
|
||
<form data-auth-form-template data-base="{{ ADMINX_BASE }}">
|
||
<input type="hidden" name="key" value="">
|
||
<div class="drawer-body customers-auth-template-body">
|
||
<div class="customers-auth-template-layout">
|
||
<section class="customers-auth-template-editor">
|
||
<div class="customers-auth-template-toolbar"><span data-auth-form-state class="badge badge-neutral">Штатный шаблон</span><div><button class="btn btn-secondary btn-sm" type="button" data-auth-form-reset><i class="ti ti-restore"></i>Восстановить штатный</button><button class="btn btn-icon btn-ghost" type="button" data-auth-template-fullscreen data-tooltip="На весь экран" aria-label="Развернуть редактор"><i class="ti ti-arrows-maximize"></i></button></div></div>
|
||
<label class="field customers-auth-template-code"><span class="field-label">Twig-шаблон страницы</span><textarea class="textarea mono" name="template" data-code-editor data-mode="htmlmixed" data-height="620" required></textarea><span class="field-error" data-auth-form-error></span></label>
|
||
</section>
|
||
<aside class="customers-auth-template-help">
|
||
<div><span class="icon-tile" style="--tile-bg:var(--cyan-100);--tile-fg:var(--cyan-600)"><i class="ti ti-braces"></i></span><div><b>Доступные данные</b><span>Нажмите, чтобы вставить выражение в редактор.</span></div></div>
|
||
<div class="customers-auth-template-tags">
|
||
<button type="button" data-auth-template-tag="{{ '{{ page.title }}' }}"><code>{{ '{{ page.title }}' }}</code><span>Заголовок страницы</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ page.description }}' }}"><code>{{ '{{ page.description }}' }}</code><span>Описание</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ page.submit_label }}' }}"><code>{{ '{{ page.submit_label }}' }}</code><span>Подпись кнопки</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ csrf|e }}' }}"><code>{{ '{{ csrf|e }}' }}</code><span>CSRF-токен</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ base }}' }}"><code>{{ '{{ base }}' }}</code><span>Базовый URL</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ auth_urls.login }}' }}"><code>{{ '{{ auth_urls.login }}' }}</code><span>URL входа</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{% for provider in oauth_providers %}\n\t{{ provider.label }}\n{% endfor %}' }}"><code>oauth_providers</code><span>Активные гейты Яндекс/VK</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ errors._form }}' }}"><code>{{ '{{ errors._form }}' }}</code><span>Ошибка формы</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{% for field in fields %}\n\t{{ field.name }}\n{% endfor %}' }}"><code>fields</code><span>Дополнительные поля</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ user.firstname }}' }}"><code>{{ '{{ user.firstname }}' }}</code><span>Имя пользователя</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ orders_total }}' }}"><code>{{ '{{ orders_total }}' }}</code><span>Всего заказов · обзор</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ orders_paid }}' }}"><code>{{ '{{ orders_paid }}' }}</code><span>Оплачено · обзор</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{{ favorites_count }}' }}"><code>{{ '{{ favorites_count }}' }}</code><span>В избранном · обзор</span></button>
|
||
<button type="button" data-auth-template-tag="{{ '{% for order in orders %}\n\t{{ order.order_id }} · {{ order.order_total }}\n{% endfor %}' }}"><code>orders</code><span>Последние заказы · обзор</span></button>
|
||
</div>
|
||
<div class="alert alert-info customers-auth-template-note"><i class="ti ti-shield-check"></i><p>Разметка и CSS-классы редактируются здесь. Маршруты, проверка данных, CSRF и сохранение пользователей остаются в системном обработчике.</p></div>
|
||
</aside>
|
||
</div>
|
||
</div>
|
||
<footer class="drawer-footer"><button class="btn btn-secondary" type="button" data-close-drawer>Закрыть</button><button class="btn btn-primary" type="submit" data-code-save-stay><i class="ti ti-device-floppy"></i>Сохранить шаблон</button></footer>
|
||
</form>
|
||
</aside>
|
||
{% endif %}
|
||
{% endblock %}
|