UI fixes: learn rows on one line, offcanvas header/brand/user layout, users column, code color, badge padding, sticky footer; class-based selectors
This commit is contained in:
@@ -131,6 +131,7 @@ p { margin-top: 0; }
|
||||
|
||||
|
||||
/* ===== B3-тема поверх Bootstrap: navbar, offcanvas, кнопки, ссылки ===== */
|
||||
code { --bs-code-color: var(--c-text); color: var(--c-text); }
|
||||
.b3-navbar { background: var(--c-surface); border-bottom: 1px solid var(--c-border); }
|
||||
.b3-navbar .container, .page-main.container { max-width: 1200px; }
|
||||
.b3-navbar .navbar-brand { color: var(--c-text); font-weight: 700; font-size: 1rem; }
|
||||
@@ -141,10 +142,10 @@ p { margin-top: 0; }
|
||||
.nav-link.active { color: var(--c-accent) !important; font-weight: 700; }
|
||||
.navbar-close { border: 0; background: none; color: var(--c-text-muted); font-size: 1.1rem; line-height: 1; }
|
||||
.navbar-close:hover { color: var(--c-text); }
|
||||
#mobileNav { --bs-offcanvas-width: 17rem; --bs-offcanvas-bg: var(--c-surface); --bs-offcanvas-color: var(--c-text); --bs-offcanvas-border-color: var(--c-border); }
|
||||
#mobileNav .offcanvas-header { border-bottom: 1px solid var(--c-border); }
|
||||
#mobileNav .navbar-nav { gap: 0.25rem; }
|
||||
#mobileNav .nav-link { padding: 0.5rem 0.25rem; font-size: 1rem; }
|
||||
.app-offcanvas { --bs-offcanvas-width: 17rem; --bs-offcanvas-bg: var(--c-surface); --bs-offcanvas-color: var(--c-text); --bs-offcanvas-border-color: var(--c-border); }
|
||||
.app-offcanvas .offcanvas-header { border-bottom: 1px solid var(--c-border); justify-content: space-between; gap: 1rem; }
|
||||
.app-offcanvas .navbar-nav { gap: 0.25rem; }
|
||||
.app-offcanvas .nav-link { padding: 0.5rem 0.25rem; font-size: 1rem; }
|
||||
@media (max-width: 767.98px) {
|
||||
#mobileNav .offcanvas-body { display: flex; flex-direction: column; justify-content: space-between; gap: 1rem; }
|
||||
}
|
||||
@@ -202,7 +203,7 @@ a { --bs-link-color: var(--c-accent); --bs-link-hover-color: var(--c-accent-hove
|
||||
/* Badges — «этикетки»: строгая рамка, разрядка капсом; только индикаторы статуса */
|
||||
.badge {
|
||||
display: inline-flex; align-items: center;
|
||||
border-radius: var(--radius-xs); padding: 0.1rem 0.5rem;
|
||||
border-radius: var(--bs-btn-border-radius, var(--radius-sm)); padding: 0.5rem 1rem;
|
||||
font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
@@ -233,7 +234,7 @@ tr:last-child td { border-bottom: none; }
|
||||
.group-title { margin: 0 0 0.5rem; font-size: 1rem; font-weight: 600; }
|
||||
.inline-form { display: inline-flex; align-items: center; gap: 0.375rem; margin: 0; }
|
||||
/* Селект фокуса на лабу в тулбаре ведомости — по содержимому, не на всю ширину */
|
||||
#lab-focus { width: auto; min-width: 11rem; }
|
||||
.input-lab-focus { width: auto; min-width: 11rem; }
|
||||
.input-score { width: 4.5rem; }
|
||||
|
||||
.inline-form .input-score, input[type="number"].input-score { width: 4.5rem; min-width: 4.5rem; flex: 0 0 auto; }
|
||||
@@ -480,7 +481,7 @@ dialog.dlg.dlg-lg .dlg-body { max-height: 88vh; min-height: 62vh; }
|
||||
/* Материалы: ряды и ручки перетаскивания слева, одним столбцом */
|
||||
.sort-row { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
|
||||
.sort-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.sort-actions { margin-left: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
|
||||
.sort-actions { margin-left: auto; display: flex; flex-wrap: nowrap; align-items: center; gap: 0.35rem; }
|
||||
.sort-list { list-style: none; margin: 0; padding: 0; }
|
||||
.sort-list > li { display: flex; align-items: center; gap: 0.5rem; min-width: 0; padding: 0.15rem 0; }
|
||||
.chapter-card { padding: 0.75rem 1rem; }
|
||||
@@ -735,8 +736,8 @@ th.th-filterable { padding-bottom: 0.35rem; }
|
||||
/* Материалы на мобильных: действия переносятся под заголовок */
|
||||
@media (max-width: 720px) {
|
||||
.sort-row, .sort-list > li { flex-wrap: wrap; row-gap: 0.35rem; }
|
||||
.sort-row .sort-actions, .sort-list > li .sort-actions { margin-left: 2.4rem; width: calc(100% - 2.4rem); justify-content: flex-start; }
|
||||
.sort-row .sort-title { flex: 1 1 auto; }
|
||||
.sort-row .sort-actions, .sort-list > li .sort-actions { margin-left: auto; flex-wrap: nowrap; justify-content: flex-end; }
|
||||
.sort-row .sort-title, .sort-list > li .sort-title { flex: 1 1 auto; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<div class="toolbar">
|
||||
<input class="input table-search w-260" data-target="group-table"
|
||||
placeholder="Поиск по студенту…" aria-label="Поиск по студенту">
|
||||
<select class="input" id="lab-focus">
|
||||
<select class="input input-lab-focus" id="lab-focus">
|
||||
<option value="">все лабораторные</option>
|
||||
<option th:each="lab : ${labs}" th:value="${lab.id}" th:text="|ЛР ${lab.number}|">—</option>
|
||||
</select>
|
||||
@@ -344,7 +344,7 @@
|
||||
<div class="dlg-body" id="assign-modal-body"></div>
|
||||
</dialog>
|
||||
|
||||
<script th:src="@{/js/admin-group.js(v='15')}" defer></script>
|
||||
<script th:src="@{/js/admin-group.js(v='19')}" defer></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -196,7 +196,7 @@
|
||||
</dialog>
|
||||
</th:block>
|
||||
</div>
|
||||
<script th:src="@{/js/admin-lab.js(v='15')}" defer></script>
|
||||
<script th:src="@{/js/admin-lab.js(v='19')}" defer></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
<tr>
|
||||
<th class="th-sortable is-asc" title="ФИО — по возрастанию">ФИО</th>
|
||||
<th>Логин</th>
|
||||
<th>Номер</th>
|
||||
<th>Группа</th>
|
||||
<th class="text-right" data-nosort>Действия</th>
|
||||
</tr>
|
||||
@@ -27,7 +26,6 @@
|
||||
<tr th:each="u : ${users}">
|
||||
<td class="font-medium" th:text="${u.fullName}">—</td>
|
||||
<td class="font-mono" th:text="${u.login}">—</td>
|
||||
<td class="font-mono" th:text="${u.studentNo}">—</td>
|
||||
<td><a th:if="${u.groupId}" th:href="@{/admin/groups/{id}(id=${u.groupId})}" th:text="${u.groupName}">—</a><span th:unless="${u.groupId}" class="text-muted">без группы</span></td>
|
||||
<td class="text-right">
|
||||
<form class="inline-form" th:action="@{/admin/users/{id}/delete(id=${u.id})}" method="post" data-confirm="Удалить пользователя безвозвратно? Будут удалены аккаунт, группа, оценки с комментариями, сдачи с файлами и задания защит.">
|
||||
@@ -37,7 +35,7 @@
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<tr th:if="${#lists.isEmpty(users)}"><td colspan="5" class="empty">Никого не нашли.</td></tr>
|
||||
<tr th:if="${#lists.isEmpty(users)}"><td colspan="4" class="empty">Никого не нашли.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -17,21 +17,21 @@
|
||||
<!-- v=4: сброс кэша стилей после редизайна; при изменении css поднимать версию -->
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/bootstrap-icons.min.css}">
|
||||
<link rel="stylesheet" th:href="@{/css/app.css(v='18')}">
|
||||
<link id="hljs-light" rel="stylesheet" th:href="@{/css/hljs-github.css(v='18')}">
|
||||
<link id="hljs-dark" rel="stylesheet" th:href="@{/css/hljs-github-dark.css(v='18')}" disabled>
|
||||
<script th:src="@{/js/highlight.min.js(v='18')}" defer></script>
|
||||
<script th:src="@{/js/table-scroll.js(v='18')}" defer></script>
|
||||
<script th:src="@{/js/tablekit.js(v='18')}" defer></script>
|
||||
<link rel="stylesheet" th:href="@{/css/app.css(v='19')}">
|
||||
<link id="hljs-light" rel="stylesheet" th:href="@{/css/hljs-github.css(v='19')}">
|
||||
<link id="hljs-dark" rel="stylesheet" th:href="@{/css/hljs-github-dark.css(v='19')}" disabled>
|
||||
<script th:src="@{/js/highlight.min.js(v='19')}" defer></script>
|
||||
<script th:src="@{/js/table-scroll.js(v='19')}" defer></script>
|
||||
<script th:src="@{/js/tablekit.js(v='19')}" defer></script>
|
||||
<script th:src="@{/js/bootstrap.bundle.min.js}" defer></script>
|
||||
<script th:src="@{/js/theme-init.js(v='18')}"></script>
|
||||
<script th:src="@{/js/app.js(v='18')}" defer></script>
|
||||
<script th:src="@{/js/ui-state.js(v='18')}" defer></script>
|
||||
<script th:src="@{/js/md-content.js(v='18')}" defer></script>
|
||||
<script th:src="@{/js/submit-guard.js(v='18')}" defer></script>
|
||||
<script th:src="@{/js/theme-init.js(v='19')}"></script>
|
||||
<script th:src="@{/js/app.js(v='19')}" defer></script>
|
||||
<script th:src="@{/js/ui-state.js(v='19')}" defer></script>
|
||||
<script th:src="@{/js/md-content.js(v='19')}" defer></script>
|
||||
<script th:src="@{/js/submit-guard.js(v='19')}" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="page d-flex flex-column min-vh-100">
|
||||
<nav class="navbar b3-navbar navbar-expand-md sticky-top">
|
||||
<div class="container">
|
||||
<a th:href="@{/}" class="navbar-brand">LMS<b>.</b></a>
|
||||
@@ -39,9 +39,9 @@
|
||||
aria-controls="mobileNav" aria-label="Меню">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
<div class="offcanvas offcanvas-end" tabindex="-1" id="mobileNav" aria-labelledby="mobileNavLabel">
|
||||
<div class="offcanvas offcanvas-end app-offcanvas" tabindex="-1" id="mobileNav" aria-labelledby="mobileNavLabel">
|
||||
<div class="offcanvas-header">
|
||||
<span class="navbar-brand" id="mobileNavLabel">LMS<b>.</b></span>
|
||||
<a th:href="@{/learn}" class="navbar-brand" id="mobileNavLabel">LMS<b>.</b></a>
|
||||
<button type="button" class="navbar-close" data-bs-dismiss="offcanvas" aria-label="Закрыть">✕</button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
@@ -52,26 +52,28 @@
|
||||
<li class="nav-item" th:if="${currentUser != null and !currentUser.admin}"><a class="nav-link" th:href="@{/student/labs}">Лабораторные</a></li>
|
||||
<li class="nav-item" th:if="${currentUser != null}"><a class="nav-link" th:href="@{/change-password}">Смена пароля</a></li>
|
||||
</ul>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="navbar-user d-flex flex-column flex-md-row align-items-start align-items-md-center gap-2">
|
||||
<a th:href="@{/admin}" th:if="${currentUser != null and currentUser.admin}" class="nav-user" th:text="${currentUser.name}" title="Личный кабинет">—</a>
|
||||
<a th:href="@{/student}" th:if="${currentUser != null and !currentUser.admin}" class="nav-user" th:text="${currentUser.name}" title="Личный кабинет">—</a>
|
||||
<button type="button" class="btn btn-secondary btn-sm theme-btn" aria-label="Сменить тему" title="Сменить тему">
|
||||
<i class="bi bi-circle-half"></i>
|
||||
</button>
|
||||
<a th:if="${currentUser == null}" th:href="@{/login}" class="btn btn-sm">Войти</a>
|
||||
<form th:if="${currentUser != null}" th:action="@{/logout}" method="post" class="m-0">
|
||||
<button class="btn btn-sm" type="submit">Выйти</button>
|
||||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||||
</form>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<button type="button" class="btn btn-secondary btn-sm theme-btn" aria-label="Сменить тему" title="Сменить тему">
|
||||
<i class="bi bi-circle-half"></i>
|
||||
</button>
|
||||
<a th:if="${currentUser == null}" th:href="@{/login}" class="btn btn-sm">Войти</a>
|
||||
<form th:if="${currentUser != null}" th:action="@{/logout}" method="post" class="m-0">
|
||||
<button class="btn btn-sm" type="submit">Выйти</button>
|
||||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<main class="container page-main">
|
||||
<main class="container page-main flex-grow-1">
|
||||
<th:block th:replace="${content}" />
|
||||
</main>
|
||||
<footer class="page-footer">
|
||||
<footer class="page-footer mt-auto">
|
||||
LMS v1.1.0
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
<script th:src="@{/js/mdeditor.js(v='15')}" defer></script>
|
||||
<script th:src="@{/js/mdeditor.js(v='19')}" defer></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<script th:src="@{/js/content-sort.js(v='15')}" defer></script>
|
||||
<script th:src="@{/js/content-sort.js(v='19')}" defer></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -232,8 +232,8 @@
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<script th:src="@{/js/mdeditor.js(v='15')}" defer></script>
|
||||
<script th:src="@{/js/content-sort.js(v='15')}" defer></script>
|
||||
<script th:src="@{/js/mdeditor.js(v='19')}" defer></script>
|
||||
<script th:src="@{/js/content-sort.js(v='19')}" defer></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<script th:src="@{/js/content-sort.js(v='15')}" defer></script>
|
||||
<script th:src="@{/js/content-sort.js(v='19')}" defer></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
<p class="text-sm text-muted">Ожидайте преподавателя с проверкой.</p>
|
||||
</div>
|
||||
</div>
|
||||
<script th:src="@{/js/defense-timer.js(v='15')}" defer></script>
|
||||
<script th:src="@{/js/defense-timer.js(v='19')}" defer></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user