150 lines
11 KiB
HTML
150 lines
11 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru" xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/base :: layout(~{::title}, ~{::#content})}">
|
||
<head><title th:text="${section.title} + ' — LMS'">Раздел</title></head>
|
||
<body>
|
||
<div id="content" th:attr="data-csrf=${csrfToken},data-sort-scope='section',data-section-id=${section.id}">
|
||
<nav class="text-sm mb-4 breadcrumb">
|
||
<a th:href="@{/learn}" class="nav-link">Материалы</a>
|
||
<span class="nav-sep">/</span>
|
||
<a th:href="@{/learn/{c}(c=${chapter.slug})}" class="nav-link" th:text="${chapter.title}">Глава</a>
|
||
<span class="nav-sep">/</span>
|
||
<span th:text="${section.title}">Раздел</span>
|
||
</nav>
|
||
|
||
<h1 class="page-title">
|
||
<span th:text="${section.title}">Раздел</span>
|
||
<span th:if="${!section.published}" class="badge badge-warn ml-2">скрыто</span>
|
||
</h1>
|
||
|
||
<div th:if="${currentUser != null and currentUser.admin}" class="flex flex-wrap gap-2 mb-4 action-row">
|
||
<button class="btn btn-primary" type="button" data-modal="modal-new-article">+ Статья</button>
|
||
<button class="btn btn-secondary btn-sm p-2" type="button" data-modal="modal-rename-section" title="Переименовать раздел" aria-label="Переименовать раздел"><i class="cell-ico ico bi bi-pencil" aria-hidden="true"></i></button>
|
||
<form class="inline-form" th:action="@{/admin/content/sections/toggle-published}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="id" th:value="${section.id}">
|
||
<input type="hidden" name="published" th:value="${!section.published}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<button class="btn btn-secondary btn-sm p-2" type="submit" th:if="${section.published}" title="Скрыть раздел" aria-label="Скрыть раздел"><i class="cell-ico ico bi bi-eye" aria-hidden="true"></i></button>
|
||
<button class="btn btn-secondary btn-sm p-2" type="submit" th:unless="${section.published}" title="Опубликовать раздел" aria-label="Опубликовать раздел"><i class="cell-ico ico bi bi-eye-slash" aria-hidden="true"></i></button>
|
||
</form>
|
||
<button class="btn btn-secondary btn-sm p-2" type="button" data-modal="modal-move-section" title="Перенести статьи и удалить" aria-label="Перенести статьи и удалить"><i class="cell-ico ico bi bi-arrow-left-right" aria-hidden="true"></i></button>
|
||
<form class="inline-form" th:action="@{/admin/content/sections/{id}/delete(id=${section.id})}" method="post" data-confirm="Удалить раздел вместе со статьями?">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="back" th:value="${backParent}">
|
||
<button class="btn btn-danger btn-sm p-2" type="submit" title="Удалить раздел вместе со статьями" aria-label="Удалить раздел вместе со статьями"><i class="cell-ico ico bi bi-trash" aria-hidden="true"></i></button>
|
||
</form>
|
||
</div>
|
||
|
||
<div th:if="${currentUser != null and currentUser.admin}" class="card card-body text-sm text-muted mb-4">
|
||
Перетаскивайте статьи за значок руки, чтобы менять их порядок. Порядок сохраняется сразу.
|
||
</div>
|
||
<div th:if="${currentUser != null and currentUser.admin}" id="sort-status" class="sort-status" hidden>
|
||
<span id="sort-status-text">Изменения не сохранены…</span>
|
||
</div>
|
||
|
||
<div class="card card-flush">
|
||
<table>
|
||
<thead><tr><th>Статья</th><th class="th-w-md" data-nosort>Действия</th></tr></thead>
|
||
<tbody data-article-list>
|
||
<tr th:each="article : ${section.articles}" th:attr="data-article-id=${article.id}">
|
||
<td>
|
||
<span th:if="${currentUser != null and currentUser.admin}" class="drag-handle" draggable="true"
|
||
th:attr="data-drag-kind='article',data-drag-id=${article.id}"
|
||
title="Перетащите, чтобы изменить порядок статей"><i class="bi bi-grip-vertical"></i></span>
|
||
<a th:href="@{/learn/{c}/{s}/{a}(c=${chapter.slug}, s=${section.slug}, a=${article.slug})}"
|
||
th:text="${article.title}">—</a>
|
||
<span th:if="${!article.published}" class="badge badge-warn ml-1">скрыто</span>
|
||
</td>
|
||
<td class="text-right actions-cell">
|
||
<a class="btn btn-secondary btn-sm p-2" title="Править статью" aria-label="Править статью"
|
||
th:href="@{/learn/{c}/{s}/{a}(c=${chapter.slug}, s=${section.slug}, a=${article.slug}, edit=1)}"><i class="ico bi bi-pencil" aria-hidden="true"></i></a>
|
||
<form class="inline-form" th:action="@{/admin/content/articles/toggle-published}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="id" th:value="${article.id}">
|
||
<input type="hidden" name="published" th:value="${!article.published}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<button class="btn btn-secondary btn-sm p-2" type="submit" th:if="${article.published}" title="Скрыть статью" aria-label="Скрыть статью"><i class="cell-ico ico bi bi-eye" aria-hidden="true"></i></button>
|
||
<button class="btn btn-secondary btn-sm p-2" type="submit" th:unless="${article.published}" title="Опубликовать статью" aria-label="Опубликовать статью"><i class="cell-ico ico bi bi-eye-slash" aria-hidden="true"></i></button>
|
||
</form>
|
||
<form class="inline-form" th:action="@{/admin/content/articles/{id}/delete(id=${article.id})}" method="post" data-confirm="Удалить статью?">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<button class="btn btn-danger" type="submit">Удалить</button>
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
<tr th:if="${#lists.isEmpty(section.articles)}"><td colspan="2" class="empty">Статей пока нет.</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<dialog id="modal-rename-section" class="dlg">
|
||
<div class="dlg-header">
|
||
<h2 class="dlg-title">Переименовать раздел</h2>
|
||
<button class="dlg-close" type="button" aria-label="Закрыть">✕</button>
|
||
</div>
|
||
<div class="dlg-body">
|
||
<form class="form-stack" th:action="@{/admin/content/sections/{id}/rename(id=${section.id})}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<div><label class="label" for="secTitle">Название</label>
|
||
<input class="input" id="secTitle" name="title" th:value="${section.title}" required></div>
|
||
<button class="btn btn-primary" type="submit">Сохранить</button>
|
||
</form>
|
||
</div>
|
||
</dialog>
|
||
|
||
<dialog id="modal-move-section" class="dlg">
|
||
<div class="dlg-header">
|
||
<h2 class="dlg-title">Перенести статьи и удалить раздел</h2>
|
||
<button class="dlg-close" type="button" aria-label="Закрыть">✕</button>
|
||
</div>
|
||
<div class="dlg-body">
|
||
<form class="form-stack" th:action="@{/admin/content/sections/{id}/delete(id=${section.id})}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="back" th:value="${backParent}">
|
||
<p class="text-sm text-muted">Выберите раздел-приёмник: его статьи перенесутся туда, а текущий раздел удалится.</p>
|
||
<p th:if="${#lists.size(sectionChoices) < 2}" class="text-sm text-muted">
|
||
<b>Других разделов нет</b> — при подтверждении статьи будут удалены вместе с разделом.
|
||
</p>
|
||
<div><label class="label" for="moveTo">Перенести в раздел</label>
|
||
<select class="input" id="moveTo" name="moveTo">
|
||
<option th:each="pair : ${sectionChoices}"
|
||
th:if="${pair['id'] != section.id}"
|
||
th:value="${pair['id']}" th:text="${pair['label']}">—</option>
|
||
</select></div>
|
||
<button class="btn btn-primary" type="submit">Перенести и удалить</button>
|
||
</form>
|
||
</div>
|
||
</dialog>
|
||
|
||
<dialog id="modal-new-article" class="dlg">
|
||
<div class="dlg-header">
|
||
<h2 class="dlg-title">Новая статья в разделе</h2>
|
||
<button class="dlg-close" type="button" aria-label="Закрыть">✕</button>
|
||
</div>
|
||
<div class="dlg-body">
|
||
<form class="form-stack" th:action="@{/admin/content/articles/create}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="sectionId" th:value="${section.id}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<div><label class="label" for="naTitle">Заголовок</label>
|
||
<input class="input" id="naTitle" name="title" required></div>
|
||
<div><label class="label" for="naBody">Текст (markdown)</label>
|
||
<div th:replace="~{fragments/md-toolbar :: toolbar('#naBody')}"></div>
|
||
<textarea class="input md-editor-body" id="naBody" name="bodyMd" rows="18"></textarea></div>
|
||
<p class="hint">
|
||
Картинка: <code class="code">:::figure assets/имя.png | Рис. 1. Подпись</code>;
|
||
видео: <code class="code">:::video assets/имя.mp4 | Подпись</code>;
|
||
спойлер: <code class="code">:::spoiler Решение … :::</code>.
|
||
</p>
|
||
<button class="btn btn-primary" type="submit">Создать</button>
|
||
</form>
|
||
</div>
|
||
</dialog>
|
||
|
||
<script th:src="@{/js/content-sort.js(v='32')}" defer></script>
|
||
</div>
|
||
</body>
|
||
</html>
|