UI rework: modal dialogs, inline lab editing, manual creation, content management
- Dashboard: real stats (groups, students, labs, average grade), labs/groups summary lists, no placeholder tile - Lab page: view + edit combined — metadata form in modal, condition rendered as markdown, per-level variant tables with add/edit/delete dialogs, level rename/delete, student level/variant selectors with group filter - Labs list: create-lab dialog with manual level entry (code; title lines) - Groups: create-group dialog, add-student dialog (auto password, toast card) - Content: public /learn reader is the single place; admin buttons (new article with chapter/section create-or-select, rename/delete chapters and sections, move articles between sections, import zip) appear for admins; removed separate 'Контент' admin section - Buttons use btn classes instead of nav-link - Favicon: generated SVG book icon - Security: CSRF synchronizer token interceptor (replaced spring-security in web which broke logback under nested jars), session regenerated on login, hardened session cookie, gateway actuator limited to health,info - Jackson 3: nullable-safe request DTOs for labs (FAIL_ON_NULL_FOR_PRIMITIVES) - academic: POST /labs (manual create with levels), level add/rename/delete, content chapters/sections CRUD, article create/move/delete endpoints
This commit is contained in:
@@ -4,11 +4,14 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title th:replace="${title}">LMS</title>
|
||||
<link rel="icon" type="image/svg+xml" th:href="@{/favicon.svg}">
|
||||
<link rel="stylesheet" th:href="@{/css/app.css}">
|
||||
<script th:src="@{/js/htmx.min.js}" defer></script>
|
||||
<script>
|
||||
(function(){ var t = localStorage.getItem('lms-theme') || 'light'; document.documentElement.setAttribute('data-theme', t); })();
|
||||
function toggleTheme(){ var e=document.documentElement; var t=e.getAttribute('data-theme')==='dark'?'light':'dark'; e.setAttribute('data-theme',t); localStorage.setItem('lms-theme',t); }
|
||||
function openModal(id){ var d=document.getElementById(id); if(d) d.showModal(); }
|
||||
function closeModal(id){ var d=document.getElementById(id); if(d) d.close(); }
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -16,13 +19,17 @@
|
||||
<header class="page-header">
|
||||
<div class="page-header-inner">
|
||||
<a th:href="@{/}" class="logo">LMS</a>
|
||||
<nav class="nav" th:if="${currentUser != null}">
|
||||
<a th:if="${currentUser.admin}" th:href="@{/admin/groups}" class="nav-link">Группы</a>
|
||||
<a th:if="${currentUser.admin}" th:href="@{/admin/labs}" class="nav-link">Лабораторные</a>
|
||||
<span class="nav-sep" th:text="${currentUser.name}">—</span>
|
||||
<nav class="nav">
|
||||
<a th:href="@{/learn}" class="nav-link">Материалы</a>
|
||||
<th:block th:if="${currentUser != null}">
|
||||
<a th:if="${currentUser.admin}" th:href="@{/admin/groups}" class="nav-link">Группы</a>
|
||||
<a th:if="${currentUser.admin}" th:href="@{/admin/labs}" class="nav-link">Лабораторные</a>
|
||||
<span class="nav-sep" th:text="${currentUser.name}">—</span>
|
||||
</th:block>
|
||||
<button onclick="toggleTheme()" class="btn btn-secondary btn-sm">☀/🌙</button>
|
||||
<form th:action="@{/logout}" method="post">
|
||||
<form th:if="${currentUser != null}" th:action="@{/logout}" method="post">
|
||||
<button class="btn btn-secondary" type="submit">Выйти</button>
|
||||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||||
</form>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user