Skip to Content
Card SDKUI-кит и оформление

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, а картинки превращайте в URL blob:.
  • Встроенные стили можно (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, которые приложение запрашивает в своей собственной форме.