通知栈
与 behaviors/notification 配套:工程级持久通知栈——进度通知、Promise confirm、多按钮、hover 暂停+倒计时进度、优先级置顶、已读未读、自定义图标/头像、详情链接、localStorage 持久化、多容器。与 toast(瞬时)/ alert(内嵌)正交。
<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 pnpm add @icen.ai/ui npm install @icen.ai/ui yarn 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 });