Initial commit: site monorepo with API, web, and infra.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
влад
2026-07-16 10:11:54 +03:00
co-authored by Cursor
commit 016910ffb7
447 changed files with 73972 additions and 0 deletions
@@ -0,0 +1,202 @@
/**
* Bootstrap shell-модалки (.wesp-shell-modal) — единая анимация открытия/закрытия.
*/
(function (global) {
const WIRED = "data-wesp-shell-modal-wired";
const ALLOW_HIDE = "data-wesp-shell-allow-hide";
const MODAL_MS = 240;
function prefersReducedMotion() {
return global.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches ?? false;
}
function getDialog(el) {
return el?.querySelector(".modal-dialog--shell");
}
function wireShellModal(el) {
if (!el || el.getAttribute(WIRED)) return;
el.setAttribute(WIRED, "1");
el.addEventListener("show.bs.modal", function () {
el.classList.remove("wesp-shell-closing");
if (prefersReducedMotion()) {
el.classList.add("wesp-shell-visible");
return;
}
el.classList.remove("wesp-shell-visible");
requestAnimationFrame(function () {
requestAnimationFrame(function () {
el.classList.add("wesp-shell-visible");
});
});
});
el.addEventListener("shown.bs.modal", function () {
el.removeAttribute("aria-hidden");
});
el.addEventListener("hide.bs.modal", function (e) {
if (el.getAttribute(ALLOW_HIDE) === "1") {
el.removeAttribute(ALLOW_HIDE);
el.classList.remove("wesp-shell-visible", "wesp-shell-closing");
return;
}
if (prefersReducedMotion()) {
el.classList.remove("wesp-shell-visible");
return;
}
e.preventDefault();
el.classList.add("wesp-shell-closing");
el.classList.remove("wesp-shell-visible");
const dialog = getDialog(el);
let finished = false;
const finish = function () {
if (finished) return;
finished = true;
el.setAttribute(ALLOW_HIDE, "1");
const instance = global.bootstrap?.Modal?.getInstance(el);
instance?.hide();
};
if (dialog) {
dialog.addEventListener(
"transitionend",
function (ev) {
if (ev.target === dialog) finish();
},
{ once: true }
);
}
global.setTimeout(finish, MODAL_MS + 50);
});
el.addEventListener("hidden.bs.modal", function () {
el.classList.remove("wesp-shell-closing", "wesp-shell-visible");
el.setAttribute("aria-hidden", "true");
});
}
function wireAllShellModals() {
document.querySelectorAll(".modal.wesp-shell-modal").forEach(wireShellModal);
}
function show(modalId) {
const el = document.getElementById(modalId);
if (!el) return null;
wireShellModal(el);
const instance = global.bootstrap?.Modal?.getOrCreateInstance(el, {
backdrop: true,
keyboard: true,
focus: true,
});
instance?.show();
return instance;
}
function hide(modalId) {
const el = document.getElementById(modalId);
if (!el) return;
const instance = global.bootstrap?.Modal?.getInstance(el);
if (instance) instance.hide();
}
function whenPageEnterDone(run) {
const html = document.documentElement;
let ran = false;
let observer = null;
let fallbackTimer = 0;
const once = function () {
if (ran) return;
ran = true;
if (observer) {
observer.disconnect();
observer = null;
}
if (fallbackTimer) {
global.clearTimeout(fallbackTimer);
fallbackTimer = 0;
}
requestAnimationFrame(run);
};
if (html.classList.contains("wesp-page-enter-done")) {
once();
return;
}
if (
!html.classList.contains("wesp-page-enter-pending") &&
!html.classList.contains("wesp-page-enter-ready")
) {
once();
return;
}
observer = new MutationObserver(function () {
if (!html.classList.contains("wesp-page-enter-done")) return;
once();
});
observer.observe(html, { attributes: true, attributeFilter: ["class"] });
fallbackTimer = global.setTimeout(function () {
if (!html.classList.contains("wesp-page-enter-done")) return;
once();
}, 1200);
}
function animateGridCards(gridSelector, options) {
if (prefersReducedMotion()) return;
const force = Boolean(options && options.force);
const run = function () {
const grid = document.querySelector(gridSelector);
if (!grid) return;
const cards = grid.querySelectorAll(".dispenser-card, .component-card, .report-card");
if (
!force &&
cards.length > 0 &&
Array.from(cards).every(function (card) {
return card.classList.contains("wesp-grid-enter-item");
})
) {
return;
}
cards.forEach(function (card, i) {
card.classList.remove("wesp-grid-enter-item");
card.style.removeProperty("--wesp-grid-i");
void card.offsetWidth;
card.style.setProperty("--wesp-grid-i", String(Math.min(i, 12)));
card.classList.add("wesp-grid-enter-item");
});
};
whenPageEnterDone(run);
}
function revealContent(el) {
if (!el || prefersReducedMotion()) return;
el.classList.remove("wesp-content-reveal");
void el.offsetWidth;
el.classList.add("wesp-content-reveal");
}
global.WespZootechModals = {
show,
hide,
wireAllShellModals,
animateGridCards,
revealContent,
prefersReducedMotion,
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", wireAllShellModals);
} else {
wireAllShellModals();
}
})(typeof window !== "undefined" ? window : globalThis);