oCBot — дизайн-система

Жива сторінка-еталон: підключає бойові CSS прошивки, тому завжди відображає актуальний стан. Правила та план — у UI_STYLE_UNIFICATION_PLAN.md. Сторінка НЕ вбудовується у прошивку.

1. Дизайн-токени (палітра)

Єдине джерело правди — блок :root у global.css. У коді — тільки var(--rb-*).

--rb-green
#1B4D3E
--rb-gold
#D4AF37
--rb-gold-light
#E5C387
--rb-cream
#F9F4E8
danger @ 0.12
безпека/аварії
--rb-gradient-gold
gold @ 0.2
лінії модалок
gold @ 0.35
рамки карток
green @ 0.05
тло шапок
green @ 0.12
лінії секцій
--rb-text-body
--rb-text-muted
Палітра периферії (16 кольорів) — приглушені, видимі на білому, чітко відмінні
Кожен колір задається одним hex; відтінки AD22 (on/off) генеруються автоматично. Нижче кожного свотча — пастельний фон (0.18), як на плитці обраного пристрою.
2. Типографіка
Заголовок модалки / сторінки --rb-font-display, 700, --rb-green (.modal-premium .modal-title)
Заголовок секції налаштувань .settings-section-title — 1.05rem, 700, зелений, лінія знизу
Секційний заголовок-капс --rb-fs-caption (0.72rem), капс — шапки таблиць та блоків віджетів
Підпис поля форми form-label fw-semibold + --rb-green
Дрібний текст віджетів (0.78rem) --rb-fs-small + --rb-text-body
23.5 °C Цифрове значення показу — прямий (не курсив), 700, --rb-green, адаптивний clamp(1.4rem → 4rem); одиниця виміру дрібніша (≈0.8rem). Поточний шрифт (Fixel/системний), без вбудовування.
3. Кнопки та контроли
Кнопки модалок
Іконкові дії (.icon-btn) — завжди без рамки, лише іконка
Видалення/редагування/додавання — завжди .icon-btn без рамки (не btn-outline-*), єдиний вигляд на картках і в модалках.
Кнопки керування скриптом (старт / стоп / параметри / налаштування)
(етап 4 плану: перевести на .icon-btn)
Степер оперативного параметра (.rb-stepper: −/+, клавіатура)
Кнопки нейтральні у палітрі (золотий hover), а не червоний/зелений — зменшення значення не «небезпека». Застосовується лише до оперативних величин; конфігураційні поля (мережа, Modbus, baud) лишаються звичайними інпутами.
4. Бейджі станів
Працює Пауза Зупинено Вимкнено Невідомо останній — .alarm-flag-badge: позначка "може сигналізувати аварію" (іконка alarm.svg єдиного розміру)
5. Статус-бар шапки (.top-status-chip)

Помітні чіпи з пульсуючою точкою стану. Детальна інформація — у спливаючій підказці (наведіть курсор на чіп).

