Banner 公告条

横贯页面顶部的一条公告。

import { Banner, Link } from '@hina-ui/react'

export default function Demo() {
  return (
    <Banner closable>
      Hina UI 1.2 已发布。
      <Link href="#" underline>
        查看更新说明
      </Link>
    </Banner>
  )
}
tsx

用法

import { Banner } from '@hina-ui/react'
ts

公告条贯穿页面整个宽度,通常放在页面最顶部,用于版本发布、停机维护、活动通知这类面向全站的信息。它是实底色块,没有圆角与边框。针对某次操作的消息使用 Alert,写在内容里的固定提示使用 Callout。需要随页面滚动固定在顶部时,加上 sticky top-0。

import { Banner } from '@hina-ui/react'

export default function Demo() {
  return <Banner>本站将于 3 月 1 日 02:00 至 04:00 停机维护。</Banner>
}
tsx

示例

色调

共六种色调,默认为 accent。图标随色调变化,icon 设为 false 时不显示图标。

import { Banner, Stack } from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack className="w-full">
      <Banner tone="neutral">本站已启用新的评论系统。</Banner>
      <Banner tone="accent">Hina UI 1.2 已发布。</Banner>
      <Banner tone="info">当前浏览的是历史版本的文档。</Banner>
      <Banner tone="success">你的邮箱已完成验证。</Banner>
      <Banner tone="warning">本站将于今晚 02:00 停机维护。</Banner>
      <Banner tone="danger">支付服务暂时不可用,我们正在处理。</Banner>
      <Banner tone="accent" icon={false}>
        Hina UI 1.2 已发布。
      </Banner>
    </Stack>
  )
}
tsx

自定义图标

icon 属性替换默认的图标。

import { Sparkles } from 'lucide-react'
import { Banner } from '@hina-ui/react'

export default function Demo() {
  return (
    <Banner icon={<Sparkles className="size-4 shrink-0" />}>
      周年活动进行中,全站图书限时八折。
    </Banner>
  )
}
tsx

操作

actions 属性位于正文之后,用于放置一个按钮。

import { Banner, Button } from '@hina-ui/react'

export default function Demo() {
  return (
    <Banner
      tone="warning"
      actions={
        <Button size="sm" tone="neutral">
          延长登录
        </Button>
      }
    >
      登录状态将在 5 分钟后过期。
    </Banner>
  )
}
tsx

可关闭

设置 closable 后末端显示关闭按钮,关闭时调用 onClose。open / onOpenChange 控制显示与隐藏,是否记住用户关闭过由应用自行保存。

'use client'

import { useState } from 'react'
import { Banner, Button, Stack } from '@hina-ui/react'

export default function Demo() {
  const [open, setOpen] = useState(true)

  return (
    <Stack className="min-h-24 w-full">
      <Banner open={open} onOpenChange={setOpen} tone="success" closable>
        你的邮箱已完成验证。
      </Banner>
      <Button
        variant="soft"
        tone="neutral"
        disabled={open}
        className="self-start"
        onClick={() => setOpen(true)}
      >
        再次显示
      </Button>
    </Stack>
  )
}
tsx

多条公告

items 传入多条公告,renderItem 属性决定每条的内容。多于一条时末端出现上一条、下一条按钮与计数,到末尾后回到开头,index / onIndexChange 绑定当前是第几条。每条可以带自己的 tone 与 icon,没有的沿用公告条的。切换时图标与正文作为一个整体按方向滑动,底色与字色平滑过渡。关闭按钮关闭的是整条公告栏。

'use client'

import { Sparkles } from 'lucide-react'
import { Banner, Link, type BannerNotice } from '@hina-ui/react'

const notices: (BannerNotice & { text: string; link?: string })[] = [
  { text: 'Hina UI 1.2 已发布。', link: '查看更新说明' },
  { text: '本站将于 3 月 1 日 02:00 至 04:00 停机维护。', tone: 'warning' },
  { text: '周年活动进行中,全站图书限时八折。', link: '了解详情', icon: Sparkles },
]

