Дизайн-система аналітичних інструментів
Спільна дизайн-система для внутрішніх аналітичних інструментів Abitly (дашборди, звіти, публічні data-viz-поверхні). Дистильована з live-дашборда «Вступ 2026» (референс-реалізація). Мета — щоб кожен наступний аналітичний інструмент виглядав як частина одного продукту й будувався за перевіреним патерном, без зайвих залежностей.
Джерело істини коду: .context/vstup-2026-live/assets/{style.css,app.js}.
Принципи
Section titled “Принципи”- Темна, one-accent. Один акцент (тепла помаранчева
--acc:#ff8f2e) на глибокому синьо-чорному тлі. Другий колір (--edboсиній) — лише для «порівняльної» серії. Semantic (ok/warn/bad) — точково. Мультисерійні графіки — окрема стримана палітра (нижче). - 0 залежностей. Vanilla JS + CSS, графіки — інлайновий SVG (жодних Highcharts/D3/Chart.js).
Чому: повний контроль над темною темою, self-contained (працює офлайн, один HTML),
мікро-вага, нічого не «протікає» стилями. Ідіом графіка —
<path>/<rect>уviewBox. - snapshot-once, read-from-cache. Уся важка аналітика рахується рідко (cron) і
матеріалізується в один незмінний
snapshot.json; сторінка — статика, читає лише його з CDN → 0 запитів у БД на візит, тримає вірусний сплеск. Деталі патерну — ARCHITECTURE дашборда. - Кожен блок self-contained для скріншота. Картка має бренд-підвал (лого + джерело +
abitly.org), що «виживає» вирізаним у канал/медіа поза контекстом сторінки. - Тільки реальні дані + чесність про прогалини. Нічого не вигадуємо. Якщо у даних немає щоденної історії — показуємо знімок, підписаний як знімок, а не малюємо фейкову криву (див. морф прогноз→реальність).
- Табличні цифри всюди. Клас
.num(font-variant-numeric: tabular-nums lining-nums) на кожному числі — щоб лічильники не «стрибали» під час анімації. - Повага до
prefers-reduced-motion— усі анімації/переходи вимикаються.
Дизайн-токени
Section titled “Дизайн-токени”Єдине джерело кольору/розмірів — CSS-змінні у :root. Копіюй блок як є:
:root{ /* поверхні */ --bg:#0a0f14; --bg-glow:#12202b; --card:#111a21; --card2:#152029; --chip:#0e161c; --line:#1e2a33; --line2:#17222a; /* текст (4 рівні контрасту) */ --ink:#eef4f8; --ink2:#c2cfd8; --muted:#7e909d; --faint:#54636e; /* акцент (один) */ --acc:#ff8f2e; --acc-ink:#ffab5c; --acc-soft:rgba(255,143,46,.13); --acc-line:rgba(255,143,46,.32); /* порівняльна серія (напр. зовнішнє джерело) */ --edbo:#4a9eef; --edbo-ink:#8fc2f5; /* semantic */ --ok:#42d07f; --warn:#f0c33c; --bad:#f2635a; /* розмір/форма/шрифт */ --pad:clamp(18px,2.4vw,26px); --radius:20px; --maxw:1120px; --font:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;}Мультисерійна палітра графіків (теплий→холодний рамп, стриманий, читається на тлі) + нейтральний «Інші»:
const STREAM_COLORS = ['#ff7a3d','#ff9e4f','#ffc15b','#ffdf7a','#d7cf5f','#9fce77', '#5fc79a','#46b5b8','#49a0d4','#5b86e0','#8a7de6','#b56fd0'];const STREAM_OTHER = '#3f4f5b'; // згорнутий хвіст «Інші»Фон сторінки — тло + м’який радіальний глоу згори:
background-image:radial-gradient(1200px 520px at 50% -180px, var(--bg-glow) 0%, rgba(18,32,43,0) 70%).
Розкладка
Section titled “Розкладка”- 12-колонкова сітка
.grid(gap:clamp(13px,1.7vw,18px)); картки беруть.c4/.c5/.c6/.c7/.c8/.c12. Наmax-width:820pxусе згортається в одну колонку. - Контейнер
.wrap{max-width:var(--maxw);margin:0 auto}. - Картка — градієнтне тло + бордер +
--radius,overflow:clip,display:flex;flex-direction:column(щоб бренд-підвал притискався донизу черезmargin-top:auto):
.card{ background:linear-gradient(180deg,var(--card) 0%,var(--card2) 140%); border:1px solid var(--line); border-radius:var(--radius); padding:var(--pad); min-width:0; overflow:clip; position:relative; display:flex; flex-direction:column; }.card .head{ display:flex; justify-content:space-between; align-items:flex-start; gap:12px; margin-bottom:14px }.card h3{ font-size:15px; font-weight:700; letter-spacing:-.01em; color:var(--ink) }.card .sub{ font-size:12.5px; color:var(--muted); margin-top:3px }Компоненти
Section titled “Компоненти”| Компонент | Клас(и) | Призначення |
|---|---|---|
| Hero-метрика | .hero .big + .kpis .kpi | одна велика цифра (clamp(52px,12vw,108px)) + сітка 4 KPI |
| Тег-бейдж | .tag.live / .tag.db / .tag.bench / .tag.plan | маркер джерела/статусу блоку (pill, uppercase) |
| Бренд-підвал | .brand (.logo/.src/.url) | самодостатність скріншота: лого + джерело + abitly.org |
| Дво-смугний список | .bars .brow .mbar .mfill.a/.b | порівняння двох серій на напрям/ЗВО (акцент vs --edbo) |
| Пігулки-фільтри | .pill (.on) | вибір предмета/зрізу |
| Перемикач | .switch (.switch-track/.switch-knob/.switch-txt) | режим блоку (напр. «прогноз ⇄ реальність») |
| Крива-роадмап | .road .step (.done/.active/.next) | таймлайн дат/етапів |
| Бейдж свіжості | .freshness (.stale) | «станом на …» + пульсуюча крапка .dot |
Пульс акценту (жива крапка) — @keyframes pulse на .dot; анімація лічильника — easing
1 - (1-t)³ у JS-хелпері countUp().
Графіки — inline-SVG-ідіом
Section titled “Графіки — inline-SVG-ідіом”Спільні правила для будь-якого графіка:
- Адаптивний SVG:
<svg viewBox="0 0 1000 H" preserveAspectRatio="none">+ CSSsvg{display:block;width:100%;height:auto;overflow:visible}. Уся геометрія рахується в просторіviewBox(ширина 1000), розтягується під контейнер. - Осі: класи
.axis-lbl(fill:var(--faint)) і.grid-line(stroke:var(--line2)). - Hover-тултип
.ctip— абсолютно позиційований, з edge-flip (панель стає з протилежного від курсора боку й повністю влазить у картку, без обрізання цифр) + вертикальна пунктирна лінія-приціл.#chart{position:relative}обов’язково.
Готові патерни (усі хендрольнуті, у renderXxx() у app.js):
- Area-curve — кумулятивна крива (area-fill градієнт
--acc→ прозорий + лінія з glow), hover-крапка + tooltip за будь-який день. - Bar-histogram — розподіл (напр. балів) із підсвіченим бакетом + перцентиль-вердикт.
- Streamgraph — «річка» напрямів у часі: центрована wiggle-база (
baseline = −total/2), inside-out порядок шарів (найбільші в центрі, «Інші» — на край), Catmull-Rom→cubic-bezier згладжування країв, топ-N + згорнутий хвіст «Інші», hover показує склад за день. - Forecast→reality морф — розширення стримграфа: смуги продовжуються за пунктирну межу
(
seam) у знімок реальності (лінійний морф з останньої точки прогнозу в реальну кінцеву величину, підписана зона). Патерн для будь-якого «прогноз → факт», коли у факту немає щоденної історії.
Пайплайн даних (для нового інструмента)
Section titled “Пайплайн даних (для нового інструмента)”- Write-path (рідко, cron): read-only-збір агрегатів з прод-БД (SSM-тунель,
SET default_transaction_read_only=on; statement_timeout, команда-виключення, нуль ПД)- зовнішні джерела →
build_snapshot.pyзливає й рахує похідні →snapshot.json.
- зовнішні джерела →
- Публікація: заливка
snapshot.jsonна CDN/CF Pages + purge шляху (атомарно — заміна одного файлу; сайт ніколи не бачить напівстан). - Read-path (кожен візит):
fetch('data/snapshot.json')— один запит, повністю з edge. Опційно другий файлlive.jsonдля швидких лічильників (короткий TTL, клієнт поллить). - Свіжість чесно: бейдж «станом на …» показує реальний
generated_at, не імітує realtime.
Кешування (edge): snapshot.json — max-age=300, stale-while-revalidate=86400; іммутабельні
ассети (app.js/style.css з хешем) — max-age=31536000, immutable.
Як застосувати до нового інструмента
Section titled “Як застосувати до нового інструмента”- Скопіюй блок токенів
:root+.num+ reduced-motion-guard. - Візьми
.grid+.card(+.head/.sub/.tag/.brand) як каркас блоків. - Для чисел — hero/KPI-патерн; для порівнянь — дво-смугний список; для розрізів — пігулки/перемикач.
- Графік — обери один із inline-SVG-патернів; не тягни чарт-бібліотеку.
- Дані — snapshot-once write-path (read-only, PII-free), сторінка читає лише
snapshot.jsonз CDN. - Чесність: немає щоденної історії → знімок, підписаний як знімок; кожен блок має бренд-підвал.
- Гейт: працює офлайн з одного HTML+JSON; перевір скріншот кожного блоку окремо.
Зв’язки
Section titled “Зв’язки”- Live-дашборд «Вступ 2026» — референс-реалізація цієї системи.
- abitly-analytics — сусідня аналітична поверхня (
abitly.org/analytics) тієї ж моделі «снапшот замість live-обчислень». - simulation — типове джерело продуктових даних для таких інструментів.