Онлайн Немає з'єднання З'єднання... 12:34:56
Зміст підказки з'єднання: стан, ім'я пристрою, IP, версія прошивки, час підключення, кількість перепідключень. Підказка годинника: повна дата, NTP-сервер, часовий пояс.
Центр сповіщень: дзвінок з кольоровим лічильником + панель історії
Сповіщення
Аварія: перевищено поріг температури12:30:05
Параметри автоматично скориговано до лімітів ТЕНів12:28:41
Перепідключення до контролера12:25:10
Параметри скрипта збережено12:24:58
Усі повідомлення (notyf) дублюються в історію. Колір лічильника = найвищий рівень непрочитаних (червоний > жовтий > синій). У списку кожне підфарбоване за рівнем; toast лишається для миттєвого показу.
6. SCADA-віджети
70.0°C
Кругова шкала (radial)
Резервуар (level)
24.6°C
0 °C100 °C
Лінійний (.rbl) — температура + маркер-ціль
1800Вт
0 Вт3000 Вт
Лінійний (.rbl) — потужність
Значення пристрою у плитці (.rb-tile-value) — єдиний формат
Двигун/Мішалка Мішалка - 40Гц
Величина з напрямом: стрілка + «- 40» + одиниця
Датчик/Куб 22.852°C
Є ціль: факт ▶︎ уставка + SCADA-смуга з маркером
Датчик/Пара 78.4
Без цілі — саме значення
Клапан/Вода УВІМК
Дискретний вихід — індикатор, не число
Усі інлайн-значення периферії (плитки «Пристрої скрипта», закріплені покази, віджети пульта, сторінка виконання) малює лише render_peripheral_value_inner_html(uid, raw) — і перший рендер, і живе оновлення (data-widget-val-uid). Знак відділений пробілом від числа (- 40, не -40), напрям показується графічно (▶︎ вперед · ◀︎ реверс · ■︎ стоп), одиниця — дрібніша. Джерело напряму одне для всіх показів — vfd_resolve_dir(), розклад значення — vfd_value_parts(), HTML — render_vfd_value_html().
Ціль (уставка) — лише коли вона РЕАЛЬНО ДІЄ (скрипт-власник запущений, state == 1): у зупиненого скрипта це збережений параметр, а не ціль процесу, і малювати його у віджеті означає видавати конфіг за стан. Діє — скрізь однаково: 22.8 ▶︎ 52 °C (факт, стрілка «прямує до», ціль, одиниця одна на обидва числа; уставка приглушена, бо вторинна щодо факту) плюс SCADA-смуга: заливка = реальне значення, зелений маркер = ціль. Смуга — той самий render_linear_gauge({ compact: true }) (лише доріжка, без верхнього числа й шкали), діапазон — peripheral_gauge_range(uid, target). HTML — render_value_with_target_html(), SVG-сцена — value_with_target_text(). Саму ціль дає лише peripheral_target_value(uid) з декларації target: { place, param } у BASIC_SCRIPT_METADATA: джерело уставки — скрипт, що її тримає (шар 3), а не обчислення в UI. Нова ціль = один рядок декларації, не код у місці показу.
Правила гейджів — ТРИ ШАРИ (обов'язкові)
Шар 1 — один компонент на всю систему. Радіальний render_gauge(cfg) і лінійний render_linear_gauge(cfg)єдиний уніфікований код, який у різних місцях виводить різні значення. Місце застосування лише будує свій cfg (value / valueText / unit / min / max / target / status / extra / zones / bottomArc / scada). Другої реалізації шкали (свій SVG, div-прогрес) не створюємо — бракує можливості, розширюємо cfg. Живе оновлення — rb_gauge_update_fill() / rb_linear_gauge_update_fill().
Шар 2 — один пристрій/сутність = один фрагмент коду. Гейдж конкретної сутності будує рівно одна функція (скрипти/сценарії — render_script_gauge_html(item); периферія — render_peripheral_linear_gauge_html(UID, kind), render_vfd_peripheral_gauge_html(UID)), і всі місця показу (картка, сторінка виконання, пульт оператора, модалка) викликають саме її. Копія «майже такого самого» гейджа під окрему сторінку — заборонена; різниця подачі — параметр (opts) тієї ж функції.
Шар 3 — показуємо лише системні стани, а не власні здобутки. Гейдж/віджет відображає те, що дає прошивка (показники global_log_variables, стан скрипта/сценарію/периферії), і не обчислює похідних сам (ні середніх, ні прогресу, ні ETA, ні «додуманої» цілі). Потрібна нова величина — її рахує скрипт і публікує через set_global_log_variable / register_indicator; UI лише малює. Немає даних → --, а не вигадане чи локально пораховане значення.
Універсальний render_linear_gauge(cfg) — той самий cfg, що й render_gauge() (value / valueText / unit / min / max / target / scada), тож радіальний ↔ лінійний перемикаються без зміни даних. Число-величина + одиниця зверху, смуга із заливкою (частка у [min,max]) і glow, шкала min/max, опційний зелений маркер-ціль (уставка). Живий показ — через scada-атрибут (.gauge-value), як у радіального.
7. Віджет пульта оператора (повна композиція)
Рівень води 1
UID: 4
Рівень води
Статус: Працює
Фільтрація шуму датчиків
Температура терма >
Пристрої скрипта
Рівень датчик_верх ON
Датчики аварії
Температура терма 23.5 °C
Віджет скрипта: шкала → статус → параметри → пристрої → безпека
терма
t_1
23.5°C
Віджет периферії (датчик)
8. Плитки даних (.rb-tile) — замість таблиць

Принцип: кожен запис — окрема самостійна плитка (рядок або колонка), без вкладених таблиць і контейнерів-обгорток. Групи розділяються заголовком-капсом .rb-tile-caption.

Перемикач режиму списку (рядки / картки) — натисніть кнопки праворуч
Список периферії
Температура терма23.5 °C
Насос подачіУВІМК
Рівень верхній76 %
Клапан зливуВИМК
Ті самі плитки, два режими: .rb-tile-list (рядки) ↔ .rb-tile-list--cards (метрика-картка з крупним центрованим значенням). Перемкніть угорі. Числові сенсори — крупне число, дискретні виходи (реле/клапан) — кольоровий індикатор .rb-state.
Кольоровий індикатор дискретного стану (.rb-state)
УВІМК ВИМК АВАРІЯ зелений = активний, сірий = неактивний, червоний = тривога
Плитки параметрів модалки «Параметри скрипта» (назва + контрол + опис)
Параметри скрипта
Цільова температура
Оперативний параметр, застосовується кнопкою «Зберегти»
Фільтрація шуму датчиків
Час стабільності стану, с
Параметри безпеки
Температура терма >
Порогове значення для датчика аварії — застосовується одразу
Плитка-рядок статусу (назва + значення) та плитка-колонка (назва + контрол)
Температура терма 23.5 °C
Тиск колони 1.2 бар
Цільова потужність
Плитка прив'язки периферії (вкладка «Периферія» налаштувань скрипта)
Рівень (підточка 1) level_high
Клапан (реле) tank_filling
Плитка умови безпеки (вкладка «Безпека»: іконка | датчик | умова | поріг)
9. Плитки вибору та маска периферії
Маленькі плитки вибору (.device-type-tile) — вертикально: іконка / тип / назва (.dtt-name, за потреби); усе центровано, зони фіксованої висоти (рядки вирівнюються між плитками); вибрана — .active
Термостат
Рівень води
Керування нагрівом
ТемператураПара колони
НасосПодача браги
Уніфікована маска периферії: ICON Тип Назва (get_peripheral_display_html)
Температура терма Насос насос_подачі Реле релюха іконка фарбується кольором конкретного пристрою
10. Картки розділів

Єдиний вигляд карток-елементів у всіх розділах: біле тло, золота рамка, радіус --rb-radius-lg, м'яка тінь, hover з підняттям. Картка з кольором пристрою — пастельні шапка й футер (--card-rgb), тіло біле.

Картка скрипта/сценарію/пульта (.script-card)
Термостат 1
Працює

Підтримання цільової температури

62°C
Картка периферії (.peripheral-card) — пастельні шапка й футер у кольорі пристрою
терма
Температура io_3v3
23.5°C
Клапан зливу
Клапан relays
ВИМК
Адаптивна сітка: сенсори row-cols-1 sm-2 lg-3 xxl-4, скриптові row-cols-1 md-2 lg-3 (4 колонки лише ≥1400px — щоб на 13-14" не тісно).
11. Модальне вікно (.modal-premium)

Використання: <div class="modal fade modal-premium"> — стилі content/header/title/footer застосовуються автоматично, інлайни не потрібні.

12. Копіювання ідентифікаторів (.rb-copy-id + модалка ID)

ID — вторинна технічна інформація: у тілі картки її не показуємо. У футері — іконка «ID» (id.svg) → модалка #idInfoModal (show_id_modal('peripheral'|'board', uid)) зі списком: периферія — Дескриптор / UID / Плата; плата — Повний ID / Тип / Модель. Кожен рядок — підпис + кнопка .rb-copy-id; по кліку rb_copy_id_feedback() змінює іконку на галочку на ~1.5 с, без notyf (щоб не засмічувати центр сповіщень-дзвінок). Прихованих copy-on-click (бейдж із onclick=copyToClipboard) не робимо.

Кнопка .rb-copy-id — натисни, зʼявиться галочка
Вміст модалки ідентифікаторів (рядки .rb-id-row)
Дескриптор
UID
Плата
Іконка-кнопка «ID» у футері картки
id.svg — відкриває модалку ідентифікаторів
13. Картки скриптів і сценаріїв (єдиний клас)

Один шаблон build_script_card_html(item, opts) для обох розділів. Стиль як у периферії: пастельна шапка кольором пристрою (--card-rgb з палітри — вкладка «Загальні» налаштувань, script_color_<uid>), іконка без рамки, бейдж стану в шапці праворуч, центральна зона .sc-zone (етап + помітна дія .sc-action), розділений футер (конфіг ліворуч, ID/видалення праворуч). Аварія → червоний акцент (.sc-state-fault). Активні/аварійні — зверху. ID на картці не дублюється (він у модалці «ID»), а опис подається через блакитний бейдж довідки .rb-help у шапці (Bootstrap-popover, trigger="hover focus" — і наведення, і тап). Контент довідки — дата-керований за ідентифікатором (i18n help_<рід>-<тип>, майбутнє — портал); хелпер rb_help_badge_html(), ініт rb_init_help_popovers(). Той самий бейдж — і на картках периферії/плат/пультів. Картки пультів оператора — той самий .script-card--unified (шапка пастель за станом: активний зелений / ні золотий), у тілі — перелік елементів пульта (крапка стану + назва) через render_panel_elements_html(). Усі шапки картокalign-items-center (елементи центровані по висоті).

Сценарій ББК
Працює
Етап: Нагрів колони
Термостат 1
Зупинено
Етап:
Рівень води 1
Аварія
Етап: Немає підживлення
14. Картка периферії (нова анатомія)

Уніфікована з картками скриптів. Шапка (верхня панель): іконка + назва + статус-бейджі праворуч — .rb-help (синій «?» — довідка-popover) і .rb-idbadge (золотий «ID»), що відкриває модалку ідентифікаторів (прогресивне розкриття; технічні дані — у модалці, не на картці). Робоча область (тіло): SCADA-віджет — якщо передбачено: круговий гейдж (VFD), число+одиниця (сенсори/аналог); для дискретних виходів — число, якщо є дані (напр. потужність нагрівача), інакше індикатор AD22. Нижня панель (футер): усі елементи керування разом із кнопкою редагування setting.svg — для VFD один рядок: ◀ ■ ▶ + степер; для дискретних — Bootstrap-перемикач (render_peripheral_bootstrap_switch_html); для аналогових — степер. ID-модалка містить технічні метадані (тип, інтерфейс, порт/канал, параметр) + дескриптор + UID (+ плата). Хелпер бейджа: rb_id_badge_html(kind, key, title).

Температура колони
24.6°C
Клапан води
Мішалка (VFD)
Гц
25
Гойдалка (VFD)
15. Правила оформлення (коротко)
  1. Кольори/шрифти — тільки var(--rb-*); нових hex у коді не з'являється.
  2. Модалка — завжди .modal-premium; кнопки: золота основна + контурна другорядна.
  3. Іконкові дії (старт/стоп/параметри/налаштування/видалення/…) — завжди .icon-btn без рамки; у JS будувати через rb_icon_btn(svg, onclick, title) — єдиний розмір (44px/34px) та hover скрізь.
  4. Доступність — touch-target ≥ 44px, :focus-visible із золотим outline, aria-label на icon-only кнопках, @media (prefers-reduced-motion: reduce) вимикає пульсації.
  5. Дані — окремими плитками .rb-tile (рядок або колонка), без вкладених таблиць і контейнерів-обгорток; групи розділяються .rb-tile-caption.
  6. Блоки безпеки — модифікатори .rb-tile--safety / .rb-tile-caption--safety (пастельно-червоне тло).
  7. Периферія в UI — лише через get_peripheral_display_html/text() (маска «ICON Тип Назва», UID — у title).
  8. Параметри скриптів — фільтр is_operative_script_param().
  9. Нові тексти — одразу через i18n (ua.json + en.json).
  10. JS-шаблони — без інлайн-стилів, окрім обчислюваних значень.
  11. Стиль для 2+ сторінок — у global.css; для однієї — у файл сторінки.
  12. !important — лише з коментарем, чому без нього не можна.
  13. Картки розділів — .script-card / .peripheral-card / .cp-widget: єдина золота рамка, радіус, hover; колір пристрою — пастельна шапка через --card-rgb, тіло/футер білі.
  14. Скрипти й сценарії — одна функція build_script_card_html() (.script-card--unified): шапка кольором з палітри + бейдж стану, центральна зона .sc-zone з пуск/стоп, розділений футер; колір у localStorage script_color_<uid>.
  15. Опис картки — блакитний бейдж довідки .rb-help у шапці (popover, hover+тап); ID на картці не дублюємо (він у модалці). Контент — за ідентифікатором (i18n help_<тип>, далі портал); хелпери rb_help_badge_html() / rb_init_help_popovers().
  16. Сітка карток — 4 колонки лише на xxl (≥1400); сенсори sm-2 lg-3 xxl-4, скриптові md-2 lg-3.
  17. Ідентифікатори — кнопка «ID» (id.svg) у футері → модалка #idInfoModal; копіювання лише через видиму .rb-copy-id з локальною галочкою (rb_copy_id_feedback), без notyf і без прихованих copy-on-click.