docs: 重写 README 与 site 站点 — 精美酷炫全新视觉
- README 全面更新:对齐 v0.5.0(钩子系统完整表、React 适配器、dragThreshold、工程质量章节) - site 三页全新设计:深色渐变 + 玻璃拟态 + 光球漂浮 + 网格背景 + 终端风格代码块 + 滚动淡入 - index.html:Hero 自动演示、数据统计条、12 特性卡、环境支持、CTA - docs.html:28 项 API 导航、滚动高亮、补全钩子系统/React/配置项/动画/主题章节 - demo.html:18 交互卡片、新增钩子拦截/dedupe 去重/自定义动画/拖拽阈值演示、107 图标网格 - jsdom 冒烟验证:三页 MeToast 全局注册、toast 渲染、图标网格/卡片/代码块完整
This commit is contained in:
+215
-114
@@ -7,51 +7,78 @@
|
||||
<title>在线演示 — MetonaToast</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0b1121; --surface: #151d33; --border: #1e2d4d;
|
||||
--text: #e2e8f0; --muted: #64748b; --accent: #6366f1; --accent2: #818cf8;
|
||||
--bg: #070b14; --surface: rgba(255,255,255,0.03); --surface2: rgba(255,255,255,0.05);
|
||||
--border: rgba(255,255,255,0.08); --text: #e8ecf4; --muted: #8b94a7;
|
||||
--accent: #a5b4fc; --grad: linear-gradient(135deg, #818cf8, #c084fc, #f472b6);
|
||||
--radius: 14px;
|
||||
}
|
||||
* { margin:0; padding:0; box-sizing:border-box; }
|
||||
body { font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif; background:var(--bg); color:var(--text); line-height:1.6; min-height:100vh; }
|
||||
a { color:var(--accent2); text-decoration:none; }
|
||||
code { background:rgba(99,102,241,0.12); color:#a5b4fc; padding:1px 6px; border-radius:4px; font-size:0.85em; }
|
||||
.nav { position:sticky; top:0; z-index:100; background:rgba(11,17,33,0.88); backdrop-filter:blur(14px); border-bottom:1px solid var(--border); }
|
||||
.nav-inner { max-width:1300px; margin:0 auto; display:flex; align-items:center; justify-content:space-between; padding:0 20px; height:56px; }
|
||||
.nav-logo { font-size:18px; font-weight:700; background:linear-gradient(135deg,#818cf8,#c084fc,#f472b6); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
|
||||
.nav-links { display:flex; gap:20px; }
|
||||
.nav-links a { color:var(--muted); font-size:13px; font-weight:500; transition:.2s; }
|
||||
.nav-links a:hover { color:var(--accent2); }
|
||||
.hero { text-align:center; padding:40px 20px 30px; border-bottom:1px solid var(--border); background:radial-gradient(ellipse at 50% 0%,rgba(99,102,241,0.12) 0%,transparent 50%); }
|
||||
.hero h1 { font-size:36px; font-weight:800; }
|
||||
.hero h1 span { background:linear-gradient(135deg,#818cf8,#c084fc,#f472b6); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
|
||||
body {
|
||||
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;
|
||||
background:var(--bg); color:var(--text); line-height:1.65; min-height:100vh;
|
||||
background-image:
|
||||
radial-gradient(ellipse 70% 45% at 50% -10%, rgba(99,102,241,0.12), transparent),
|
||||
radial-gradient(ellipse 50% 40% at 90% 20%, rgba(168,85,247,0.07), transparent);
|
||||
}
|
||||
a { color:var(--accent); text-decoration:none; }
|
||||
code { background:rgba(99,102,241,0.15); color:#a5b4fc; padding:1px 6px; border-radius:5px; font-size:.85em; }
|
||||
.grad-text { background:var(--grad); -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; color:transparent; }
|
||||
|
||||
.nav { position:sticky; top:0; z-index:100; background:rgba(7,11,20,0.72); backdrop-filter:blur(16px); border-bottom:1px solid var(--border); }
|
||||
.nav-inner { max-width:1320px; margin:0 auto; display:flex; align-items:center; justify-content:space-between; padding:0 22px; height:58px; }
|
||||
.nav-logo { font-size:18px; font-weight:800; }
|
||||
.nav-links { display:flex; gap:22px; }
|
||||
.nav-links a { color:var(--muted); font-size:13.5px; font-weight:500; transition:.2s; }
|
||||
.nav-links a:hover { color:var(--accent); }
|
||||
|
||||
.hero { text-align:center; padding:38px 20px 28px; }
|
||||
.hero h1 { font-size:34px; font-weight:800; }
|
||||
.hero p { color:var(--muted); font-size:14px; margin-top:6px; }
|
||||
|
||||
.container { max-width:1300px; margin:0 auto; padding:24px 20px; display:grid; grid-template-columns:repeat(auto-fill,minmax(400px,1fr)); gap:18px; }
|
||||
.card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); padding:20px; }
|
||||
.card h2 { font-size:15px; margin-bottom:2px; }
|
||||
.card > p { color:var(--muted); font-size:11px; margin-bottom:12px; }
|
||||
.container { max-width:1320px; margin:0 auto; padding:20px; display:grid; grid-template-columns:repeat(auto-fill,minmax(400px,1fr)); gap:16px; }
|
||||
.card {
|
||||
background:var(--surface); border:1px solid var(--border); border-radius:var(--radius);
|
||||
padding:20px; transition:border-color .2s, transform .2s; position:relative; overflow:hidden;
|
||||
}
|
||||
.card:hover { border-color:rgba(129,140,248,.35); }
|
||||
.card::before {
|
||||
content:''; position:absolute; top:0; left:0; right:0; height:2px;
|
||||
background:var(--grad); opacity:0; transition:opacity .25s;
|
||||
}
|
||||
.card:hover::before { opacity:.8; }
|
||||
.card h2 { font-size:14.5px; margin-bottom:2px; font-weight:700; }
|
||||
.card > p { color:var(--muted); font-size:11.5px; margin-bottom:12px; }
|
||||
.btn-row { display:flex; flex-wrap:wrap; gap:6px; }
|
||||
.btn { padding:8px 14px; border:none; border-radius:7px; font-size:12px; font-weight:500; cursor:pointer; transition:.15s; color:#fff; }
|
||||
.btn:hover { transform:translateY(-1px); filter:brightness(1.15); }
|
||||
.btn-sm { padding:5px 10px; font-size:11px; border-radius:5px; }
|
||||
.btn {
|
||||
padding:8px 14px; border:none; border-radius:8px; font-size:12px; font-weight:600;
|
||||
cursor:pointer; transition:transform .15s, filter .15s, box-shadow .15s; color:#fff;
|
||||
}
|
||||
.btn:hover { transform:translateY(-1.5px); filter:brightness(1.15); box-shadow:0 6px 18px -6px rgba(0,0,0,.5); }
|
||||
.btn-sm { padding:5.5px 11px; font-size:11px; border-radius:6px; }
|
||||
.btn-tiny { padding:4px 9px; font-size:10px; border-radius:5px; }
|
||||
.btn-outline { background:transparent; border:1px solid var(--border); color:var(--text); }
|
||||
.btn-outline:hover { border-color:var(--accent); background:rgba(99,102,241,0.06); }
|
||||
.btn-tiny { padding:4px 9px; font-size:10px; border-radius:4px; }
|
||||
.btn-outline:hover { border-color:rgba(129,140,248,.5); background:rgba(129,140,248,.08); }
|
||||
.c-s { background:#10b981; } .c-e { background:#ef4444; } .c-w { background:#f59e0b; color:#1e293b; }
|
||||
.c-i { background:#3b82f6; } .c-p { background:#6366f1; } .c-pp { background:#8b5cf6; }
|
||||
.c-pk { background:#ec4899; } .c-t { background:#14b8a6; } .c-o { background:#f97316; }
|
||||
.c-sl { background:#475569; } .c-r { background:#f43f5e; } .c-g { background:#22c55e; }
|
||||
.label { font-size:10px; text-transform:uppercase; letter-spacing:0.8px; color:var(--muted); margin-bottom:10px; font-weight:600; }
|
||||
.demo-section { border-top:1px solid var(--border); padding-top:8px; margin-top:8px; }
|
||||
.c-grad { background:var(--grad); }
|
||||
.label {
|
||||
font-size:10px; text-transform:uppercase; letter-spacing:1px; color:var(--muted);
|
||||
margin-bottom:10px; font-weight:700;
|
||||
}
|
||||
.demo-section { border-top:1px solid var(--border); padding-top:10px; margin-top:10px; }
|
||||
.status-line { font-size:11.5px; color:#34d399; margin-top:10px; font-family:monospace; min-height:18px; }
|
||||
footer { text-align:center; padding:30px 20px; color:var(--muted); font-size:12px; border-top:1px solid var(--border); }
|
||||
@media (max-width:768px) { .container { grid-template-columns:1fr; } }
|
||||
|
||||
@media (max-width:820px) { .container { grid-template-columns:1fr; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="nav">
|
||||
<div class="nav-inner">
|
||||
<div class="nav-logo">MetonaToast</div>
|
||||
<div class="nav-logo"><span class="grad-text">MetonaToast</span></div>
|
||||
<div class="nav-links">
|
||||
<a href="index.html">首页</a>
|
||||
<a href="docs.html">文档</a>
|
||||
@@ -62,7 +89,7 @@
|
||||
</nav>
|
||||
|
||||
<header class="hero">
|
||||
<h1><span>在线演示</span></h1>
|
||||
<h1><span class="grad-text">在线演示</span></h1>
|
||||
<p>覆盖项目全部功能的交互演示 — 点击即可体验</p>
|
||||
</header>
|
||||
|
||||
@@ -81,10 +108,10 @@
|
||||
<div class="demo-section">
|
||||
<div class="btn-row">
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.success({title:'保存成功',message:'文件已同步到云端'})">带标题</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.info('持续10秒',{duration:10000})">长时10s</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.info('持续 10 秒',{duration:10000})">长时 10s</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.warning('手动关闭',{duration:0,closeButton:true})">手动关闭</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.info('',{icon:false})">无图标</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.info('无按钮',{closeButton:false})">无关闭按钮</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.info('无关闭按钮',{closeButton:false})">无按钮</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="demoCustomIcon()">自定义图标</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -92,16 +119,17 @@
|
||||
|
||||
<!-- 2. Loading 链式 -->
|
||||
<div class="card">
|
||||
<div class="label">🔄 Loading 链式转换</div>
|
||||
<div class="label">🔄 Loading 链式转换 <span style="color:#34d399">id 稳定</span></div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-s" onclick="demoLoading()">提交成功</button>
|
||||
<button class="btn c-e" onclick="demoLoadingFail()">提交失败</button>
|
||||
<button class="btn c-w" onclick="demoLoadingWarn()">转为警告</button>
|
||||
<button class="btn c-i" onclick="demoLoadingUpdate()">原地更新</button>
|
||||
<button class="btn c-s" onclick="demoLoading('success')">提交成功</button>
|
||||
<button class="btn c-e" onclick="demoLoading('error')">提交失败</button>
|
||||
<button class="btn c-w" onclick="demoLoading('warning')">转为警告</button>
|
||||
<button class="btn c-i" onclick="demoLoading('update')">原地更新</button>
|
||||
</div>
|
||||
<p class="status-line" id="loading-status">转换后返回的 toast 与 loading 是同一个实例(id 不变)</p>
|
||||
</div>
|
||||
|
||||
<!-- 3. Promise + confirm + prompt -->
|
||||
<!-- 3. 对话框 -->
|
||||
<div class="card">
|
||||
<div class="label">💬 对话框</div>
|
||||
<div class="btn-row">
|
||||
@@ -116,8 +144,8 @@
|
||||
<div class="card">
|
||||
<div class="label">📊 进度 & 倒计时</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-o" onclick="demoProgress()">进度条(水平)</button>
|
||||
<button class="btn c-g" onclick="demoProgressV()">进度条(垂直)</button>
|
||||
<button class="btn c-o" onclick="demoProgress('horizontal')">进度条(水平)</button>
|
||||
<button class="btn c-g" onclick="demoProgress('vertical')">进度条(垂直)</button>
|
||||
<button class="btn c-pk" onclick="demoCountdown()">倒计时 5s</button>
|
||||
<button class="btn c-r" onclick="demoCountdownPause()">倒计时(可暂停)</button>
|
||||
</div>
|
||||
@@ -136,7 +164,7 @@
|
||||
|
||||
<!-- 6. Action Toast -->
|
||||
<div class="card">
|
||||
<div class="label">⚡ Action Toast</div>
|
||||
<div class="label">⚡ Action Toast <span style="color:#34d399">close:false 不关闭</span></div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-e" onclick="demoActionDelete()">删除+撤销</button>
|
||||
<button class="btn c-i" onclick="demoActionMulti()">多按钮</button>
|
||||
@@ -146,7 +174,7 @@
|
||||
|
||||
<!-- 7. 分组管理 -->
|
||||
<div class="card">
|
||||
<div class="label">📁 分组管理</div>
|
||||
<div class="label">📁 分组管理</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-p" onclick="demoGroup()">创建分组消息</button>
|
||||
<button class="btn c-e" onclick="dismissGroup()">关闭分组</button>
|
||||
@@ -157,7 +185,7 @@
|
||||
|
||||
<!-- 8. 动画效果 -->
|
||||
<div class="card">
|
||||
<div class="label">🎭 11种动画效果</div>
|
||||
<div class="label">🎭 11 种动画效果</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn btn-outline btn-tiny" onclick="anim('slide')">slide</button>
|
||||
<button class="btn btn-outline btn-tiny" onclick="anim('fade')">fade</button>
|
||||
@@ -171,9 +199,14 @@
|
||||
<button class="btn btn-outline btn-tiny" onclick="anim('slideLeft')">slideLeft</button>
|
||||
<button class="btn btn-outline btn-tiny" onclick="anim('slideRight')">slideRight</button>
|
||||
</div>
|
||||
<div class="demo-section">
|
||||
<div class="btn-row">
|
||||
<button class="btn c-grad" onclick="demoCustomAnim()">✨ 注册自定义动画</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 9. 6种位置 -->
|
||||
<!-- 9. 位置 -->
|
||||
<div class="card">
|
||||
<div class="label">📍 全部位置</div>
|
||||
<div class="btn-row">
|
||||
@@ -186,7 +219,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 10. 主题切换 + 自定义 -->
|
||||
<!-- 10. 主题 -->
|
||||
<div class="card">
|
||||
<div class="label">🎨 主题切换 & 自定义</div>
|
||||
<div class="btn-row">
|
||||
@@ -194,24 +227,43 @@
|
||||
<button class="btn btn-outline btn-sm" onclick="switchTheme('dark')">🌙 Dark</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="switchTheme('auto')">🔄 Auto</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="switchTheme('warm')">🔥 Warm</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="demoRegisterTheme()">注册自定义主题</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="demoRegisterTheme()">注册自定义</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 11. 插件系统 -->
|
||||
<!-- 11. 插件 -->
|
||||
<div class="card">
|
||||
<div class="label">🔌 插件系统</div>
|
||||
<div class="label">🔌 插件系统 <span style="color:#34d399">4 款预设</span></div>
|
||||
<div class="btn-row">
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.use('keyboard');MeToast.info('已安装 — 按 ESC 关闭所有 Toast')">keyboard ESC关闭</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.use('persistence');MeToast.info('已安装 — 配置将持久化到 localStorage')">persistence 持久化</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.use('accessibility');MeToast.info('已安装 — 屏幕阅读器可用')">accessibility 无障碍</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.use('keyboard');MeToast.info('已安装 — 按 ESC 关闭所有 Toast')">keyboard</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.use('persistence');MeToast.info('已安装 — 配置持久化')">persistence</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.use('accessibility');MeToast.info('已安装 — 屏幕阅读器')">accessibility</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="MeToast.use('dedupe');MeToast.info('已安装 — 同消息去重')">dedupe</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="demoCustomPlugin()">自定义插件</button>
|
||||
</div>
|
||||
<div class="demo-section">
|
||||
<div class="btn-row">
|
||||
<button class="btn c-t btn-sm" onclick="demoDedupe()">去重演示</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 12. 高级特性 -->
|
||||
<!-- 12. 钩子系统 -->
|
||||
<div class="card">
|
||||
<div class="label">🔥 高级特性 <span style="color:#34d399;font-size:10px;">resetTimer · onUpdate · render · notify</span></div>
|
||||
<div class="label">🔗 钩子系统 <span style="color:#34d399">beforeShow 拦截演示</span></div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-p" onclick="demoHookBlock()">开启拦截 error</button>
|
||||
<button class="btn c-e" onclick="MeToast.error('这条会被拦截')">触发被拦 error</button>
|
||||
<button class="btn c-s" onclick="MeToast.success('这条不受影响')">正常 success</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="demoHookUnblock()">关闭拦截</button>
|
||||
<button class="btn btn-outline btn-sm" onclick="demoHookCount()">钩子统计</button>
|
||||
</div>
|
||||
<p class="status-line" id="hook-status">钩子:未注册</p>
|
||||
</div>
|
||||
|
||||
<!-- 13. 高级特性 -->
|
||||
<div class="card">
|
||||
<div class="label">🔥 高级特性</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-i" onclick="demoResetTimer()">resetTimerOnUpdate</button>
|
||||
<button class="btn c-p" onclick="demoOnUpdate()">onUpdate 回调</button>
|
||||
@@ -220,7 +272,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 13. Toast 管理 -->
|
||||
<!-- 14. Toast 管理 -->
|
||||
<div class="card">
|
||||
<div class="label">🔧 Toast 管理</div>
|
||||
<div class="btn-row">
|
||||
@@ -230,7 +282,7 @@
|
||||
<button class="btn c-sl" onclick="MeToast.pauseAll();MeToast.info('已暂停全部')">暂停全部</button>
|
||||
<button class="btn c-sl" onclick="MeToast.resumeAll();MeToast.info('已恢复全部')">恢复全部</button>
|
||||
<button class="btn c-e" onclick="MeToast.dismiss()">关闭全部</button>
|
||||
<button class="btn c-r" onclick="MeToast.destroy();MeToast.info('已销毁')">销毁</button>
|
||||
<button class="btn c-r" onclick="MeToast.destroy();MeToast.init({});MeToast.info('已销毁并重建')">销毁重建</button>
|
||||
</div>
|
||||
<div class="demo-section">
|
||||
<div class="btn-row">
|
||||
@@ -238,32 +290,34 @@
|
||||
<button class="btn btn-outline btn-tiny" onclick="demoGetAll()">getAll</button>
|
||||
<button class="btn btn-outline btn-tiny" onclick="demoClearByPos()">clear(位置)</button>
|
||||
<button class="btn btn-outline btn-tiny" onclick="demoGetConfig()">查看配置</button>
|
||||
<button class="btn btn-outline btn-tiny" onclick="demoRemove()">removeToast 立即移除</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 14. 错误回调 -->
|
||||
<!-- 15. onError -->
|
||||
<div class="card">
|
||||
<div class="label">🛡️ onError 错误捕获 <span style="color:#34d399;font-size:10px;">v0.5.0</span></div>
|
||||
<div class="label">🛡️ onError 错误捕获</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-e" onclick="demoOnError()">演示 onError</button>
|
||||
<button class="btn c-w" onclick="demoOnErrorReset()">重置回调</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 15. 交互特性 -->
|
||||
<!-- 16. 交互特性 -->
|
||||
<div class="card">
|
||||
<div class="label">✋ 交互特性</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-i" onclick="demoDraggable()">拖拽关闭</button>
|
||||
<button class="btn c-p" onclick="demoPauseHover()">悬停暂停</button>
|
||||
<button class="btn c-w" onclick="demoCloseOnClick()">点击关闭</button>
|
||||
<button class="btn c-pp" onclick="demoWidth()">自定义宽度</button>
|
||||
<button class="btn c-t" onclick="demoClassName()">自定义className</button>
|
||||
<button class="btn c-p" onclick="demoDragThreshold()">拖拽阈值 300px</button>
|
||||
<button class="btn c-w" onclick="demoPauseHover()">悬停暂停</button>
|
||||
<button class="btn c-pp" onclick="demoCloseOnClick()">点击关闭</button>
|
||||
<button class="btn c-t" onclick="demoWidth()">自定义宽度</button>
|
||||
<button class="btn c-sl" onclick="demoClassName()">自定义 className</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 16. 国际化切换 -->
|
||||
<!-- 17. 国际化 -->
|
||||
<div class="card">
|
||||
<div class="label">🌍 国际化 & 格式化</div>
|
||||
<div class="btn-row">
|
||||
@@ -273,16 +327,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 17. 107种预设图标 -->
|
||||
<!-- 18. 图标网格 -->
|
||||
<div class="card" style="grid-column:1/-1;">
|
||||
<div class="label">🎨 107种预设图标 — 点击任意图标发送Toast</div>
|
||||
<div class="btn-row" id="icon-grid" style="max-height:300px;overflow-y:auto;padding:4px 0;"></div>
|
||||
<div class="label">🎨 107 种预设图标 — 点击任意图标发送 Toast</div>
|
||||
<div class="btn-row" id="icon-grid" style="max-height:320px;overflow-y:auto;padding:4px 0;"></div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
MetonaToast v0.5.0 · MIT · <a href="index.html">首页</a> · <a href="docs.html">文档</a> · <a href="https://git.metona.cn/MetonaTeam/MetonaToast">Gitea</a>
|
||||
MetonaToast v0.5.0 · MIT ·
|
||||
<a href="index.html">首页</a> ·
|
||||
<a href="docs.html">文档</a> ·
|
||||
<a href="https://git.metona.cn/MetonaTeam/MetonaToast">Gitea</a>
|
||||
</footer>
|
||||
|
||||
<script src="../dist/metona-toast.js"></script>
|
||||
@@ -290,27 +347,41 @@
|
||||
MeToast.configure({ position:'top-right', duration:4000, theme:'dark', animation:'slide', pauseOnHover:true, showProgress:true });
|
||||
|
||||
// === Loading ===
|
||||
function demoLoading() { const l=MeToast.loading('正在提交...'); setTimeout(()=>l.success('提交成功!'),2000); }
|
||||
function demoLoadingFail() { const l=MeToast.loading('正在处理...'); setTimeout(()=>l.error('处理失败'),2000); }
|
||||
function demoLoadingWarn() { const l=MeToast.loading('检查中...'); setTimeout(()=>l.warning('发现潜在问题'),2000); }
|
||||
function demoLoadingUpdate() { const l=MeToast.loading('处理中 0%'); let i=1; const t=setInterval(()=>{if(i>3){clearInterval(t);l.success('完成!');return;} l.update({message:'处理中 '+i*33+'%'}); i++;},600); }
|
||||
function demoLoading(mode) {
|
||||
const l = MeToast.loading('正在处理...');
|
||||
const showId = () => document.getElementById('loading-status').textContent = 'loading id: ' + l.id;
|
||||
showId();
|
||||
setTimeout(() => {
|
||||
const map = { success:['提交成功!','success'], error:['处理失败','error'], warning:['发现潜在问题','warning'], update:null };
|
||||
if (mode === 'update') {
|
||||
l.update({ message: '进度 50%' });
|
||||
setTimeout(() => l.success('完成!'), 1000);
|
||||
return;
|
||||
}
|
||||
const [msg, type] = map[mode];
|
||||
const t = l[type](msg);
|
||||
if (t) document.getElementById('loading-status').textContent = '转换后 id: ' + t.id + '(' + (t.id === l.id ? '同一实例 ✓' : '不同实例 ✗') + ')';
|
||||
}, 1600);
|
||||
}
|
||||
|
||||
// === Promise / confirm / prompt ===
|
||||
async function demoPromise() {
|
||||
const p=new Promise((r,e)=>setTimeout(()=>Math.random()>0.3?r('ok'):e('fail'),2000));
|
||||
try{await MeToast.promise(p,{loading:'处理中...',success:'成功!',error:'失败'});}catch(_){}
|
||||
const p = new Promise((r,e)=>setTimeout(()=>Math.random()>0.3?r('ok'):e('fail'),2000));
|
||||
try{ await MeToast.promise(p,{loading:'处理中...',success:'成功!',error:'失败'}); }catch(_){}
|
||||
}
|
||||
async function demoConfirm() { const ok=await MeToast.confirm('确定删除?',{confirmText:'删除',confirmColor:'#ef4444'}); if(ok)MeToast.success('已删除'); }
|
||||
async function demoPrompt() { const v=await MeToast.prompt('请输入姓名',{placeholder:'请输入...'}); if(v) MeToast.info('你好,'+v+'!'); }
|
||||
async function demoPromptPassword() { const v=await MeToast.prompt('请输入密码',{placeholder:'密码',inputType:'password',submitText:'登录'}); if(v) MeToast.info('密码已输入'); }
|
||||
|
||||
// === Progress & Countdown ===
|
||||
function demoProgress() { const p=MeToast.progress('上传中...',{progressColor:'#3b82f6'}); let v=0; const t=setInterval(()=>{v+=Math.random()*25; if(v>=100){clearInterval(t);p.complete('上传完成!');}else p.setProgress(v);},400); }
|
||||
function demoProgressV() { const p=MeToast.progress('上传中...',{progressColor:'#10b981',progressDirection:'vertical'}); let v=0; const t=setInterval(()=>{v+=Math.random()*25; if(v>=100){clearInterval(t);p.complete('完成!');}else p.setProgress(v);},400); }
|
||||
function demoProgress(dir) {
|
||||
const p=MeToast.progress('上传中...',{progressColor: dir==='vertical'?'#10b981':'#3b82f6', progressDirection: dir});
|
||||
let v=0; const t=setInterval(()=>{v+=Math.random()*25; if(v>=100){clearInterval(t);p.complete('上传完成!');}else p.setProgress(v);},400);
|
||||
}
|
||||
function demoCountdown() { MeToast.countdown('{seconds} 秒后执行',5,{onComplete:()=>MeToast.success('已执行')}); }
|
||||
function demoCountdownPause() {
|
||||
const c=MeToast.countdown('{seconds}s 可暂停',10,{type:'info',onComplete:()=>MeToast.success('倒计时结束')});
|
||||
setTimeout(()=>{c.pause();MeToast.warning('已暂停3秒后恢复',{duration:3000})},4000);
|
||||
setTimeout(()=>{c.pause();MeToast.warning('已暂停 3 秒后恢复',{duration:3000})},4000);
|
||||
setTimeout(()=>{c.resume();MeToast.info('已恢复倒计时')},7000);
|
||||
}
|
||||
|
||||
@@ -321,14 +392,15 @@
|
||||
setTimeout(()=>{q.cancel();MeToast.warning('队列已取消',{duration:2000});},3500);
|
||||
}
|
||||
function demoStack() { MeToast.stack(['消息1','消息2','消息3','消息4','消息5'],{stagger:120,type:'info'}); }
|
||||
function demoStackMixed() {
|
||||
MeToast.stack(['普通消息',{message:'警告消息',type:'warning',duration:5000},{message:'错误消息',type:'error'}],{stagger:150});
|
||||
}
|
||||
function demoStackMixed() { MeToast.stack(['普通消息',{message:'警告消息',type:'warning',duration:5000},{message:'错误消息',type:'error'}],{stagger:150}); }
|
||||
|
||||
// === Action ===
|
||||
function demoActionDelete() { MeToast.action('文件 data.json 已删除',[{text:'撤销',onClick:()=>MeToast.success('已撤销'),color:'#3b82f6'}]); }
|
||||
function demoActionMulti() { MeToast.action('邮件已发送',[{text:'查看',onClick:()=>MeToast.info('打开邮件详情'),color:'#3b82f6'},{text:'撤回',onClick:()=>MeToast.warning('已撤回'),color:'#f59e0b'}]); }
|
||||
function demoActionNoClose() { MeToast.action('完成后点击关闭',[{text:'我知道了',onClick:()=>{},color:'#10b981'}]); }
|
||||
function demoActionNoClose() {
|
||||
let n=0;
|
||||
MeToast.action('点「+1」不会关闭,可连续点击',[{text:'+1',onClick:(t)=>{n++;t.update({message:'已点击 '+n+' 次(close:false 不关闭)'});},color:'#10b981',close:false}],{duration:8000});
|
||||
}
|
||||
|
||||
// === Group ===
|
||||
const group = MeToast.group('demo-group');
|
||||
@@ -342,32 +414,71 @@
|
||||
|
||||
// === Animation ===
|
||||
function anim(name) { MeToast.success('动画: '+name,{animation:name,duration:3000,showProgress:false}); }
|
||||
function demoCustomAnim() {
|
||||
MeToast.animations.register('swing', {
|
||||
enter: { transform: 'rotate(-40deg) scale(0.3)', opacity: 0 },
|
||||
leave: { transform: 'rotate(20deg) scale(0.5)', opacity: 0 },
|
||||
duration: 600,
|
||||
easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
|
||||
});
|
||||
MeToast.success('自定义 swing 动画!', { animation: 'swing', duration: 3000 });
|
||||
}
|
||||
|
||||
// === Theme ===
|
||||
function switchTheme(t) { MeToast.themes.switchTheme(t); MeToast.configure({theme:t}); MeToast.info('主题: '+t,{theme:t}); }
|
||||
function demoRegisterTheme() {
|
||||
try {
|
||||
MeToast.themes.registerTheme('sunset',{bg:'rgba(255,248,240,0.96)',text:'#92400e',border:'rgba(249,115,22,0.2)',shadow:'0 10px 36px -10px rgba(249,115,22,0.2)',hoverShadow:'0 14px 48px -10px rgba(249,115,22,0.3)',progressBg:'rgba(249,115,22,0.1)',closeHoverBg:'rgba(249,115,22,0.1)'});
|
||||
MeToast.themes.switchTheme('sunset');
|
||||
MeToast.configure({theme:'sunset'});
|
||||
MeToast.themes.switchTheme('sunset'); MeToast.configure({theme:'sunset'});
|
||||
MeToast.success('已切换到 sunset 主题',{theme:'sunset'});
|
||||
} catch(_) { MeToast.warning('主题已注册,已切换'); }
|
||||
}
|
||||
|
||||
// === Plugins ===
|
||||
function demoCustomPlugin() {
|
||||
MeToast.use({name:'click-counter',version:'1.0',install(){let c=0;Toast.on('afterShow',t=>{c++;setTimeout(()=>t.update({message:t.message.replace(/\\(\\d+\\)/,'')+' (总通知#'+c+')'}),1);});}});
|
||||
MeToast.use({name:'click-counter',version:'1.0',install(){let c=0;Toast.on('afterShow',t=>{c++;setTimeout(()=>t.update({message:t.message.replace(/\(\d+\)/,'')+' (总通知#'+c+')'}),1);});}});
|
||||
MeToast.info('自定义插件已安装(消息后追加计数)');
|
||||
}
|
||||
function demoDedupe() {
|
||||
if (!MeToast.plugins.has('dedupe')) MeToast.use('dedupe');
|
||||
MeToast.info('同一条消息');
|
||||
MeToast.info('同一条消息');
|
||||
MeToast.info('同一条消息');
|
||||
MeToast.info('当前仅 ' + MeToast.count() + ' 条 — 相同消息自动合并');
|
||||
}
|
||||
|
||||
// === Hooks ===
|
||||
let hookOff = null;
|
||||
function demoHookBlock() {
|
||||
if (hookOff) hookOff();
|
||||
hookOff = Toast.on('beforeShow', (toast) => {
|
||||
if (toast.type === 'error') { document.getElementById('hook-status').textContent = '钩子:error 已被拦截 ✋'; return false; }
|
||||
});
|
||||
document.getElementById('hook-status').textContent = '钩子:已注册(error 类型将被拦截)';
|
||||
MeToast.info('拦截器已开启 — 试试触发 error');
|
||||
}
|
||||
function demoHookUnblock() {
|
||||
if (hookOff) { hookOff(); hookOff = null; }
|
||||
document.getElementById('hook-status').textContent = '钩子:已移除';
|
||||
MeToast.info('拦截器已关闭');
|
||||
}
|
||||
function demoHookCount() {
|
||||
const stats = [];
|
||||
['afterShow','afterClose','configChange','themeChange'].forEach(name => {
|
||||
const list = Toast._hooks.get(name);
|
||||
stats.push(name + ':' + (list ? list.length : 0));
|
||||
});
|
||||
MeToast.info('钩子数量 — ' + stats.join(' '), { duration: 5000 });
|
||||
}
|
||||
|
||||
// === 高级特性 ===
|
||||
function demoResetTimer() {
|
||||
const t=MeToast.info('这条消息不会自动消失(resetTimer)',{duration:3000,resetTimerOnUpdate:true,closeButton:true});
|
||||
let n=0; const iv=setInterval(()=>{n++;if(n>8){clearInterval(iv);t.close();return;}t.update({message:'重置计时器 #'+n+' — 每次更新重置3秒'});},1000);
|
||||
const t=MeToast.info('这条不会自动消失(每次更新重置 3 秒)',{duration:3000,resetTimerOnUpdate:true,closeButton:true});
|
||||
let n=0; const iv=setInterval(()=>{n++;if(n>8){clearInterval(iv);t.close();return;}t.update({message:'重置计时器 #'+n});},1000);
|
||||
}
|
||||
function demoOnUpdate() { const t=MeToast.success('onUpdate 演示',{onUpdate:t=>{console.log('更新了:',t.message);}}); setTimeout(()=>t.update({message:'已更新!'}),1000); setTimeout(()=>t.update({message:'再次更新!'}),2000); }
|
||||
function demoOnUpdate() { const t=MeToast.success('onUpdate 演示',{onUpdate:t=>{console.log('更新了:',t.message);}}); setTimeout(()=>t.update({message:'已更新!'}),1000); }
|
||||
function demoCustomRender() {
|
||||
MeToast.show({render:toast=>'<div style="background:#111;color:#0f0;padding:16px 20px;border-radius:10px;border:1px solid #0f0;font-family:monospace">🟢 <b>'+toast.message+'</b><br><span style="font-size:11px;opacity:0.6"># custom render by thzxx</span></div>',message:'自定义渲染内容',duration:5000});
|
||||
MeToast.show({render:toast=>'<div style="background:#111;color:#0f0;padding:16px 20px;border-radius:10px;border:1px solid #0f0;font-family:monospace">🟢 <b>'+toast.message+'</b><br><span style="font-size:11px;opacity:0.6"># custom render</span></div>',message:'自定义渲染内容',duration:5000});
|
||||
}
|
||||
function demoNotify() {
|
||||
if(typeof Notification==='undefined'){MeToast.error('浏览器不支持 Notification');return;}
|
||||
@@ -382,48 +493,38 @@
|
||||
}
|
||||
function demoGetAll() { const all=MeToast.getAll(); MeToast.info('当前共 '+all.size+' 条 toast'); }
|
||||
function demoClearByPos() { MeToast.error('右下角临时消息',{position:'bottom-right',duration:3000}); setTimeout(()=>{MeToast.clear('bottom-right');MeToast.info('右下角已清除');},500); }
|
||||
function demoGetConfig() { try{const c=MeToast.getConfig();MeToast.info('配置: '+JSON.stringify({position:c.position,duration:c.duration,theme:c.theme,animation:c.animation,locale:c.locale}).replace(/"/g,''),{duration:5000});}catch(e){MeToast.error('无 getConfig 方法');} }
|
||||
|
||||
// === Interaction ===
|
||||
function demoDraggable() { MeToast.info('← 试试拖动我来关闭',{draggable:true,duration:8000,closeButton:true}); }
|
||||
function demoPauseHover() { MeToast.info('鼠标悬停在我上面,倒计时会暂停',{pauseOnHover:true,duration:8000}); }
|
||||
function demoCloseOnClick() { MeToast.warning('点击我即可关闭',{closeOnClick:true,duration:10000}); }
|
||||
function demoWidth() { MeToast.info('宽550px',{width:550}); setTimeout(()=>MeToast.info('宽280px(窄)',{width:280}),500); }
|
||||
function demoClassName() { MeToast.success('带自定义 className',{className:'demo-custom-class'}); }
|
||||
function demoCustomIcon() {
|
||||
MeToast.info('通用通知', {
|
||||
iconHTML: '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/></svg>'
|
||||
});
|
||||
}
|
||||
function demoGetConfig() { const c=MeToast.getConfig(); MeToast.info('配置: '+JSON.stringify({position:c.position,duration:c.duration,theme:c.theme,animation:c.animation,locale:c.locale}).replace(/"/g,''),{duration:5000}); }
|
||||
function demoRemove() { const t=MeToast.warning('这条将被立即移除(无动画)'); setTimeout(()=>{MeToast.removeToast(t.id);MeToast.info('已立即移除');},800); }
|
||||
|
||||
// === onError ===
|
||||
function demoOnError() {
|
||||
MeToast.configure({
|
||||
onError: function(info) {
|
||||
MeToast.error('⚠️ 捕获错误: ' + (info.hook || info.source), { duration: 3000, position: 'bottom-center' });
|
||||
}
|
||||
});
|
||||
MeToast.info('已启用 onError 监控(钩子/定时器异常将被捕获)', { duration: 3000 });
|
||||
// 触发一个钩子错误来演示
|
||||
MeToast.configure({ onError: function(info) { MeToast.error('⚠️ 捕获: ' + (info.hook || info.source), { duration: 3000, position: 'bottom-center' }); } });
|
||||
MeToast.info('已启用 onError 监控', { duration: 3000 });
|
||||
var badFn = function() { throw new Error('demo-error'); };
|
||||
Toast.on('afterShow', badFn);
|
||||
MeToast.success('这条消息会触发错误', { duration: 2000 });
|
||||
MeToast.success('这条会触发错误回调', { duration: 2000 });
|
||||
setTimeout(function() { Toast.off('afterShow', badFn); }, 3000);
|
||||
}
|
||||
function demoOnErrorReset() {
|
||||
MeToast.configure({ onError: null });
|
||||
MeToast.info('onError 已重置为 null');
|
||||
function demoOnErrorReset() { MeToast.configure({ onError: null }); MeToast.info('onError 已重置'); }
|
||||
|
||||
// === Interaction ===
|
||||
function demoDraggable() { MeToast.info('← 拖动我超过 120px 关闭',{draggable:true,duration:8000,closeButton:true}); }
|
||||
function demoDragThreshold() { MeToast.info('← 拖动阈值 300px(要拖更远)',{draggable:true,dragThreshold:300,duration:8000,closeButton:true}); }
|
||||
function demoPauseHover() { MeToast.info('悬停时倒计时会暂停',{pauseOnHover:true,duration:8000}); }
|
||||
function demoCloseOnClick() { MeToast.warning('点击我即可关闭',{closeOnClick:true,duration:10000}); }
|
||||
function demoWidth() { MeToast.info('宽 550px',{width:550}); setTimeout(()=>MeToast.info('宽 280px(窄)',{width:280}),500); }
|
||||
function demoClassName() { MeToast.success('带自定义 className',{className:'demo-custom-class'}); }
|
||||
function demoCustomIcon() {
|
||||
MeToast.info('通用通知', { iconHTML: '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/></svg>' });
|
||||
}
|
||||
|
||||
// === i18n ===
|
||||
function switchLocale(loc) {
|
||||
try{MeToast.i18n.switchLocale(loc);MeToast.configure({locale:loc});MeToast.success(loc==='zh-CN'?'已切换到中文':'Switched to English',{theme:'dark'});}
|
||||
catch(e){MeToast.info('已切换语言');}
|
||||
MeToast.i18n.switchLocale(loc); MeToast.configure({locale:loc});
|
||||
MeToast.success(loc==='zh-CN'?'已切换到中文':'Switched to English');
|
||||
}
|
||||
function demoFormat() {
|
||||
try{
|
||||
MeToast.info('数字: '+MeToast.i18n.formatNumber(1234567)+' | 货币: '+MeToast.i18n.formatCurrency(99.5,'CNY')+' | 日期: '+MeToast.i18n.formatDate(new Date()),{duration:8000});
|
||||
}catch(e){MeToast.info('格式化: 1234567 → 1,234,567');}
|
||||
MeToast.info('数字: '+MeToast.i18n.formatNumber(1234567)+' | 货币: '+MeToast.i18n.formatCurrency(99.5,'CNY')+' | 日期: '+MeToast.i18n.formatDate(new Date()),{duration:8000});
|
||||
}
|
||||
|
||||
// === 图标网格 ===
|
||||
|
||||
Reference in New Issue
Block a user