组件库

这个站的所有组件都用方言写在 site/app/ui/, 样式是 Tailwind class。它们是共享组件: 同一份源码, 服务端编成 Go, 客户端编成 DOM 指令, 所以既能出现在页面里, 也能出现在岛里。API 刻意长得像 MUI / shadcn, 实现完全是自己的。

为什么不用 MUI
MUI 是跑在 React 运行时上的动态 JS(forwardRef、Emotion、{...props} 铺属性), 不可能通过子集检查, 也不可能编译成 Go。方言的库必须用方言写——就像 AssemblyScript 不能直接用 npm 包。

Button

ui/Button.tsx · variant / size / href / disabled / onClick

链接形态
用法
<Button>Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button size="sm">Small</Button>
<Button size="lg" href="/docs">As a link</Button>
ui/Button.tsx(节选): 解构默认值 + 三元选择元素类型
import type { Node } from "gotsx";

export default function Button({ variant = "primary", size = "md", href = "", onClick, children }: ButtonProps) {
  const cls = `inline-flex items-center rounded-lg font-medium ${sizeCls(size)} ${variantCls(variant)}`;
  return href !== ""
    ? <a href={href} class={cls}>{children}</a>
    : <button class={cls} onClick={onClick}>{children}</button>;
}

在岛里用同一个 Button——它的 children 是响应式文本, 服务端预渲染, 浏览器接管:

Badge

ui/Badge.tsx · color

默认brandgreenamberred
用法
<Badge>Default</Badge>
<Badge color="brand">brand</Badge>
<Badge color="green">green</Badge>
<Badge color="amber">amber</Badge>
<Badge color="red">red</Badge>

Card / Stat / Callout

服务端布局用的三个容器

Card

带 icon 和 title 的容器, children 是任意节点。
30 µs
Stat: 数字 + 说明

嵌套

组件可以任意嵌套
Callout
kind = info | tip | warn。你正在看的就是一个。

CodeBlock / CodeTabs

高亮由 Go 写的 tokenizer(host:hl)完成, 方言只渲染 span

服务端组件 CodeBlock 直接调宿主; 岛 CodeTabs 拿的是页面在服务端切好的 token 数组(props), 两端都只负责渲染——客户端代码永远碰不到 Go。

<Button>Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button size="sm">Small</Button>
<Button size="lg" href="/docs">As a link</Button>

Accordion

islands/Accordion.client.tsx · items: { q, a }[]