From e4307f2248ec5ab65cd9f696d6ac13e301553e64 Mon Sep 17 00:00:00 2001 From: Vladislav Kopnin Date: Fri, 2 Oct 2026 16:37:00 +0300 Subject: [PATCH] Group page: B3 layout (page-head, toolbar, matrix), neutral header with accent logo dot --- .../ysu/lms/web/admin/AdminGroupController.kt | 1 + web/src/main/resources/static/css/app.css | 47 ++++++++++++++----- .../main/resources/templates/admin/group.html | 29 +++++++----- .../resources/templates/fragments/base.html | 29 ++++++++---- 4 files changed, 73 insertions(+), 33 deletions(-) diff --git a/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminGroupController.kt b/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminGroupController.kt index 5702de1..938a4e0 100644 --- a/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminGroupController.kt +++ b/web/src/main/kotlin/ru/ysu/lms/web/admin/AdminGroupController.kt @@ -281,6 +281,7 @@ class AdminGroupController( model.addAttribute("studentGrades", view.rows) model.addAttribute("labPublication", view.labPublication) model.addAttribute("labSubmissionCounts", view.submissionCounts) + model.addAttribute("publishedLabsCount", view.labPublication.values.count { it.publishedCount > 0 }) } /** Фрагмент большой модалки «Выдача вариантов»: вся группа одной таблицей по выбранной лабе. */ diff --git a/web/src/main/resources/static/css/app.css b/web/src/main/resources/static/css/app.css index df6883a..1f9e48f 100644 --- a/web/src/main/resources/static/css/app.css +++ b/web/src/main/resources/static/css/app.css @@ -74,24 +74,28 @@ a:not(.btn):hover { color: var(--c-text-link-hover); } /* Layout */ .page { display: flex; flex-direction: column; min-height: 100vh; } .page-header { position: sticky; top: 0; z-index: 10; border-bottom: 1px solid var(--c-border); background: var(--c-surface); } -.page-header-inner { max-width: 1152px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem 1rem; flex-wrap: wrap; padding: 0.75rem 1.5rem; } +.page-header-inner { max-width: 1200px; margin: 0 auto; display: flex; align-items: center; gap: 0.5rem 1.75rem; flex-wrap: wrap; padding: 0.875rem 1.75rem; } @media (max-width: 640px) { - .page-header-inner { padding: 0.5rem 0.75rem; } - .nav { width: 100%; gap: 0.5rem 0.75rem; flex-wrap: wrap; font-size: 0.8125rem; } - .nav .btn { padding: 0.25rem 0.6rem; font-size: 0.75rem; } + .page-header-inner { padding: 0.5rem 0.875rem; gap: 0.5rem 1rem; } + .nav { gap: 0.5rem 0.75rem; flex-wrap: wrap; } + .user { gap: 0.5rem; } .nav-user { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } } -.page-main { flex: 1; width: 100%; max-width: 1152px; margin: 0 auto; padding: 2rem 1.5rem; } -.page-footer { border-top: 1px solid var(--c-border); padding: 1rem; text-align: center; font-size: 0.75rem; color: var(--c-text-muted); } +.page-main { flex: 1; width: 100%; max-width: 1200px; margin: 0 auto; padding: 2.5rem 1.75rem 3.5rem; } +@media (max-width: 720px) { .page-main { padding: 1.5rem 0.875rem 2.5rem; } } +.page-footer { text-align: center; color: var(--c-text-muted); font-size: 0.75rem; padding: 1.5rem; } /* Nav */ -.nav { display: flex; align-items: center; gap: 1rem; font-size: 0.875rem; } -.nav-link { color: var(--c-text-muted); text-decoration: none; } +.nav { display: flex; align-items: center; gap: 1.125rem; flex: 1 1 auto; flex-wrap: wrap; font-size: 0.84375rem; } +.nav-link { color: var(--c-text-muted); text-decoration: none; font-weight: 500; } .nav-link:hover { color: var(--c-text); } +.nav-link.active { color: var(--c-accent); } .nav-sep { color: var(--c-text-muted); } .logo { font-size: 1rem; font-weight: 700; color: var(--c-text); text-decoration: none; letter-spacing: -0.01em; } .logo b { color: var(--c-accent); } -.nav-user { font-weight: 500; } +.user { display: flex; align-items: center; gap: 0.75rem; font-size: 0.84375rem; margin-left: auto; } +.nav-user { font-weight: 500; color: var(--c-text); } +.nav-user:hover { color: var(--c-accent); } .theme-btn { display: inline-flex; align-items: center; justify-content: center; padding: 0.3rem 0.5rem; } .theme-icon { width: 1.05rem; height: 1.05rem; display: block; } .breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; } @@ -138,8 +142,18 @@ a:not(.btn):hover { color: var(--c-text-link-hover); } .grid-stats { grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); } /* Typography */ -.page-title { margin: 0 0 1.5rem; font-size: 1.5rem; font-weight: 600; } +.page-title { margin: 0 0 1.5rem; font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em; } .section-title { margin: 0 0 0.75rem; font-size: 1.125rem; font-weight: 500; } + +/* Шапка страницы в стиле Б3: kicker + заголовок + мета, действия справа */ +.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; margin-bottom: 1.75rem; flex-wrap: wrap; } +.page-head .page-title { margin: 0 0 0.5rem; } +.kicker { margin: 0 0 0.375rem; font-size: 0.75rem; font-weight: 500; color: var(--c-text-muted); } +.meta { margin: 0; color: var(--c-text-muted); font-size: 0.8125rem; } +.meta b { color: var(--c-text); font-weight: 600; } +.actions { display: flex; gap: 0.5rem; flex-wrap: wrap; } +.toolbar { display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; } +.toolbar .table-search { width: 260px; } .stat-value { margin: 0.5rem 0 0; font-size: 1.875rem; font-weight: 600; } .stat-title { font-size: 0.875rem; color: var(--c-text-muted); margin: 0; } .text-muted { color: var(--c-text-muted); } @@ -483,11 +497,20 @@ dialog.modal.modal-lg .modal-body { max-height: 88vh; min-height: 62vh; } .font-medium { font-weight: 500; } .scroll-x { overflow-x: auto; } .matrix { border-collapse: separate; border-spacing: 0; } -.matrix th { vertical-align: top; } -.matrix td { vertical-align: middle; } +.matrix th { + vertical-align: top; padding: 0.75rem 1rem; text-align: left; + font-size: 0.75rem; font-weight: 500; color: var(--c-text-muted); + background: var(--c-surface); white-space: nowrap; +} +.matrix td { vertical-align: top; padding: 1rem; } +.matrix tbody tr:hover td { background: rgba(19, 19, 22, 0.03); } +[data-theme="dark"] .matrix tbody tr:hover td { background: rgba(232, 233, 236, 0.045); } +.matrix tbody tr:last-child td { border-bottom: none; } .matrix th.lab-col { min-width: 9.5rem; border-left: 1px solid var(--c-border); } .matrix td.cell-lab { min-width: 9.5rem; border-left: 1px solid var(--c-border); } .matrix td.student-cell { min-width: 12rem; } +.student-name { font-weight: 600; font-size: 0.84375rem; } +.student-cell .font-mono { margin-top: 0.125rem; } .lab-col-head { display: flex; flex-direction: column; align-items: center; gap: 0.375rem; } .lab-col-title { max-width: 9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; diff --git a/web/src/main/resources/templates/admin/group.html b/web/src/main/resources/templates/admin/group.html index 8042672..1e5a368 100644 --- a/web/src/main/resources/templates/admin/group.html +++ b/web/src/main/resources/templates/admin/group.html @@ -3,25 +3,28 @@ Группа
- ← Все группы -
+
-

Группа

-

Студентов: 0

+

Ведомость группы

+

Группа

+

+ 0 студентов · + 0 + лабораторных + с открытыми оценками +

+ Скачать работы - Скачать пароли - +
-
-

Студенты и лабораторные

-
-
+
-
- +
diff --git a/web/src/main/resources/templates/fragments/base.html b/web/src/main/resources/templates/fragments/base.html index 9b691f7..038d295 100644 --- a/web/src/main/resources/templates/fragments/base.html +++ b/web/src/main/resources/templates/fragments/base.html @@ -37,7 +37,15 @@ document.querySelectorAll('pre code').forEach(function(el){ window.hljs.highlightElement(el); }); }; })(); - document.addEventListener('DOMContentLoaded', function(){ window.__hljsSet(document.documentElement.getAttribute('data-theme')); window.__hljsAll(); syncModalScrollLock(); }); + document.addEventListener('DOMContentLoaded', function(){ window.__hljsSet(document.documentElement.getAttribute('data-theme')); window.__hljsAll(); syncModalScrollLock(); initNavActive(); initSections(); }); + /* Активный пункт меню — как в макете: бордовый цвет у текущего раздела. */ + function initNavActive(){ + var path = window.location.pathname; + document.querySelectorAll('#top-nav .nav-link').forEach(function (a) { + var href = a.getAttribute('href') || ''; + if (path === href || (href !== '/' && path.indexOf(href + '/') === 0)) a.classList.add('active'); + }); + } 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); window.__hljsSet(t); @@ -99,18 +107,23 @@