UI: адаптив, журнал, спиннеры; docs: README и api_routes
- Навигация: выезжающее меню при узком экране (nav-mobile.js) - Журнал: карточки <620px, компактная пагинация, время в две строки <920px - Создание кластера: оверлей загрузки, инкрементальное обновление таблицы заданий - Документация: полноэкранный спиннер при загрузке и навигации - Главная: масштабирование CTA, статистика 2 колонки <520px, донаты перенос <710px - README: env.example, новые фичи UI, автор в конце файла - api_routes: маршрут /cluster-create, спиннеры, шаблоны; автор в конце - env.example: автор перенесён в конец файла
This commit is contained in:
@@ -24,6 +24,25 @@
|
||||
el.classList.add("hidden");
|
||||
}
|
||||
|
||||
/** Полноэкранный спиннер как на панели (page-loading-overlay в documentation.html). */
|
||||
function showDocumentationPageLoadingOverlay() {
|
||||
var el = document.getElementById("documentation-page-loading-overlay");
|
||||
if (!el) return;
|
||||
el.classList.remove("hidden");
|
||||
el.setAttribute("aria-busy", "true");
|
||||
el.setAttribute("aria-hidden", "false");
|
||||
document.body.classList.add("documentation-page-loading");
|
||||
}
|
||||
|
||||
function hideDocumentationPageLoadingOverlay() {
|
||||
var el = document.getElementById("documentation-page-loading-overlay");
|
||||
if (!el) return;
|
||||
el.classList.add("hidden");
|
||||
el.setAttribute("aria-busy", "false");
|
||||
el.setAttribute("aria-hidden", "true");
|
||||
document.body.classList.remove("documentation-page-loading");
|
||||
}
|
||||
|
||||
function getPathFromLocation() {
|
||||
var q = new URLSearchParams(window.location.search || "");
|
||||
var p = (q.get("path") || "").trim();
|
||||
@@ -193,10 +212,36 @@
|
||||
return page;
|
||||
}
|
||||
|
||||
function renderMarkdownToRoot(text, docPath, rootEl, errEl, loadEl) {
|
||||
/**
|
||||
* Таблицы Markdown с более чем двумя колонками: класс и data-label для мини-карточек при ширине до 480px (CSS).
|
||||
* @param {HTMLElement} rootEl
|
||||
*/
|
||||
function markupWideMarkdownTables(rootEl) {
|
||||
if (!rootEl || !rootEl.querySelectorAll) return;
|
||||
rootEl.querySelectorAll(".markdown-body table").forEach(function (table) {
|
||||
var thList = table.querySelectorAll("thead tr th");
|
||||
if (!thList.length) return;
|
||||
var n = thList.length;
|
||||
if (n <= 2) return;
|
||||
table.classList.add("markdown-body-table--stack");
|
||||
var labels = [];
|
||||
for (var i = 0; i < thList.length; i++) {
|
||||
labels.push((thList[i].textContent || "").trim());
|
||||
}
|
||||
var tbody = table.querySelector("tbody");
|
||||
if (!tbody) return;
|
||||
tbody.querySelectorAll("tr").forEach(function (tr) {
|
||||
var tds = tr.querySelectorAll("td");
|
||||
for (var j = 0; j < tds.length; j++) {
|
||||
if (labels[j]) tds[j].setAttribute("data-label", labels[j]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function renderMarkdownToRoot(text, docPath, rootEl, errEl) {
|
||||
if (typeof marked === "undefined" || typeof DOMPurify === "undefined") {
|
||||
showErr(errEl, "Не загружены скрипты marked или DOMPurify из /static/js/vendor/.");
|
||||
if (loadEl) loadEl.classList.add("hidden");
|
||||
applyDocumentationTabTitle("");
|
||||
return;
|
||||
}
|
||||
@@ -223,6 +268,7 @@
|
||||
while (rootEl.firstChild) rootEl.removeChild(rootEl.firstChild);
|
||||
var pageInner = sectionizeFromNodes(temp);
|
||||
rootEl.appendChild(pageInner);
|
||||
markupWideMarkdownTables(rootEl);
|
||||
rootEl.removeAttribute("hidden");
|
||||
} catch (e2) {
|
||||
showErr(errEl, "Ошибка разбора: " + (e2.message || String(e2)));
|
||||
@@ -242,18 +288,20 @@
|
||||
|
||||
var rootEl = document.getElementById("readme-doc-root");
|
||||
var errEl = document.getElementById("readme-error");
|
||||
var loadEl = document.getElementById("readme-loading");
|
||||
if (!rootEl || !loadEl) return;
|
||||
if (!rootEl) {
|
||||
hideDocumentationPageLoadingOverlay();
|
||||
return;
|
||||
}
|
||||
|
||||
hideErr(errEl);
|
||||
rootEl.setAttribute("hidden", "hidden");
|
||||
while (rootEl.firstChild) rootEl.removeChild(rootEl.firstChild);
|
||||
loadEl.classList.remove("hidden");
|
||||
|
||||
updateBreadcrumbs(docPath);
|
||||
|
||||
var url = fetchUrlForPath(docPath);
|
||||
showDocumentationPageLoadingOverlay();
|
||||
try {
|
||||
hideErr(errEl);
|
||||
rootEl.setAttribute("hidden", "hidden");
|
||||
while (rootEl.firstChild) rootEl.removeChild(rootEl.firstChild);
|
||||
|
||||
updateBreadcrumbs(docPath);
|
||||
|
||||
var url = fetchUrlForPath(docPath);
|
||||
var r = await fetch(url, {
|
||||
headers: { Accept: "text/markdown, text/plain, */*" },
|
||||
});
|
||||
@@ -267,13 +315,11 @@
|
||||
/* raw */
|
||||
}
|
||||
showErr(errEl, "Не удалось загрузить документ: " + (detail || r.statusText));
|
||||
loadEl.classList.add("hidden");
|
||||
applyDocumentationTabTitle("");
|
||||
return;
|
||||
}
|
||||
|
||||
renderMarkdownToRoot(text, docPath, rootEl, errEl, loadEl);
|
||||
loadEl.classList.add("hidden");
|
||||
renderMarkdownToRoot(text, docPath, rootEl, errEl);
|
||||
|
||||
var newUrl = docUrlForPath(docPath);
|
||||
if (push) {
|
||||
@@ -283,8 +329,9 @@
|
||||
}
|
||||
} catch (e) {
|
||||
showErr(errEl, "Ошибка: " + (e.message || String(e)));
|
||||
loadEl.classList.add("hidden");
|
||||
applyDocumentationTabTitle("");
|
||||
} finally {
|
||||
hideDocumentationPageLoadingOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +356,10 @@
|
||||
|
||||
function run() {
|
||||
var rootEl = document.getElementById("readme-doc-root");
|
||||
if (!rootEl) return;
|
||||
if (!rootEl) {
|
||||
hideDocumentationPageLoadingOverlay();
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener("popstate", onPopState);
|
||||
rootEl.addEventListener("click", onRootClick);
|
||||
|
||||
Reference in New Issue
Block a user