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)在 <body> 上加 class="ns-kit" 即可获得基础排版、背景和滚动条,然后使用这些类:
<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(两端对齐)、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() 会把应用的实时主题以 --ns-<token> 变量的形式写到 <html> 上——--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,再把图片转成blob:URL。 - 内联样式没问题(
style="…"和<style>)。 - 使用相对 URL。 页面从
nscard://<id>/<path>提供;构建时请使用相对资源路径(Vite:base: './',React 模板已配置)。 - 没有
localStorage、Cookie、alert、弹窗、下载、全屏、摄像头或麦克风。 请使用card.storage、card.ui.confirm、card.openLink。 - 页面不能写入剪贴板。
copy/cut处理函数和document.execCommand('copy')不起作用(否则任何卡片都能在一次点击时替换剪贴板)。 请使用card.copyText;用户自己复制选中文本仍然可以。 - 不能嵌套框架。
iframe、frame、object和embed元素会被移除。 - 只能用 blob Worker。
new Worker('worker.js')在卡片的源中会失败;请先获取脚本,把它包装成Blob, 再用new Worker(URL.createObjectURL(blob))启动。 - 永远不要信任
message事件。 其他卡片可以对你的框架调用postMessage。
npx @neurosquad/card-sdk validate 会对入口页面中的内联脚本、内联事件处理器和外部文件发出警告。
表单永远不会跳转。 <form> 的 submit 事件会触发,你的处理函数也会运行,但应用会取消提交本身,
form.submit() 也什么都不做——卡片页面无法向任何地方提交,也无法重新加载。无论如何,请在处理函数中调用
event.preventDefault(),并用 JavaScript 完成工作。
为画布而设计
- 大小皆宜。 卡片通常是 400×300,有时会展开铺满屏幕。两种状态都要做得完整:用
card.lifecycle.onExpanded或useExpanded()切换布局。 - 空状态、加载中、出错。 数据到达之前、没有数据时、调用失败时,都要显示合理的内容。
- 概览图块就是缩小后的你的卡片。 用
setOverview持续展示最重要的那一条信息。 - 没人看时保持安静。
usePaused()为 true 时停止动画——一块画布上可能有五十张卡片。 - 标题栏属于应用。 不要在正文里重复卡片名称或关闭按钮;标题栏已经有了。
卡片正文里的一切都属于卡片自己,用户也被如此告知。不要模仿 NeuroSquad 的对话框,也不要在卡片里索要密码和密钥——
请使用 secret 设置,由应用在它自己的表单中询问。