UI-кит и оформление
Внутри своей коробки карточка — обычная веб-страница: любой фреймворк, любой CSS, canvas, WebGL, WebAssembly. Оформить её можно двумя путями:
- Как родная — необязательный кит
ui.css: небольшой тёмный набор кнопок, полей, списков и бейджей на живой теме приложения. Карточки на нём выглядят частью NeuroSquad и следуют его теме. - Свой дизайн — просто не подключайте кит. Переменные темы всё равно под рукой, если захочется позаимствовать цвет.
UI-кит
<link rel="stylesheet" href="vendor/ui.css" /> <!-- plain template -->import '@neurosquad/card-sdk/ui.css' // with a bundler (React template)Поставьте class="ns-kit" на <body> — это даст базовую типографику, фон и полосы прокрутки, — и
пользуйтесь классами:
<body class="ns-kit">
<header class="ns-spread">
<h1 class="ns-title ns-truncate">Test radar</h1>
<span class="ns-badge ns-badge--danger">3 failed</span>
</header>
<ul class="ns-list ns-scroll">
<li class="ns-list-item"><span class="ns-dot ns-dot--danger"></span> checkout › pays</li>
<li class="ns-list-item"><span class="ns-dot ns-dot--success"></span> auth › logs in</li>
</ul>
<label class="ns-field">
<span class="ns-label">Filter</span>
<input class="ns-input" placeholder="checkout" />
</label>
<div class="ns-row">
<button class="ns-btn ns-btn--primary">Run</button>
<button class="ns-btn ns-btn--ghost ns-btn--sm">Clear</button>
</div>
</body>| Группа | Классы |
|---|---|
| Раскладка | ns-kit, ns-stack (вертикально), ns-row (горизонтально), ns-spread (space-between), ns-grow, ns-scroll, ns-pad, ns-divider |
| Поверхности | ns-surface, ns-surface--inset, ns-callout, ns-callout--success, ns-callout--danger, ns-empty |
| Текст | ns-title, ns-subtitle, ns-muted, ns-small, ns-mono, ns-truncate, ns-kbd, ns-help, ns-error |
| Кнопки | ns-btn + --primary, --secondary, --outline, --ghost, --danger, --sm, --lg, --icon |
| Поля | ns-field, ns-label, ns-input, ns-textarea, ns-select, ns-switch |
| Списки | ns-list, ns-list-item |
| Статус | ns-badge + --accent, --success, --warning, --danger; ns-dot + те же; ns-spinner, ns-progress |
Вне приложения (в превью в браузере) кит откатывается к тёмной теме приложения, так что и превью выглядит правильно.
Переменные темы
connect() кладёт живую тему приложения на <html> в виде переменных --ns-<token> —
--ns-background, --ns-surface, --ns-foreground, --ns-muted, --ns-accent, --ns-success,
--ns-warning, --ns-danger, их варианты -foreground и -soft, --ns-border, --ns-focus,
--ns-field-*, --ns-radius, --ns-font-sans, --ns-font-mono и другие (полный список — в разделе
Тема). Пользуйтесь ими в своём CSS, и карточка будет следовать за
приложением:
:root { color-scheme: dark; }
body {
margin: 0;
background: var(--ns-background, #0b0b0f);
color: var(--ns-foreground, #fafafa);
font: 13px/1.45 var(--ns-font-sans, system-ui, sans-serif);
}
.chip {
border-radius: calc(var(--ns-radius, 0.5rem) * 2);
background: var(--ns-accent-soft);
color: var(--ns-accent-soft-foreground);
}Давайте переменным запасные значения (как выше), если страница должна отображаться и вне
приложения. Чтобы ваши цвета никто не трогал, подключайтесь через connect({ theme: false }).
Правила песочницы для страниц
Ваша страница отдаётся из собственного пакета со строгой политикой безопасности контента (CSP). На практике:
- Никаких встроенных скриптов и атрибутов
onclick="…"— код кладите в файлы.js.evalиnew Functionтоже заблокированы (WebAssembly разрешён). - Никаких внешних файлов. Скрипты, стили, шрифты и картинки должны лежать в пакете;
<link href="https://fonts…">или<img src="https://…">заблокируются. Картинкиdata:иblob:работают. За удалёнными данными ходите черезcard.net.fetch, а картинки превращайте в URLblob:. - Встроенные стили можно (
style="…"и<style>). - Относительные URL. Страница отдаётся с
nscard://<id>/<path>; собирайте с относительными путями к ресурсам (в Vite —base: './', как в шаблоне React). - Никаких
localStorage, cookies,alert, всплывающих окон, загрузок, полноэкранного режима, камеры и микрофона. Используйтеcard.storage,card.ui.confirm,card.openLink. - Никакой записи в буфер обмена со страницы. Обработчики
copy/cutиdocument.execCommand('copy')ничего не делают (иначе любая карточка могла бы подменить буфер обмена по клику). Используйтеcard.copyText; обычное копирование выделенного текста пользователем по-прежнему работает. - Никаких вложенных фреймов. Элементы
iframe,frame,objectиembedудаляются. - Только blob-воркеры.
new Worker('worker.js')в источнике карточки не работает; скачайте скрипт, заверните его вBlobи запуститеnew Worker(URL.createObjectURL(blob)). - Никогда не доверяйте событиям
message. Другие карточки могут делатьpostMessageв ваш фрейм.
npx @neurosquad/card-sdk validate предупреждает о встроенных скриптах, встроенных обработчиках и
внешних файлах во входной странице.
Формы никуда не уводят. Событие submit у <form> срабатывает, и ваш обработчик выполняется,
но саму отправку приложение отменяет, а form.submit() ничего не делает — страница карточки не
может ничего никуда отправить или перезагрузиться. Всё равно вызывайте в обработчике
event.preventDefault() и делайте работу в JavaScript.
Дизайн для холста
- Маленькая и большая. Карточка часто размером 400×300, а иногда развёрнута на весь экран.
Пусть оба вида выглядят законченными: переключайте раскладку через
card.lifecycle.onExpandedилиuseExpanded(). - Пусто, загрузка, ошибка. Показывайте что-то осмысленное, пока данные не пришли, когда их нет и когда вызов упал.
- Плитка обзора — это ваша карточка издалека. Держите
setOverviewактуальным, с одним главным фактом. - Тихо, когда не видно. Останавливайте анимации, когда
usePaused()возвращает true, — на холсте бывает пятьдесят карточек. - Шапка — забота приложения. Не повторяйте в теле имя карточки или кнопку закрытия: в шапке они уже есть.
Всё, что внутри тела карточки, принадлежит самой карточке, и пользователям об этом сказано. Не
подражайте диалогам NeuroSquad и не спрашивайте пароли и ключи внутри карточки — используйте
настройки secret, которые приложение запрашивает в своей собственной форме.