Modals: lock background scroll; comment dropdown keeps row on one line, full tone labels, flip up near bottom

This commit is contained in:
2026-09-29 16:19:15 +03:00
parent 81133684e9
commit 22b33e6629
3 changed files with 39 additions and 7 deletions

View File

@@ -235,6 +235,9 @@ dialog.modal {
box-shadow: 0 20px 60px rgba(0,0,0,0.35); box-shadow: 0 20px 60px rgba(0,0,0,0.35);
} }
dialog.modal::backdrop { background: rgba(0,0,0,0.55); } dialog.modal::backdrop { background: rgba(0,0,0,0.55); }
/* Пока открыта модалка — страница не прокручивается; прокрутка остаётся внутри .modal-body */
html.modal-open, html.modal-open body { overflow: hidden; }
html.modal-open body { padding-right: var(--modal-scrollbar, 0); }
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.5rem; border-bottom: 1px solid var(--c-border); } .modal-header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.5rem; border-bottom: 1px solid var(--c-border); }
.modal-title { margin: 0; font-size: 1.0625rem; font-weight: 600; } .modal-title { margin: 0; font-size: 1.0625rem; font-weight: 600; }
.modal-close { border: none; background: none; cursor: pointer; font-size: 1.25rem; color: var(--c-text-muted); padding: 0 0.25rem; } .modal-close { border: none; background: none; cursor: pointer; font-size: 1.25rem; color: var(--c-text-muted); padding: 0 0.25rem; }
@@ -304,17 +307,17 @@ code.code { padding: 0.125rem 0.5rem; border-radius: 0.25rem; font-family: monos
.chip-neu { background: #5d6570; color: #fff; } .chip-neu { background: #5d6570; color: #fff; }
.chip-neg { background: #b3283b; color: #fff; } .chip-neg { background: #b3283b; color: #fff; }
/* Слоты комментариев в диалоге */ /* Слоты комментариев в диалоге */
.cs-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; } .cs-row { display: flex; gap: 6px; align-items: center; }
.cs-text-wrap { position: relative; flex: 1 1 12rem; min-width: 0; } .cs-text-wrap { position: relative; flex: 1 1 auto; min-width: 0; }
.cs-text-wrap .cs-text { width: 100%; } .cs-text-wrap .cs-text { width: 100%; }
.cs-row .cs-tone, .cs-row .btn { flex: 0 0 auto; } .cs-row .cs-tone, .cs-row .btn { flex: 0 0 auto; }
.cs-tone { max-width: 9rem; }
.ac-list { .ac-list {
position: absolute; left: 0; right: 0; top: 100%; margin-top: 2px; z-index: 20; position: absolute; left: 0; right: 0; top: 100%; margin-top: 2px; z-index: 20;
max-height: 14rem; overflow-y: auto; max-height: 14rem; overflow-y: auto;
background: var(--c-surface); border: 1px solid var(--c-border); background: var(--c-surface); border: 1px solid var(--c-border);
border-radius: 0.4rem; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15); border-radius: 0.4rem; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
} }
.ac-list.drop-up { top: auto; bottom: 100%; margin-top: 0; margin-bottom: 2px; }
.ac-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.6rem; cursor: pointer; font-size: 0.875rem; } .ac-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.6rem; cursor: pointer; font-size: 0.875rem; }
.ac-item:hover, .ac-item.active { background: var(--c-bg); } .ac-item:hover, .ac-item.active { background: var(--c-bg); }
.ac-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ac-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

View File

@@ -47,7 +47,7 @@ function csRow(text, tone) {
var sel = document.createElement('select'); var sel = document.createElement('select');
sel.className = 'input cs-tone'; sel.className = 'input cs-tone';
sel.title = 'Тональность комментария'; sel.title = 'Тональность комментария';
[['positive', '+ позитив'], ['negative', '— негатив'], ['neutral', '○ нейтрал']].forEach(function (o) { [['positive', '+ позитивный'], ['negative', '— негативный'], ['neutral', '○ нейтральный']].forEach(function (o) {
var op = document.createElement('option'); var op = document.createElement('option');
op.value = o[0]; op.value = o[0];
op.textContent = o[1]; op.textContent = o[1];
@@ -152,8 +152,22 @@ function attachCommentAutocomplete(input) {
}); });
list.hidden = false; list.hidden = false;
active = -1; active = -1;
positionList();
} }
/* Если снизу внутри модалки мало места — раскрываем список вверх, чтобы он не обрезался. */
function positionList() {
var wrap = input.parentNode;
var scrollParent = input.closest('.modal-body') || document.documentElement;
var wr = wrap.getBoundingClientRect();
var sr = scrollParent.getBoundingClientRect();
var below = sr.bottom - wr.bottom;
var above = wr.top - sr.top;
list.classList.toggle('drop-up', below < 220 && above > below);
}
window.addEventListener('resize', function () { if (!list.hidden) positionList(); });
function load() { function load() {
clearTimeout(AC_TIMER); clearTimeout(AC_TIMER);
AC_TIMER = setTimeout(function () { AC_TIMER = setTimeout(function () {

View File

@@ -27,15 +27,30 @@
document.querySelectorAll('pre code').forEach(function(el){ window.hljs.highlightElement(el); }); document.querySelectorAll('pre code').forEach(function(el){ window.hljs.highlightElement(el); });
}; };
})(); })();
document.addEventListener('DOMContentLoaded', function(){ window.__hljsSet(document.documentElement.getAttribute('data-theme')); window.__hljsAll(); }); document.addEventListener('DOMContentLoaded', function(){ window.__hljsSet(document.documentElement.getAttribute('data-theme')); window.__hljsAll(); syncModalScrollLock(); });
function toggleTheme(){ function toggleTheme(){
var e=document.documentElement; var t=e.getAttribute('data-theme')==='dark'?'light':'dark'; 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); e.setAttribute('data-theme',t); localStorage.setItem('lms-theme',t); window.__hljsSet(t);
} }
function openModal(id){ var d=document.getElementById(id); if(d) d.showModal(); } function openModal(id){ var d=document.getElementById(id); if(d) d.showModal(); syncModalScrollLock(); }
function closeModal(id){ var d=document.getElementById(id); if(d) d.close(); } function closeModal(id){ var d=document.getElementById(id); if(d) d.close(); syncModalScrollLock(); }
function openModalData(btn){ openModal(btn.dataset.modal); } function openModalData(btn){ openModal(btn.dataset.modal); }
function closeModalData(btn){ closeModal(btn.dataset.modal); } function closeModalData(btn){ closeModal(btn.dataset.modal); }
/* Пока открыта хоть одна модалка — блокируем прокрутку страницы (внутри .modal-body прокрутка остаётся). */
function syncModalScrollLock(){
var root = document.documentElement;
if (document.querySelector('dialog[open]')) {
var sw = window.innerWidth - root.clientWidth;
root.style.setProperty('--modal-scrollbar', (sw > 0 ? sw : 0) + 'px');
root.classList.add('modal-open');
} else {
root.classList.remove('modal-open');
root.style.removeProperty('--modal-scrollbar');
}
}
document.addEventListener('toggle', function (e) {
if (e.target && e.target.tagName === 'DIALOG') syncModalScrollLock();
}, true);
function sectionStateKey(id){ return 'lms-section-open:' + id; } function sectionStateKey(id){ return 'lms-section-open:' + id; }
function applySectionState(acc){ function applySectionState(acc){
var id = acc.getAttribute('data-section-id'); var id = acc.getAttribute('data-section-id');