export default function Demo() {
  return (
    <Banner
      items={notices}
      closable
      renderItem={({ item }) => (
        <>
          {item.text}
          {item.link && (
            <Link href="#" underline>
              {item.link}
            </Link>
          )}
        </>
      )}
    />
  )
}
tsx

自动轮播

autoplay 传入毫秒数后按此间隔自动切到下一条。指针悬停、焦点在公告条内或页面不可见时暂停,离开后继续;用户在系统中选择了减少动态效果时不自动切换。

'use client'

import { Banner } from '@hina-ui/react'

const notices = [
  { text: '新增书评 86 条,活跃读者 1,204 人。' },
  { text: '本周最受欢迎的作品是《狼と香辛料》。' },
  { text: '书架支持按标签筛选了。' },
]

export default function Demo() {
  return <Banner items={notices} autoplay={4000} tone="info" renderItem={({ item }) => item.text} />
}
tsx

在 AppShell 里

AppShell 的 banner 属性位于最顶部,横贯侧栏与主区域。公告条关闭后,下方的侧栏与主区域一起上移补满。

首页

关闭公告条后,侧栏与主区域一起上移补满。

import {
  AppShell,
  Banner,
  Heading,
  Link,
  NavLink,
  Sidebar,
  SidebarTrigger,
  Text,
} from '@hina-ui/react'

export default function Demo() {
  return (
    <AppShell
      collapsible="hidden"
      className="border-line h-96 w-full rounded-lg border"
      banner={
        <Banner closable>
          Hina UI 1.2 已发布。
          <Link href="#" underline>
            查看更新说明
          </Link>
        </Banner>
      }
      sidebarContent={
        <Sidebar>
          <NavLink href="#" active label="首页">
            首页
          </NavLink>
          <NavLink href="#" label="我的书架">
            我的书架
          </NavLink>
        </Sidebar>
      }
      header={
        <>
          <SidebarTrigger />
          <Heading level={2} size="sm">
            首页
          </Heading>
        </>
      }
    >
      <Text size="sm" tone="muted" className="block p-6">
        关闭公告条后,侧栏与主区域一起上移补满。
      </Text>
    </AppShell>
  )
}
tsx

行为

  • 视口宽度达到 640 像素时正文相对整条居中;更窄时正文靠起始边、占满关闭按钮之外的整行,按普通段落换行。
  • 关闭时收合并淡出,下方内容平滑上移。
  • 首次渲染时不播放出现动画。
  • 多条公告之间切换时,图标与正文一起按方向滑动:下一条从末端进入,上一条从起端进入,从右到左的书写方向下镜像。旧内容滑出后新内容滑入,公告条高度不变。
  • 切到色调不同的一条时,底色与字色平滑过渡。

无障碍

  • 公告条不是实时区域,屏幕阅读器按文档顺序朗读它。
  • 图标只是装饰,对辅助技术隐藏。
  • 多条公告手动切换时,内容所在的区域是礼貌级实时区域,屏幕阅读器会朗读新内容;自动轮播时不朗读,避免反复打断。
  • 关闭按钮的名称来自语言包的 close 条目,上一条、下一条按钮的名称来自 banner.prev 与 banner.next。

API

Props

属性
类型
默认值
说明
tone
'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger'
'accent'
色调
icon
boolean
true
是否显示图标
closable
boolean
false
是否显示关闭按钮
open
boolean
true
是否显示,可受控
items
T[]
—
多条公告,由 renderItem 属性渲染;每条可带 tone 与 icon
index
number
0
当前公告的序号,可受控
autoplay
number
—
自动切换的间隔,毫秒
className
string
—
追加至公告条的类名

回调

回调
参数
说明
onOpenChange
open: boolean
显示状态变化
onIndexChange
index: number
当前公告变化
onClose
—
点击了关闭按钮

内容属性

属性
参数
说明
children
—
正文
renderItem
{ item: T, index: number }
多条公告时每一条的内容
icon
—
替换图标
actions
—
正文之后的操作区