列表

列表是由若干行组成的带边框区域。每一行有标题、可选的描述,以及行首和行尾两个位置,用来放头像、图标或控件。

基础列表

  • 路由
    src/about.ht.js 变成 /about
  • 数据加载
    data() 只在构建时跑一次
  • 资源
    只有 HTML 引用到的东西才会被打包
list(
  listItem({ title: '路由', description: 'src/about.ht.js 变成 /about' }),
  listItem({ title: '数据加载', description: 'data() 只在构建时跑一次' }),
  listItem({ title: '资源', description: '只有 HTML 引用到的东西才会被打包' }),
)

行首与行尾

  • AL
    Ada Lovelace
    向 main 推送了 3 个提交
    2 小时前
  • GH
    Grace Hopper
    发起了一个 pull request
    开放中
list(
  listItem({
    start: avatar({ name: 'Ada Lovelace', size: 'sm' }),
    title: 'Ada Lovelace',
    description: '向 main 推送了 3 个提交',
    end: chip({ size: 'sm', color: 'neutral' }, '2 小时前'),
  }),
  listItem({
    start: avatar({ name: 'Grace Hopper', size: 'sm', color: 'success' }),
    title: 'Grace Hopper',
    description: '发起了一个 pull request',
    end: chip({ size: 'sm', color: 'success', dot: true }, '开放中'),
  }),
)

可点击跳转的行

带 href 的行会把锚点放进 <li> 里面,而不是套在外面,这样列表仍然是合法的列表。别再往这种行里塞按钮——可交互内容不能嵌在链接里。

list(
  listItem({ title: '快速开始', description: '安装并写出第一个页面', href: '/zh/docs' }),
  listItem({ title: '路由', description: '基于文件,支持动态片段', href: '/zh/docs/routing' }),
  listItem({ title: '部署', description: 'Netlify、Vercel、Pages、Amplify', href: '/zh/docs/deployment' }),
)

带控件的行

当一行里放着开关或按钮时,就别再给整行加链接,让控件成为那个可交互的部分。

  • Pagefind 搜索
    构建结束时索引每一个页面
  • 图片优化
    缩放并转换图片格式。需要 sharp。
  • 服务端区块
    在请求时渲染被标记的区域
list(
  listItem({
    title: 'Pagefind 搜索',
    description: '构建结束时索引每一个页面',
    end: toggle({ 'aria-label': 'Pagefind 搜索', checked: true }),
  }),
  listItem({
    title: '图片优化',
    description: '缩放并转换图片格式。需要 sharp。',
    end: toggle({ 'aria-label': '图片优化', checked: true }),
  }),
  listItem({
    title: '服务端区块',
    description: '在请求时渲染被标记的区域',
    end: toggle({ 'aria-label': '服务端区块' }),
  }),
)

无外框

plain 会去掉边框和底色,适合放进本身已经有一层面的卡片或侧栏里的列表。

最近的构建

  • 94a837a
    main · 4 分钟前
    通过
  • dcfaaae
    main · 2 小时前
    通过
  • a46a461
    main · 昨天
    失败
card(
  cardHeader({ title: '最近的构建' }),
  cardBody(
    list({ plain: true },
      listItem({ title: '94a837a', description: 'main · 4 分钟前', end: chip({ size: 'sm', color: 'success', dot: true }, '通过') }),
      listItem({ title: 'dcfaaae', description: 'main · 2 小时前', end: chip({ size: 'sm', color: 'success', dot: true }, '通过') }),
      listItem({ title: 'a46a461', description: 'main · 昨天', end: chip({ size: 'sm', color: 'danger', dot: true }, '失败') }),
    ),
  ),
)

自由排布的行

不给 title 和 description 时,一行会原样渲染你给它的子元素——用于两行式结构覆盖不了的排版。

  • 自定义行

    里面爱放什么放什么
list(
  listItem(
    stack({ direction: 'row', gap: 'md', align: 'center', justify: 'space-between', style: 'width: 100%' },
      stack({ gap: 'none' },
        text({ variant: 'small' }, '自定义行'),
        text({ variant: 'caption', tone: 'muted' }, '里面爱放什么放什么'),
      ),
      button({ size: 'sm', variant: 'soft' }, '操作'),
    ),
  ),
)

由数据生成

  • E
    English
    24 个页面
    en
  • E
    Español
    24 个页面
    es
  • Z
    简体中文
    24 个页面
    zh
return (() => {
  const locales = [
    { code: 'en', name: 'English', pages: 24 },
    { code: 'es', name: 'Español', pages: 24 },
    { code: 'zh', name: '简体中文', pages: 24 },
  ]

  return list(
    locales.map((locale) =>
      listItem({
        start: avatar({ name: locale.code, size: 'sm', color: 'neutral', square: true }),
        title: locale.name,
        description: locale.pages + ' 个页面',
        end: chip({ size: 'sm', color: 'neutral' }, locale.code),
      }),
    ),
  )
})()

属性

list():

属性类型默认值说明
plainbooleanfalse去掉边框和底色。
asstring'ul'渲染成哪个元素,比如 ol。

listItem():

属性类型默认值说明
titleChild—这一行的主文字。
descriptionChild—弱化的第二行。
startChild—行首位置——头像或图标。
endChild—行尾位置——标签片、控件或时间戳。
hrefstring—把这行变成链接,锚点放在 li 里面。
interactivebooleanfalse有悬停高亮,但不变成链接。