Единая шапка для проектов kobets.info: текущий пользователь, его реалмы и часы-индикатор живости. Авторизацию шапка выясняет сама при загрузке страницы.
Версия шапки: 1.0.086 · файлы: embed.js, embed.css, loader.js
https://header.kobets.info/embed.js. Не копировать embed.js / embed.css
к себе в проект, не класть рядом «свою версию», не форкать. Любая копия молча отстаёт: у неё остаётся старый
вид и старое поведение, а чинят потом там, где копии нет. Один адрес — одна шапка на всех проектах.
В конце <body>, после контента:
<script src="https://header.kobets.info/embed.js"
id="kobets-header-script"
defer
data-realm="ваш_реалм"></script>
Всё. Контейнер создавать не нужно — виджет сам вставит <div id="kobets-header"> в начало
<body> (если хотите другое место — положите этот div сами). Стили виджет подгружает сам,
отдельный <link> не нужен. defer обязателен: без него скрипт блокирует разбор страницы.
| Атрибут | Обязателен | Зачем |
|---|---|---|
id="kobets-header-script" | да | по нему страница и диагностика находят тег шапки |
data-realm | да | идентификатор реалма проекта в Key (net, home, tracker…) |
data-auth-url | нет | эндпоинт вашего сервиса, который знает сессию: шапка сама спросит его при загрузке (см. п. 3) |
data-key-auth | нет | разрешить шапке спрашивать ключник напрямую — только если Key отдаёт CORS для вашего origin |
data-shell="off" | нет | не строить каркас (полоса + контейнер во всю высоту), оставить полосу просто первой в body |
data-log-endpoint | нет | URL, куда виджет шлёт свои клиентские логи (init_ok / init_fail) |
Если проект не должен падать без header.kobets.info — подключайте loader.js: он грузит
embed.js с первого адреса, а при недоступности — со второго. Код шапки при этом всё равно один,
просто раздаётся с двух хостов.
<script src="https://header.kobets.info/loader.js"
id="kobets-header-script"
defer
data-realm="ваш_реалм"
data-base-url="https://header.kobets.info"
data-base-url-fallback="https://второй-хост/header"></script>
В полосе — только имя пользователя, в правом углу (или «Войти», если сессии нет), рядом крестик «выйти». Всё остальное убрано с глаз и открывается окошком при наведении на имя (на тач-экранах — по тапу). Окошко не захлопывается сразу: после ухода курсора оно висит ещё 0,9 с, чтобы успеть дойти до крестика реалма:
| Где | Что | Действие |
|---|---|---|
| Полоса | имя авторизованного либо «Войти» | крестик — выйти |
| Окошко | часы — индикатор того, что шапка жива | замирают, если скрипт шапки повис |
| Окошко | реалм(ы): чип на каждый, имя — ссылка | крестик — выйти из реалма |
Названия и версии проекта в шапке нет: проект и так знает, как он называется, а место это занимало у всех. Ссылок в админку ключника и прочего «полезного одному человеку» — тоже нет.
Шапка задаёт каркас окна: полоса всегда сверху и во всю ширину браузера, а всё
содержимое страницы живёт в контейнере #kobets-page под ней. Контейнер занимает
всю оставшуюся высоту окна и скроллится сам — полоса при этом остаётся на месте,
ничего не перекрывает и padding-top не требует.
Виджет делает это сам при загрузке: переносит содержимое <body> в контейнер
и ставит на <html> класс kobets-shell. Отступы body
переезжают на контейнер, чтобы вёрстка не поехала.
Что учесть. Скролл теперь у контейнера, а не у окна: если ваш код слушает
window.onscroll или читает window.scrollY, переключите его на
document.getElementById('kobets-page'). Каркас можно отключить —
data-shell="off" у тега шапки (или shell: false в конфиге), тогда полоса
просто стоит первой в body, как раньше.
Цвет полоса берёт от окна браузера (системные Canvas /
CanvasText): в светлой теме она светлая с тёмным текстом, в тёмной — наоборот,
переключается сама вместе с браузером и ОС. Полупрозрачность оставлена, так что фон сервиса
сквозь неё просвечивает. Нужен свой цвет — задайте переменные на своей странице:
:root {
--kobets-header-bg: rgba(20, 30, 60, .35);
--kobets-header-fg: #eef;
}
При загрузке страницы шапка сама идёт за состоянием авторизации — хосту ничего вызывать не нужно. Пока ответа нет, блок пользователя пустой (чтобы не мигало «Войти»); есть права — сразу появляется имя; прав нет или ответа не дождались — появляется кнопка «Войти». Надписей «Не авторизован» и «Нет доступа» в шапке нет: пользователю нужно действие, а не диагноз.
Куда шапка идёт, по порядку:
| Источник | Когда |
|---|---|
состояние от хоста (__KOBETS_HEADER_AUTH__, SET_AUTH) | если хост его дал — оно главнее всего |
data-auth-url — эндпоинт хоста | если задан: свой origin, работает всегда |
| ключник напрямую | только с data-key-auth — и только там, где Key отдаёт CORS для вашего origin |
<script src="https://header.kobets.info/embed.js"
id="kobets-header-script" defer
data-realm="net"
data-auth-url="/api/auth/header-state"></script>
Эндпоинт по data-auth-url отдаёт тот же объект auth, что описан ниже
(как минимум status и name); запрос идёт с credentials: same-origin,
то есть с вашей сессионной cookie. Если он не ответил за 4 секунды — шапка показывает «Войти».
Если хост хочет управлять состоянием сам (или дополнить его), после загрузки виджета доступны три глобальные функции.
__KOBETS_HEADER_SET_AUTH__(auth)window.__KOBETS_HEADER_SET_AUTH__({
status: "allowed", // allowed | need_login | pending | revoked | invalid
name: "Иван Петров", // имя для показа; GUID в шапку не выводится
realm: "net", // либо realms: [...] — см. ниже
loginUrl: "https://key.kobets.info/auth/login?service_id=net&…",
logoutUrl: "/auth/logout"
});
Если сервису нужно сразу несколько реалмов — передавайте realms; каждый станет отдельным чипом.
Имя реалма — ссылка: адрес берётся из url самого реалма, затем из шаблона
realmUrl с {realm}, а если ничего не задано — из projectUrl
(см. SET_PROJECT) или текущего origin. Крестик «Выйти из реалма» появляется только там,
где хост дал адрес выхода (logoutUrl/logoutApi у реалма, шаблон
realmLogoutUrl, либо общий logoutUrl — если реалм единственный).
window.__KOBETS_HEADER_SET_AUTH__({
status: "allowed",
name: "Иван Петров",
realms: [
{ realm: "tracker", status: "allowed", url: "/tracker/", logoutUrl: "/auth/logout?realm=tracker" },
{ realm: "net", status: "allowed", url: "/net/", logoutUrl: "/auth/logout?realm=net" },
{ realm: "key", status: "pending" }
],
realmUrl: "/r/{realm}/", // общий шаблон ссылки, если у реалма нет своего url
logoutUrl: "/auth/logout"
});
__KOBETS_HEADER_SET_PROJECT__(data)Отдельного блока проекта в полосе нет, но данные шапке пригодятся: projectUrl —
куда ведёт имя реалма, если у реалма не задан свой url; название и версия попадают
в подсказку чипа при наведении.
window.__KOBETS_HEADER_SET_PROJECT__({
projectName: "GPS Track",
version: "0.1.261",
projectUrl: "https://gps.example.com" // ссылка ведёт сюда, не на header
});
__KOBETS_HEADER_ALIVE__()Часы в окошке — не украшение, а watchdog: тик перепланирует сам себя, и если код шапки повис или упал, время замирает. Паузу дольше 2,5 с шапка помечает жёлтым со знаком ⚠ (метка остаётся и после того, как зависание кончилось, — её видно, когда откроете окошко). То же самое программно, без наведения:
window.__KOBETS_HEADER_ALIVE__();
// { version: "…", running: true, ticks: 42, lastTickAt: …, sinceLastTickMs: 650, stalledMs: 0 }
https://header.kobets.info/embed.js. Обновление шапки
доезжает до всех проектов само (кэш — до часа).__KOBETS_HEADER_SET_PROJECT__, а не рисуйте свой блок сверху страницы.<body> и с defer. Иначе страница ждёт шапку.Подробные документы (контракт auth, отладка, деплой) — в репозитории kobets.info, каталог
header/docs/; точка входа — HEADER-INTEGRATION-GUIDE.md.