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:
tianhao
2026-08-08 15:11:04 +08:00
parent 1f718c4ef8
commit dd061025e0
4 changed files with 1019 additions and 688 deletions
+355 -146
View File
@@ -5,62 +5,231 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<title>MetonaToast — 轻量精致的 Toast 通知库</title>
<meta name="description" content="MetonaToast 是轻量、零依赖、精致美观的 Toast 通知库。107 种图标类型、11 种动画、主题系统、国际化、插件架构。">
<meta name="description" content="MetonaToast 是轻量、零依赖、精致美观的 Toast 通知库。107 种图标、11 种动画、主题系统、国际化、插件架构、React 适配器。">
<style>
:root {
--bg: #0b1121; --bg2: #111827; --surface: #1a2332;
--border: #1e2d4d; --text: #e2e8f0; --muted: #64748b;
--accent: #6366f1; --accent2: #818cf8; --radius: 14px;
--bg: #070b14;
--surface: rgba(255,255,255,0.03);
--surface-hover: rgba(255,255,255,0.06);
--border: rgba(255,255,255,0.08);
--text: #e8ecf4;
--muted: #8b94a7;
--accent1: #6366f1;
--accent2: #a855f7;
--accent3: #ec4899;
--grad: linear-gradient(135deg, #818cf8, #c084fc, #f472b6);
--radius: 16px;
}
* { 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.7; }
a { color: var(--accent2); text-decoration: none; }
code { background: rgba(99,102,241,0.12); color: #a5b4fc; padding: 2px 7px; border-radius: 5px; font-size: 0.9em; }
pre { background: #0a0f1a; border: 1px solid var(--border); border-radius: 10px; padding: 18px 22px; overflow-x: auto; font: 13px/1.8 'SF Mono','Cascadia Code','Fira Code',Consolas,monospace; color: #cbd5e1; }
pre .kw { color: #c084fc; } pre .fn { color: #60a5fa; } pre .s { color: #34d399; } pre .cm { color: #475569; }
* { margin:0; padding:0; box-sizing:border-box; }
html { scroll-behavior:smooth; }
body {
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;
background:var(--bg); color:var(--text); line-height:1.7; overflow-x:hidden;
background-image:
radial-gradient(ellipse 80% 50% at 50% -20%, rgba(99,102,241,0.15), transparent),
radial-gradient(ellipse 60% 40% at 90% 10%, rgba(168,85,247,0.08), transparent),
radial-gradient(ellipse 50% 40% at 10% 30%, rgba(236,72,153,0.06), transparent);
}
/* 背景网格 */
body::before {
content:''; position:fixed; inset:0; pointer-events:none; z-index:0;
background-image:
linear-gradient(rgba(255,255,255,0.025) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.025) 1px, transparent 1px);
background-size:56px 56px;
mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, black 40%, transparent 100%);
-webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, black 40%, transparent 100%);
}
a { color:#a5b4fc; text-decoration:none; transition:color .2s; }
a:hover { color:#c7d2fe; }
::selection { background:rgba(139,92,246,.4); }
.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: 1200px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; 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: 24px; }
.nav-links a { color: var(--muted); font-size: 14px; font-weight: 500; transition: .2s; }
.nav-links a:hover { color: var(--accent2); }
.grad-text {
background:var(--grad);
-webkit-background-clip:text; background-clip:text;
-webkit-text-fill-color:transparent; color:transparent;
}
.hero { text-align: center; padding: 100px 20px 70px; background: radial-gradient(ellipse at 50% 0%, rgba(99,102,241,0.18) 0%, transparent 60%), linear-gradient(180deg, #0f172a 0%, var(--bg) 100%); border-bottom: 1px solid var(--border); }
.hero h1 { font-size: 52px; 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; }
.hero p { color: var(--muted); font-size: 17px; margin-top: 12px; max-width: 600px; margin-left: auto; margin-right: auto; }
.hero .badges { display: flex; gap: 12px; justify-content: center; margin-top: 24px; flex-wrap: wrap; }
.hero .badges span { background: var(--surface); border: 1px solid var(--border); border-radius: 20px; padding: 6px 18px; font-size: 13px; color: var(--accent2); }
.hero-actions { margin-top: 32px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.btn { padding: 11px 28px; border-radius: 10px; font-size: 14px; font-weight: 600; cursor: pointer; transition: .2s; border: none; }
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent2); transform: translateY(-1px); }
.btn-outline { background: transparent; border: 1px solid var(--border); color: var(--text); }
.btn-outline:hover { border-color: var(--accent); color: var(--accent2); }
/* ===== Nav ===== */
.nav {
position:sticky; top:0; z-index:100;
background:rgba(7,11,20,0.7);
backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);
border-bottom:1px solid var(--border);
}
.nav-inner {
max-width:1180px; margin:0 auto; display:flex; align-items:center;
justify-content:space-between; padding:0 28px; height:60px;
}
.nav-logo { font-size:19px; font-weight:800; letter-spacing:.2px; cursor:pointer; }
.nav-links { display:flex; gap:26px; }
.nav-links a { color:var(--muted); font-size:14px; font-weight:500; position:relative; }
.nav-links a::after {
content:''; position:absolute; left:0; right:100%; bottom:-6px; height:2px;
background:var(--grad); border-radius:2px; transition:right .25s;
}
.nav-links a:hover::after { right:0; }
.nav-links a:hover { color:var(--text); }
.container { max-width: 1100px; margin: 0 auto; padding: 60px 24px; }
.section-title { font-size: 28px; font-weight: 700; text-align: center; margin-bottom: 8px; }
.section-desc { color: var(--muted); text-align: center; margin-bottom: 40px; font-size: 15px; }
/* ===== Hero ===== */
.hero { text-align:center; padding:110px 24px 60px; position:relative; z-index:1; }
.hero-badge {
display:inline-flex; align-items:center; gap:8px;
background:rgba(99,102,241,0.1); border:1px solid rgba(99,102,241,0.3);
color:#a5b4fc; font-size:12px; font-weight:600; letter-spacing:1px;
padding:6px 16px; border-radius:999px; margin-bottom:26px;
}
.hero-badge .dot {
width:7px; height:7px; border-radius:50%; background:#34d399;
box-shadow:0 0 12px #34d399; animation:pulse 2s infinite;
}
@keyframes pulse { 50% { opacity:.4; } }
.hero h1 { font-size:clamp(42px, 7vw, 76px); font-weight:800; letter-spacing:-1px; line-height:1.1; }
.hero h1 .grad-text { animation:shimmer 6s linear infinite; }
@keyframes shimmer {
0%,100% { filter:hue-rotate(0deg); }
50% { filter:hue-rotate(30deg); }
}
.hero-sub {
color:var(--muted); font-size:clamp(15px, 2.2vw, 18px);
max-width:640px; margin:18px auto 0;
}
.hero-badges { display:flex; gap:10px; justify-content:center; margin-top:26px; flex-wrap:wrap; }
.hero-badges span {
background:var(--surface); border:1px solid var(--border); border-radius:999px;
padding:5px 14px; font-size:12.5px; color:#cbd5e1;
transition:border-color .2s, transform .2s;
}
.hero-badges span:hover { border-color:rgba(129,140,248,.5); transform:translateY(-2px); }
.hero-actions { margin-top:36px; display:flex; gap:14px; justify-content:center; flex-wrap:wrap; }
.btn {
padding:12px 30px; border-radius:12px; font-size:14.5px; font-weight:600;
cursor:pointer; transition:transform .2s, box-shadow .2s, border-color .2s;
border:1px solid transparent;
}
.btn-primary {
background:var(--grad); color:#fff;
box-shadow:0 8px 30px -8px rgba(139,92,246,.6);
}
.btn-primary:hover { transform:translateY(-2px); box-shadow:0 12px 40px -8px rgba(139,92,246,.8); }
.btn-ghost { background:var(--surface); border-color:var(--border); color:var(--text); }
.btn-ghost:hover { border-color:rgba(129,140,248,.5); transform:translateY(-2px); background:var(--surface-hover); }
.features { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 18px; }
.feature { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; transition: .2s; }
.feature:hover { border-color: var(--accent); }
.feature-icon { font-size: 28px; margin-bottom: 12px; }
.feature h3 { font-size: 16px; margin-bottom: 6px; }
.feature p { color: var(--muted); font-size: 13px; line-height: 1.6; }
/* 浮动光球 */
.orb { position:absolute; border-radius:50%; filter:blur(70px); pointer-events:none; z-index:0; }
.orb-1 { width:340px; height:340px; background:rgba(99,102,241,.25); top:-80px; left:12%; animation:float 12s ease-in-out infinite; }
.orb-2 { width:260px; height:260px; background:rgba(236,72,153,.18); top:40px; right:10%; animation:float 15s ease-in-out infinite reverse; }
.orb-3 { width:200px; height:200px; background:rgba(168,85,247,.2); bottom:-40px; left:40%; animation:float 18s ease-in-out infinite 2s; }
@keyframes float { 0%,100%{transform:translateY(0) translateX(0);} 50%{transform:translateY(-30px) translateX(20px);} }
.code-block { max-width: 750px; margin: 0 auto; }
/* ===== 数据统计 ===== */
.stats { position:relative; z-index:1; max-width:1000px; margin:10px auto 0; padding:0 24px; }
.stats-grid {
display:grid; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); gap:1px;
background:var(--border); border:1px solid var(--border); border-radius:var(--radius); overflow:hidden;
}
.stat { background:rgba(10,15,26,.85); padding:22px 12px; text-align:center; backdrop-filter:blur(8px); }
.stat-num { font-size:26px; font-weight:800; }
.stat-label { font-size:12px; color:var(--muted); margin-top:2px; letter-spacing:.5px; }
.theme-demo { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin: 24px 0; }
.theme-btn { padding: 10px 20px; border-radius: 8px; border: 1px solid var(--border); cursor: pointer; background: var(--surface); color: var(--text); font-size: 13px; font-weight: 500; transition: .2s; }
.theme-btn:hover { border-color: var(--accent); }
/* ===== 通用 Section ===== */
.container { position:relative; z-index:1; max-width:1100px; margin:0 auto; padding:80px 24px; }
.section-title { font-size:30px; font-weight:800; text-align:center; letter-spacing:-.5px; }
.section-desc { color:var(--muted); text-align:center; margin-top:8px; font-size:15px; }
footer { text-align: center; padding: 40px 24px; color: var(--muted); font-size: 13px; border-top: 1px solid var(--border); }
/* ===== 特性卡片 ===== */
.features { display:grid; grid-template-columns:repeat(auto-fill, minmax(300px, 1fr)); gap:16px; margin-top:44px; }
.feature {
background:var(--surface); border:1px solid var(--border); border-radius:var(--radius);
padding:26px 24px; transition:transform .25s, border-color .25s, background .25s;
position:relative; overflow:hidden;
}
.feature::before {
content:''; position:absolute; top:0; left:0; right:0; height:2px;
background:var(--grad); opacity:0; transition:opacity .25s;
}
.feature:hover { transform:translateY(-4px); border-color:rgba(129,140,248,.4); background:var(--surface-hover); }
.feature:hover::before { opacity:1; }
.feature-icon { font-size:26px; margin-bottom:12px; display:inline-block; }
.feature h3 { font-size:15.5px; margin-bottom:6px; font-weight:700; }
.feature p { color:var(--muted); font-size:13px; line-height:1.65; }
.feature code {
background:rgba(99,102,241,0.15); color:#a5b4fc;
padding:1px 6px; border-radius:5px; font-size:12px;
}
@media (max-width: 768px) {
.hero h1 { font-size: 32px; }
.nav-links { gap: 14px; }
/* ===== 代码块 ===== */
.code-block { max-width:760px; margin:36px auto 0; }
.terminal {
background:#0a0f1c; border:1px solid var(--border); border-radius:12px; overflow:hidden;
box-shadow:0 20px 60px -20px rgba(0,0,0,.6);
}
.terminal-bar {
display:flex; align-items:center; gap:7px; padding:11px 16px;
background:rgba(255,255,255,0.03); border-bottom:1px solid var(--border);
}
.terminal-bar .t-dot { width:11px; height:11px; border-radius:50%; }
.terminal-bar .t-dot:nth-child(1){ background:#ff5f57; } .terminal-bar .t-dot:nth-child(2){ background:#febc2e; } .terminal-bar .t-dot:nth-child(3){ background:#28c840; }
.terminal-bar .t-title { margin-left:10px; font-size:11.5px; color:var(--muted); letter-spacing:.5px; }
.terminal pre {
padding:20px 22px; overflow-x:auto;
font:13px/1.8 'SF Mono','Cascadia Code','Fira Code',Consolas,monospace;
color:#cbd5e1;
}
.terminal pre .kw { color:#c084fc; } .terminal pre .fn { color:#60a5fa; }
.terminal pre .s { color:#34d399; } .terminal pre .cm { color:#475569; }
.terminal pre .num { color:#f472b6; }
/* ===== 主题预览 ===== */
.theme-demo { display:flex; gap:12px; justify-content:center; flex-wrap:wrap; margin-top:36px; }
.theme-btn {
padding:11px 22px; border-radius:10px; border:1px solid var(--border);
cursor:pointer; background:var(--surface); color:var(--text);
font-size:13.5px; font-weight:500; transition:all .2s;
}
.theme-btn:hover { border-color:rgba(129,140,248,.5); transform:translateY(-2px); }
.theme-btn.active {
background:var(--grad); color:#fff; border-color:transparent;
box-shadow:0 6px 24px -6px rgba(139,92,246,.6);
}
/* ===== 环境支持 ===== */
.env-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(160px, 1fr)); gap:12px; margin-top:40px; }
.env-card {
background:var(--surface); border:1px solid var(--border); border-radius:12px;
padding:20px 14px; text-align:center; transition:border-color .2s, transform .2s;
}
.env-card:hover { border-color:rgba(129,140,248,.4); transform:translateY(-3px); }
.env-card .e-ico { font-size:26px; }
.env-card h3 { font-size:14px; margin:8px 0 2px; }
.env-card p { font-size:12.5px; color:var(--muted); }
/* ===== CTA ===== */
.cta {
max-width:760px; margin:0 auto; text-align:center;
background:var(--grad); border-radius:20px; padding:56px 32px;
position:relative; overflow:hidden;
}
.cta::before {
content:''; position:absolute; inset:0;
background:radial-gradient(ellipse 60% 60% at 50% 120%, rgba(255,255,255,.25), transparent);
}
.cta h2 { font-size:30px; font-weight:800; color:#fff; position:relative; }
.cta p { color:rgba(255,255,255,.85); margin-top:10px; position:relative; }
.cta .btn { margin-top:26px; background:#fff; color:#6d28d9; position:relative; }
.cta .btn:hover { transform:translateY(-2px); }
footer { text-align:center; padding:44px 24px; color:var(--muted); font-size:13px; border-top:1px solid var(--border); position:relative; z-index:1; }
footer a { color:#a5b4fc; }
/* 滚动淡入 */
.reveal { opacity:0; transform:translateY(24px); transition:opacity .6s ease, transform .6s ease; }
.reveal.visible { opacity:1; transform:none; }
@media (max-width:768px) {
.hero { padding:80px 20px 44px; }
.nav-links { gap:16px; }
.container { padding:56px 20px; }
}
</style>
</head>
@@ -68,7 +237,7 @@
<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>
@@ -79,117 +248,117 @@
</nav>
<header class="hero">
<h1><span>MetonaToast</span></h1>
<p>轻量 · 零依赖 · 精致美观的 Toast 通知库。TypeScript 严格模式源码,gzip 不到 10KB。</p>
<div class="badges">
<span>📦 &lt;10KB gzip</span><span>🎨 107 图标</span><span>🎭 11 动画</span><span>🌍 国际化</span><span>🔌 插件</span><span>📘 TypeScript</span>
<div class="orb orb-1"></div>
<div class="orb orb-2"></div>
<div class="orb orb-3"></div>
<div class="hero-badge"><span class="dot"></span> v0.5.0 · 385 测试 · 覆盖率 96%</div>
<h1><span class="grad-text">MetonaToast</span></h1>
<p class="hero-sub">轻量 · 零依赖 · 精致美观的 Toast 通知库。TypeScript 严格模式,gzip 不到 10KB,一切开箱即用。</p>
<div class="hero-badges">
<span>📦 &lt;10KB gzip</span>
<span>🎨 107 图标</span>
<span>🎭 11 动画</span>
<span>🧩 4 插件</span>
<span>🔗 17 钩子</span>
<span>⚛️ React 适配器</span>
<span>🌍 国际化</span>
</div>
<div class="hero-actions">
<button class="btn btn-primary" onclick="demoQuickStart()">快速预览</button>
<button class="btn btn-outline" onclick="location.href='docs.html'">查看文档</button>
<button class="btn btn-primary" onclick="demoQuickStart()">快速预览</button>
<button class="btn btn-ghost" onclick="location.href='docs.html'">📖 查看文档</button>
<button class="btn btn-ghost" onclick="location.href='demo.html'">🎮 在线演示</button>
</div>
</header>
<section class="stats reveal">
<div class="stats-grid">
<div class="stat"><div class="stat-num grad-text">&lt;10KB</div><div class="stat-label">gzip 体积</div></div>
<div class="stat"><div class="stat-num grad-text">107</div><div class="stat-label">内置图标</div></div>
<div class="stat"><div class="stat-num grad-text">11</div><div class="stat-label">动画效果</div></div>
<div class="stat"><div class="stat-num grad-text">17</div><div class="stat-label">生命周期钩子</div></div>
<div class="stat"><div class="stat-num grad-text">385</div><div class="stat-label">测试用例</div></div>
<div class="stat"><div class="stat-num grad-text">96%</div><div class="stat-label">行覆盖率</div></div>
</div>
</section>
<main class="container">
<h2 class="section-title">核心特性</h2>
<p class="section-desc">一切你需要的,都在一个不到 10KB 的包中</p>
<h2 class="section-title reveal">核心特性</h2>
<p class="section-desc reveal">你需要的一切,都在一个不到 10KB 的包中</p>
<div class="features">
<div class="feature">
<div class="feature reveal">
<div class="feature-icon"></div>
<h3>零依赖</h3>
<p>TypeScript 严格模式,纯原生实现,无任何运行时依赖。兼容所有现代浏览器。</p>
</div>
<div class="feature reveal">
<div class="feature-icon">🎨</div>
<h3>107 种图标类型</h3>
<p>success / error / warning / info / loading 及 100+ 扩展类型,覆盖所有常见场景。</p>
<p>success / error / warning / info / loading 及 100+ 扩展类型,覆盖所有常见场景。</p>
</div>
<div class="feature">
<div class="feature reveal">
<div class="feature-icon">🎭</div>
<h3>11 种动画效果</h3>
<p>slide / fade / scale / bounce / flip / rotate / zoom / slideUp / slideDown / slideLeft / slideRight,每种感官差异明显</p>
<h3>11 种动画 + 自定义</h3>
<p>每种感官差异明显,<code>animations.register()</code> 注册自定义动画,动态注入 keyframes 真实生效</p>
</div>
<div class="feature">
<div class="feature reveal">
<div class="feature-icon">🖌️</div>
<h3>主题系统</h3>
<p>内置 light / dark / auto / warm 四种主题,支持 <code>registerTheme()</code> 自定义注册任意主题</p>
<p>light / dark / auto / warm 内置主题,<code>registerTheme()</code> 自定义,跟随系统自动切换</p>
</div>
<div class="feature">
<div class="feature reveal">
<div class="feature-icon">🌍</div>
<h3>国际化</h3>
<p>内置 zh-CN en-US 完整翻译,400+ 词汇。支持 <code>addTranslations()</code> 扩展任意语言。</p>
<p>zh-CN / en-US 完整翻译,<code>addTranslations()</code> 扩展任意语言RTL 完整适配</p>
</div>
<div class="feature">
<div class="feature-icon">🔌</div>
<div class="feature reveal">
<div class="feature-icon">🧩</div>
<h3>插件系统</h3>
<p>3 款预设插件 + 自定义插件架构。keyboard / persistence / accessibility 开箱即用</p>
<p>4 款预设keyboard / persistence / accessibility / dedupe,支持自定义插件架构</p>
</div>
<div class="feature">
<div class="feature reveal">
<div class="feature-icon">🔗</div>
<h3>17 个钩子</h3>
<p>完整生命周期钩子,<code>beforeShow</code> / <code>beforeClose</code> / <code>beforeUpdate</code> 支持拦截。</p>
</div>
<div class="feature reveal">
<div class="feature-icon"></div>
<h3>拖拽关闭</h3>
<p>任意方向拖动 Toast 即可关闭。支持 Pointer Events,移动端和桌面端体验一致。</p>
<p>任意方向拖动即关,阈值 <code>dragThreshold</code> 可配置。Pointer Events 全端一致。</p>
</div>
<div class="feature">
<div class="feature-icon"></div>
<h3>零依赖</h3>
<p>TypeScript 严格模式,纯原生实现,无需任何运行时依赖。兼容所有现代浏览器</p>
<div class="feature reveal">
<div class="feature-icon">⚛️</div>
<h3>React 适配器</h3>
<p><code>@metona-team/metona-toast/react</code> — useToast hook + 声明式 Toast 组件,主包保持零依赖</p>
</div>
<div class="feature">
<div class="feature reveal">
<div class="feature-icon">🛡️</div>
<h3>错误捕获</h3>
<p>全局 <code>onError</code> 回调捕获钩子异常和定时器错误,方便接入 Sentry、DataDog 等监控系统</p>
<p>全局 <code>onError</code> 回调捕获钩子定时器异常,方便接入 Sentry、DataDog。</p>
</div>
<div class="feature">
<div class="feature reveal">
<div class="feature-icon">⏱️</div>
<h3>暂停恢复</h3>
<p>悬停自动暂停、拖拽临时暂停、手动 pause/resume,剩余时间精确保持不丢失进度</p>
<p>悬停暂停、拖拽暂停、手动 pause/resume,剩余时间精确保持不丢失。</p>
</div>
<div class="feature">
<div class="feature reveal">
<div class="feature-icon">📘</div>
<h3>TypeScript</h3>
<p>严格模式源码,类型从源码自动生成。strictNullChecks、noImplicitAny 全开,零类型漂移</p>
<h3>类型安全</h3>
<p>严格模式源码,类型自动生成零漂移。加载态转换 id 稳定,原地更新</p>
</div>
</div>
</main>
<section class="container">
<h2 class="section-title">环境支持</h2>
<p class="section-desc">所有现代浏览器原生支持,无需 polyfill</p>
<div class="env-grid" style="display:grid; grid-template-columns:repeat(auto-fill,minmax(165px,1fr)); gap:12px;">
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">🌐</div>
<h3>Chrome</h3>
<p>64+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">🦊</div>
<h3>Firefox</h3>
<p>63+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">🧭</div>
<h3>Safari</h3>
<p>11+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">🪟</div>
<h3>Edge</h3>
<p>79+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">📦</div>
<h3>Node.js</h3>
<p>16+</p>
</div>
<div class="feature" style="text-align:center;padding:20px 16px;">
<div style="font-size:28px;margin-bottom:6px;">📘</div>
<h3>TypeScript</h3>
<p>4.5+</p>
</div>
</div>
<p style="text-align:center;color:var(--muted);font-size:13px;margin-top:16px">核心依赖:Web Animations API · Pointer Events · CSS Grid · CSS Custom Properties</p>
</section>
<section class="container">
<h2 class="section-title">快速开始</h2>
<p class="section-desc">浏览器 window 上仅注册两个全局变量:<code>MeToast</code><code>Met</code>,完全等价</p>
<div class="code-block">
<pre><span class="cm"># npm 安装</span>
<section class="container" style="padding-top:0">
<h2 class="section-title reveal">快速开始</h2>
<p class="section-desc reveal">浏览器上仅注册两个全局变量:<code>MeToast</code><code>Met</code>,完全等价</p>
<div class="code-block reveal">
<div class="terminal">
<div class="terminal-bar">
<span class="t-dot"></span><span class="t-dot"></span><span class="t-dot"></span>
<span class="t-title">quickstart.js</span>
</div>
<pre><span class="cm"># 安装</span>
npm install @metona-team/metona-toast
<span class="cm">// 导入</span>
@@ -202,43 +371,45 @@ MeToast.<span class="fn">loading</span>(<span class="s">'加载中...'</span>);
<span class="cm">// CDN 直接引用</span>
<span class="kw">&lt;script</span> <span class="fn">src</span>=<span class="s">"https://git.metona.cn/MetonaTeam/MetonaToast/raw/branch/master/dist/metona-toast.min.js"</span><span class="kw">&gt;&lt;/script&gt;</span></pre>
</div>
</div>
</section>
<section class="container">
<h2 class="section-title">高级功能速览</h2>
<p class="section-desc">不仅仅是一个 Toast——确认框、输入框、进度条、倒计时、队列,应有尽有</p>
<div class="code-block">
<pre><span class="cm">// Promise 风格 — 自动 loading → success/error</span>
<section class="container" style="padding-top:0">
<h2 class="section-title reveal">高级功能速览</h2>
<p class="section-desc reveal">不仅仅是 Toast确认框、输入框、进度条、倒计时、队列、Action,应有尽有</p>
<div class="code-block reveal">
<div class="terminal">
<div class="terminal-bar">
<span class="t-dot"></span><span class="t-dot"></span><span class="t-dot"></span>
<span class="t-title">advanced.js</span>
</div>
<pre><span class="cm">// Promise 风格 — 自动 loading → success/error</span>
<span class="kw">await</span> MeToast.<span class="fn">promise</span>(<span class="fn">fetch</span>(<span class="s">'/api/data'</span>), {
<span class="fn">loading</span>: <span class="s">'加载中...'</span>,
<span class="fn">success</span>: <span class="s">'加载完成!'</span>,
<span class="fn">error</span>: <span class="s">'加载失败'</span>,
<span class="fn">loading</span>: <span class="s">'加载中...'</span>, <span class="fn">success</span>: <span class="s">'完成'</span>, <span class="fn">error</span>: <span class="s">'失败'</span>
});
<span class="cm">// 确认对话框 → Promise&lt;boolean&gt;</span>
<span class="kw">const</span> ok = <span class="kw">await</span> MeToast.<span class="fn">confirm</span>(<span class="s">'确定删除'</span>, { <span class="fn">confirmText</span>: <span class="s">'删除'</span> });
<span class="cm">// 输入对话框 → Promise&lt;string|null&gt;</span>
<span class="cm">// 确认 / 输入对话框</span>
<span class="kw">const</span> ok = <span class="kw">await</span> MeToast.<span class="fn">confirm</span>(<span class="s">'确定删除?'</span>, { <span class="fn">confirmText</span>: <span class="s">'删除'</span> });
<span class="kw">const</span> name = <span class="kw">await</span> MeToast.<span class="fn">prompt</span>(<span class="s">'请输入姓名'</span>);
<span class="cm">// Action Toast — 内嵌操作按钮</span>
MeToast.<span class="fn">action</span>(<span class="s">'文件已删除'</span>, [
{ <span class="fn">text</span>: <span class="s">'撤销'</span>, <span class="fn">onClick</span>: () => <span class="fn">restore</span>() },
{ <span class="fn">text</span>: <span class="s">'查看'</span>, <span class="fn">onClick</span>: () => <span class="fn">open</span>() },
{ <span class="fn">text</span>: <span class="s">'查看'</span>, <span class="fn">onClick</span>: () => <span class="fn">open</span>(), <span class="fn">close</span>: <span class="kw">false</span> },
]);
<span class="cm">// Toast 分组管理</span>
<span class="kw">const</span> orderGroup = MeToast.<span class="fn">group</span>(<span class="s">'orders'</span>);
orderGroup.<span class="fn">success</span>(<span class="s">'订单已创建'</span>);
orderGroup.<span class="fn">dismiss</span>(); <span class="cm">// 一键关闭整组</span></pre>
<span class="cm">// 加载 → 链式转换(id 稳定)</span>
<span class="kw">const</span> loading = MeToast.<span class="fn">loading</span>(<span class="s">'正在提交...'</span>);
<span class="fn">setTimeout</span>(() => loading.<span class="fn">success</span>(<span class="s">'提交成功!'</span>), <span class="num">2000</span>);</pre>
</div>
</div>
</section>
<section class="container">
<h2 class="section-title">主题切换</h2>
<p class="section-desc">点击按钮实时预览四种内置主题</p>
<div class="theme-demo">
<section class="container" style="padding-top:0">
<h2 class="section-title reveal">主题切换</h2>
<p class="section-desc reveal">点击按钮实时预览内置主题,切换结果自动持久化</p>
<div class="theme-demo reveal">
<button class="theme-btn" onclick="switchTheme('light')">☀️ 浅色 Light</button>
<button class="theme-btn" onclick="switchTheme('dark')">🌙 深色 Dark</button>
<button class="theme-btn" onclick="switchTheme('auto')">🔄 自动 Auto</button>
@@ -246,8 +417,34 @@ orderGroup.<span class="fn">dismiss</span>(); <span class="cm">// 一键关闭
</div>
</section>
<section class="container" style="padding-top:0">
<h2 class="section-title reveal">环境支持</h2>
<p class="section-desc reveal">所有现代浏览器原生支持,无需 polyfill</p>
<div class="env-grid reveal">
<div class="env-card"><div class="e-ico">🌐</div><h3>Chrome</h3><p>64+</p></div>
<div class="env-card"><div class="e-ico">🦊</div><h3>Firefox</h3><p>63+</p></div>
<div class="env-card"><div class="e-ico">🧭</div><h3>Safari</h3><p>11+</p></div>
<div class="env-card"><div class="e-ico">🪟</div><h3>Edge</h3><p>79+</p></div>
<div class="env-card"><div class="e-ico">📱</div><h3>iOS Safari</h3><p>11+</p></div>
<div class="env-card"><div class="e-ico">🤖</div><h3>Android</h3><p>64+</p></div>
<div class="env-card"><div class="e-ico">📦</div><h3>Node.js</h3><p>16+</p></div>
<div class="env-card"><div class="e-ico">📘</div><h3>TypeScript</h3><p>4.5+</p></div>
</div>
</section>
<section class="container" style="padding-top:0">
<div class="cta reveal">
<h2>开始使用 MetonaToast</h2>
<p>一条命令安装,立即体验精致优雅的 Toast 通知</p>
<button class="btn" onclick="location.href='demo.html'">🎮 打开在线演示</button>
</div>
</section>
<footer>
<p>MetonaToast v0.5.0 · MIT License · <a href="https://git.metona.cn/MetonaTeam/MetonaToast">Gitea</a></p>
MetonaToast v0.5.0 · MIT License ·
<a href="https://git.metona.cn/MetonaTeam/MetonaToast" target="_blank">Gitea</a> ·
<a href="docs.html">文档</a> ·
<a href="demo.html">演示</a>
</footer>
<script src="../dist/metona-toast.js"></script>
@@ -256,16 +453,28 @@ orderGroup.<span class="fn">dismiss</span>(); <span class="cm">// 一键关闭
function demoQuickStart() {
MeToast.success('✨ 欢迎使用 MetonaToast');
setTimeout(() => MeToast.info('💡 试试点击右上角的 Toast 来关闭'), 800);
setTimeout(() => MeToast.warning('⚠️ 你也可以拖动 Toast 关闭'), 1600);
setTimeout(() => MeToast.info('💡 点击 Toast 或点击 × 即可关闭'), 800);
setTimeout(() => MeToast.warning('⚠️ 拖动 Toast 也能关闭', { draggable: true }), 1600);
setTimeout(() => MeToast.success('🎭 试试 bounce 动画', { animation: 'bounce' }), 2400);
}
function switchTheme(t) {
MeToast.themes.switchTheme(t);
MeToast.configure({ theme: t });
document.querySelectorAll('.theme-btn').forEach(b => b.classList.remove('active'));
event.target.classList.add('active');
const names = { light: '浅色', dark: '深色', auto: '自动', warm: '暖色' };
MeToast.info('已切换到「' + names[t] + '」主题', { theme: t });
}
// 滚动淡入
const observer = new IntersectionObserver(entries => {
entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('visible'); observer.unobserve(e.target); } });
}, { threshold: 0.12 });
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
// 页面加载自动演示
setTimeout(demoQuickStart, 600);
</script>
</body>
</html>