mirror of
https://github.com/TronoSfera/Law.git
synced 2026-05-18 18:13:46 +03:00
Task P052-P053 fix
This commit is contained in:
parent
4b9b2df2e3
commit
5ff2a32087
6 changed files with 97 additions and 9 deletions
|
|
@ -920,6 +920,15 @@
|
||||||
background: rgba(255, 255, 255, 0.015);
|
background: rgba(255, 255, 255, 0.015);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Main table data lives in its own scroll area; controls and pager remain outside of it. */
|
||||||
|
.table-scroll-region {
|
||||||
|
min-height: 240px;
|
||||||
|
max-height: clamp(260px, 50vh, 620px);
|
||||||
|
overflow: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
scrollbar-gutter: stable both-edges;
|
||||||
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
|
|
@ -965,6 +974,19 @@
|
||||||
letter-spacing: 0.06em;
|
letter-spacing: 0.06em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-scroll-region thead th {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 2;
|
||||||
|
background: linear-gradient(160deg, rgba(23, 34, 46, 0.98), rgba(16, 24, 33, 0.98));
|
||||||
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.05);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-scroll-region tbody tr:last-child td {
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.sortable-th {
|
.sortable-th {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
@ -1148,6 +1170,27 @@
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-footer-bar {
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 0.55rem 0.65rem;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-top: none;
|
||||||
|
border-radius: 0 0 12px 12px;
|
||||||
|
background: linear-gradient(160deg, rgba(18, 28, 37, 0.96), rgba(13, 20, 28, 0.98));
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-scroll-region + .table-footer-bar {
|
||||||
|
margin-top: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-toolbar + .table-scroll-region {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.status {
|
.status {
|
||||||
margin: 0.6rem 0 0;
|
margin: 0.6rem 0 0;
|
||||||
min-height: 1.1rem;
|
min-height: 1.1rem;
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ const NEW_REQUEST_CLIENT_OPTION = "__new_client__";
|
||||||
|
|
||||||
function DataTable({ headers, rows, emptyColspan, renderRow, onSort, sortClause }) {
|
function DataTable({ headers, rows, emptyColspan, renderRow, onSort, sortClause }) {
|
||||||
return (
|
return (
|
||||||
<div className="table-wrap">
|
<div className="table-wrap table-scroll-region">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
@ -120,7 +120,7 @@ const NEW_REQUEST_CLIENT_OPTION = "__new_client__";
|
||||||
|
|
||||||
function TablePager({ tableState, onPrev, onNext, onLoadAll }) {
|
function TablePager({ tableState, onPrev, onNext, onLoadAll }) {
|
||||||
return (
|
return (
|
||||||
<div className="pager">
|
<div className="pager table-footer-bar">
|
||||||
<div>
|
<div>
|
||||||
{tableState.showAll
|
{tableState.showAll
|
||||||
? "Всего: " + tableState.total + " • показаны все записи"
|
? "Всего: " + tableState.total + " • показаны все записи"
|
||||||
|
|
@ -389,7 +389,7 @@ const NEW_REQUEST_CLIENT_OPTION = "__new_client__";
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", gap: "0.6rem", flexWrap: "wrap" }}>
|
<div style={{ display: "flex", gap: "0.6rem", flexWrap: "wrap" }}>
|
||||||
<button className="btn" type="submit">
|
<button className="btn" type="submit">
|
||||||
Добавить/Сохранить
|
{draft.editIndex !== null ? "Сохранить" : "Добавить"}
|
||||||
</button>
|
</button>
|
||||||
<button className="btn secondary" type="button" onClick={onClear}>
|
<button className="btn secondary" type="button" onClick={onClear}>
|
||||||
Очистить все
|
Очистить все
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,7 @@ export function ConfigSection(props) {
|
||||||
<div className="section-head">
|
<div className="section-head">
|
||||||
<div>
|
<div>
|
||||||
<h2>Справочники</h2>
|
<h2>Справочники</h2>
|
||||||
<p className="breadcrumbs">{"Справочники -> " + (configActiveKey ? getTableLabel(configActiveKey) : "Справочник не выбран")}</p>
|
<p className="breadcrumbs">{configActiveKey ? getTableLabel(configActiveKey) : "Справочник не выбран"}</p>
|
||||||
<p className="muted">Выберите справочник в дереве слева.</p>
|
|
||||||
</div>
|
</div>
|
||||||
<button className="btn secondary" type="button" onClick={() => loadCurrentConfigTable(true)}>
|
<button className="btn secondary" type="button" onClick={() => loadCurrentConfigTable(true)}>
|
||||||
Обновить
|
Обновить
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,14 @@
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: #c6d4e8;
|
color: #c6d4e8;
|
||||||
min-height: 2.8rem;
|
min-height: 2.8rem;
|
||||||
|
transition: opacity 0.42s ease, transform 0.42s ease;
|
||||||
|
will-change: opacity, transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.consultation-quote.is-transitioning p,
|
||||||
|
.consultation-quote.is-transitioning .quote-meta {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
section { padding: 1.3rem 0 2.2rem; }
|
section { padding: 1.3rem 0 2.2rem; }
|
||||||
|
|
@ -359,6 +367,15 @@
|
||||||
margin-top: 0.7rem;
|
margin-top: 0.7rem;
|
||||||
color: #98adc7;
|
color: #98adc7;
|
||||||
font-size: 0.86rem;
|
font-size: 0.86rem;
|
||||||
|
transition: opacity 0.42s ease, transform 0.42s ease;
|
||||||
|
will-change: opacity, transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.consultation-quote p,
|
||||||
|
.quote-meta {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.expert {
|
.expert {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
const quoteText = document.getElementById("quote-text");
|
const quoteText = document.getElementById("quote-text");
|
||||||
const quoteMeta = document.getElementById("quote-meta");
|
const quoteMeta = document.getElementById("quote-meta");
|
||||||
|
const quoteWrap = quoteText ? quoteText.closest(".consultation-quote") : null;
|
||||||
const featuredTeamSection = document.getElementById("team");
|
const featuredTeamSection = document.getElementById("team");
|
||||||
const featuredTeamTrack = document.getElementById("featured-team-track");
|
const featuredTeamTrack = document.getElementById("featured-team-track");
|
||||||
const featuredTeamDots = document.getElementById("featured-team-dots");
|
const featuredTeamDots = document.getElementById("featured-team-dots");
|
||||||
|
|
@ -120,6 +121,33 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadQuotes() {
|
async function loadQuotes() {
|
||||||
|
let quoteTransitionTimer = 0;
|
||||||
|
const reducedMotion = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||||
|
|
||||||
|
const setQuoteContent = (quote) => {
|
||||||
|
if (!quoteText || !quoteMeta) return;
|
||||||
|
quoteText.textContent = String(quote?.text || "");
|
||||||
|
quoteMeta.textContent = [quote?.author, quote?.source].filter(Boolean).join(" • ");
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderQuote = (quote) => {
|
||||||
|
if (!quoteText || !quoteMeta) return;
|
||||||
|
if (!quoteWrap || reducedMotion) {
|
||||||
|
setQuoteContent(quote);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (quoteTransitionTimer) {
|
||||||
|
clearTimeout(quoteTransitionTimer);
|
||||||
|
quoteTransitionTimer = 0;
|
||||||
|
}
|
||||||
|
quoteWrap.classList.add("is-transitioning");
|
||||||
|
quoteTransitionTimer = window.setTimeout(() => {
|
||||||
|
setQuoteContent(quote);
|
||||||
|
quoteWrap.classList.remove("is-transitioning");
|
||||||
|
quoteTransitionTimer = 0;
|
||||||
|
}, 320);
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/public/quotes?limit=8&order=random");
|
const response = await fetch("/api/public/quotes?limit=8&order=random");
|
||||||
if (!response.ok) throw new Error("quotes fetch failed");
|
if (!response.ok) throw new Error("quotes fetch failed");
|
||||||
|
|
@ -128,15 +156,16 @@
|
||||||
let index = 0;
|
let index = 0;
|
||||||
const render = () => {
|
const render = () => {
|
||||||
const quote = items[index % items.length];
|
const quote = items[index % items.length];
|
||||||
quoteText.textContent = quote.text;
|
renderQuote(quote);
|
||||||
quoteMeta.textContent = [quote.author, quote.source].filter(Boolean).join(" • ");
|
|
||||||
index += 1;
|
index += 1;
|
||||||
};
|
};
|
||||||
render();
|
render();
|
||||||
if (items.length > 1) setInterval(render, 5500);
|
if (items.length > 1) setInterval(render, 5500);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
quoteText.textContent = "С вами работает дружный коллектив профессионалов. Мы уверены в вашем успехе.";
|
renderQuote({
|
||||||
quoteMeta.textContent = "Команда компании";
|
text: "С вами работает дружный коллектив профессионалов. Мы уверены в вашем успехе.",
|
||||||
|
author: "Команда компании",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in a new issue