通知栈

与 behaviors/notification 配套:工程级持久通知栈——进度通知、Promise confirm、多按钮、hover 暂停+倒计时进度、优先级置顶、已读未读、自定义图标/头像、详情链接、localStorage 持久化、多容器。与 toast(瞬时)/ alert(内嵌)正交。

语义
特性
丰富
0 条
<div class="toolbar" style="margin-bottom:10px">  <span class="toolbar-label">语义</span>  <button class="btn btn-sm" id="notif-info">info</button>  <button class="btn btn-sm btn-primary" id="notif-success">success</button>  <button class="btn btn-sm" id="notif-warn">warn</button>  <button class="btn btn-sm btn-danger" id="notif-error">error</button></div><div class="toolbar" style="margin-bottom:10px">  <span class="toolbar-label">特性</span>  <button class="btn btn-sm" id="notif-progress">进度通知</button>  <button class="btn btn-sm" id="notif-confirm">Promise 确认</button>  <button class="btn btn-sm" id="notif-multi">多按钮</button>  <button class="btn btn-sm" id="notif-countdown">倒计时(8s)</button>  <button class="btn btn-sm" id="notif-priority">高优先级</button></div><div class="toolbar" style="margin-bottom:10px">  <span class="toolbar-label">丰富</span>  <button class="btn btn-sm" id="notif-avatar">带头像</button>  <button class="btn btn-sm" id="notif-link">带链接</button>  <button class="btn btn-sm" id="notif-unread">未读标记</button>  <button class="btn btn-sm" id="notif-actions">actions 回调</button>  <button class="btn btn-sm" id="notif-update">动态更新</button></div><div class="toolbar">  <span class="toolbar-spacer"></span>  <span class="toolbar-label" id="notif-count">0 条</span>  <button class="btn btn-sm" id="notif-read">全部已读</button>  <button class="btn btn-sm" id="notif-clear">清空</button></div>

安装

bun add @icen.ai/ui

一行引入该组件(CSS 与 behavior 自动带上,无需关心内部 CSS 文件名):

import '@icen.ai/ui/kit/notification';

也可以用脚手架直接打印引入行:

bunx --bun @icen.ai/ui add notification

Astro 项目注意:kit 入口里的 CSS import 在页面 <script> 里会被 Astro 的 client bundle 摇掉——请改在布局 frontmatter 里引 CSS(import '@icen.ai/ui/components/notification.css';),JS 行为仍可走 kit。Vite SPA / webpack 项目无此问题。

用法

import { notify, createNotificationCenter } from '@icen.ai/ui/behaviors/notification'; // ── 便捷 API ──notify.success('已发布', { description: '5 分钟后全量生效' });notify.warn('配额将尽', { description: '已用 80%', duration: 8000 });  // 8s 自动关闭notify.error('发布失败', { description: '封面图尺寸不足' }); // ── 进度通知(返回 handle,可动态 setProgress)──const h = notify.progress('正在导出', { progressLabel: '准备中…' });let p = 0;const timer = setInterval(() => {  p += 0.08;  if (p >= 1) {    h.setProgress(1, '完成');    clearInterval(timer);    setTimeout(() => h.dismiss(), 1500);  } else {    h.setProgress(p, '导出中 ' + Math.round(p * 100) + '%');  }}, 300); // ── Promise confirm(阻塞式确认)──const ok = await notify.confirm('确认删除该作品?', {  description: '此操作不可撤销,相关数据将被清除。',  confirmLabel: '删除',  cancelLabel: '取消',});if (ok) { /* 执行删除 */ } // ── 多按钮 ──notify.info('评论了你的作品', {  description: '「很喜欢这段配乐」—— 沈墨',  avatar: 'https://example.com/u.jpg',  actions: [    { label: '回复', type: 'primary', onClick: () => openReply() },    { label: '忽略', onClick: () => {} },  ],  link: '/works/123',  linkLabel: '查看作品',}); // ── 高优先级置顶 + 未读 ──notify.error('服务中断', {  description: 'gateway-001 不可达,已自动切换备用节点',  priority: 'high',  unread: true,}); // ── Handle 方法 ──h.update({ title: '新标题', description: '更新后' });h.markRead();h.pause(); h.resume();h.dismiss();notify.markRead();        // 全部已读notify.clear();           // 全清notify.get(id);           // 读取notify.getAll();          // 全部 // ── 多容器(独立位置与配置)──const center = createNotificationCenter(document.body, {  position: 'bottom-right',  maxStack: 3,  persist: 'app:messages',});center.push({ title: '新消息', kind: 'info', options: { description: '…' } });center.markAllRead();center.clear(); // ── 全局配置 ──notify.config({ position: 'top-right', maxStack: 5, pauseOnHover: true });