feat(site): demo.html full-feature showcase — all v0.1.14 capabilities enabled

Demo now demonstrates:
- Syntax highlighting editor (toggle via 🎨 高亮 button)
- Line numbers with current line highlight
- Zen mode (🧘 button)
- Outline panel (📋 toggle)
- Word wrap toggle (↩ button)
- All 6 plugins: autoSave, exportTool, searchReplace, imagePaste, shortcutHelp, fileSystem
- Disk file open/save (📂 💾 buttons via File System Access API)
- Toast notifications (💬 button)
- Theme/locale switching
- Mode switching (edit/split/preview)
- Preview link interception (onLinkClick)
- Mermaid diagram example
- Mathematical formulas, footnotes, nested lists, task lists
- Custom shortcut Ctrl+Shift+T
- File open/save event listeners with toast feedback
This commit is contained in:
2026-07-24 17:33:31 +08:00
parent 2ab4c8d499
commit 9728fb7b6e
+210 -464
View File
@@ -4,196 +4,42 @@
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📝</text></svg>"/>
<title>MetonaEditor v0.1.14 — 在线演示</title>
<title>MetonaEditor v0.1.14 — 全功能演示</title>
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root {
--app-bg: #f5f6f8;
--app-text: #1a1a2e;
--app-card: #ffffff;
--app-border: #e5e7eb;
--app-accent: #3b82f6;
--app-accent2: #8b5cf6;
/* dark overrides */
--header-bg: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
--header-text: #f1f5f9;
--badge-bg: rgba(255,255,255,0.12);
--badge-text: #e2e8f0;
}
[data-md-theme="dark"] {
--app-bg: #0f1117;
--app-text: #e2e8f0;
--app-card: #1a1d27;
--app-border: #2d3140;
--header-bg: linear-gradient(135deg, #0a0d15 0%, #161923 100%);
}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
:root{--app-bg:#f5f6f8;--app-text:#1a1a2e;--app-card:#fff;--app-border:#e5e7eb;--app-accent:#3b82f6;--app-accent2:#8b5cf6;--header-bg:linear-gradient(135deg,#1e293b 0%,#0f172a 100%);--header-text:#f1f5f9;--badge-bg:rgba(255,255,255,.12);--badge-text:#e2e8f0}
[data-md-theme=dark]{--app-bg:#0f1117;--app-text:#e2e8f0;--app-card:#1a1d27;--app-border:#2d3140;--header-bg:linear-gradient(135deg,#0a0d15 0%,#161923 100%)}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;background:var(--app-bg);color:var(--app-text);min-height:100vh;line-height:1.6;transition:background .3s,color .3s}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
background: var(--app-bg);
color: var(--app-text);
min-height: 100vh;
line-height: 1.6;
transition: background 0.3s, color 0.3s;
}
.header{background:var(--header-bg);color:var(--header-text);padding:28px 24px 20px;text-align:center;position:relative;overflow:hidden}
.header::before{content:'';position:absolute;top:-60px;right:-60px;width:300px;height:300px;background:radial-gradient(circle,rgba(139,92,246,.3) 0%,transparent 70%);border-radius:50%}
.header h1{font-size:1.85rem;font-weight:800;letter-spacing:-.5px;position:relative}
.header h1 span.grad{background:linear-gradient(135deg,var(--app-accent),var(--app-accent2));-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.header .badges{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:12px;position:relative}
.header .badge{padding:4px 12px;border-radius:20px;font-size:13px;font-weight:500;background:var(--badge-bg);color:var(--badge-text);border:1px solid rgba(255,255,255,.1)}
/* ====== Header ====== */
.header {
background: var(--header-bg);
color: var(--header-text);
padding: 32px 24px 24px;
text-align: center;
position: relative;
overflow: hidden;
}
.header::before {
content: '';
position: absolute;
top: -60px; right: -60px;
width: 300px; height: 300px;
background: radial-gradient(circle, rgba(139,92,246,0.3) 0%, transparent 70%);
border-radius: 50%;
}
.header h1 {
font-size: 2rem;
font-weight: 800;
letter-spacing: -0.5px;
position: relative;
}
.header h1 span.grad {
background: linear-gradient(135deg, var(--app-accent), var(--app-accent2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.header .badges {
display: flex;
gap: 10px;
justify-content: center;
flex-wrap: wrap;
margin-top: 14px;
position: relative;
}
.header .badge {
padding: 4px 12px;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
background: var(--badge-bg);
color: var(--badge-text);
border: 1px solid rgba(255,255,255,0.1);
}
.toolbar-strip{display:flex;align-items:center;gap:8px;padding:8px 20px;background:var(--app-card);border-bottom:1px solid var(--app-border);flex-wrap:wrap;position:sticky;top:0;z-index:50;transition:background .3s}
.toolbar-strip label{font-size:12px;font-weight:500;color:var(--app-text);opacity:.7;white-space:nowrap}
.toolbar-strip select{padding:4px 8px;border:1px solid var(--app-border);border-radius:6px;font-size:12px;background:var(--app-bg);color:var(--app-text);cursor:pointer}
.toolbar-strip button{padding:5px 12px;border:1px solid var(--app-border);border-radius:6px;font-size:12px;font-weight:500;background:var(--app-card);color:var(--app-text);cursor:pointer;transition:all .15s;white-space:nowrap}
.toolbar-strip button:hover{background:var(--app-accent);color:#fff;border-color:var(--app-accent)}
.toolbar-strip button.accent{background:var(--app-accent);color:#fff;border-color:var(--app-accent)}
.toolbar-strip button.on{background:var(--app-accent);color:#fff;border-color:var(--app-accent)}
.toolbar-strip .spacer{flex:1}
/* ====== Toolbar Strip ====== */
.toolbar-strip {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 24px;
background: var(--app-card);
border-bottom: 1px solid var(--app-border);
flex-wrap: wrap;
position: sticky;
top: 0;
z-index: 50;
transition: background 0.3s;
}
.toolbar-strip label {
font-size: 13px;
font-weight: 500;
color: var(--app-text);
opacity: 0.7;
white-space: nowrap;
}
.toolbar-strip select {
padding: 5px 10px;
border: 1px solid var(--app-border);
border-radius: 6px;
font-size: 13px;
background: var(--app-bg);
color: var(--app-text);
cursor: pointer;
}
.toolbar-strip button {
padding: 6px 14px;
border: 1px solid var(--app-border);
border-radius: 6px;
font-size: 13px;
font-weight: 500;
background: var(--app-card);
color: var(--app-text);
cursor: pointer;
transition: all 0.15s;
white-space: nowrap;
}
.toolbar-strip button:hover { background: var(--app-accent); color: #fff; border-color: var(--app-accent); }
.toolbar-strip button.accent { background: var(--app-accent); color: #fff; border-color: var(--app-accent); }
.toolbar-strip .spacer { flex: 1; }
.editor-section{max-width:1280px;margin:20px auto;padding:0 20px}
.editor-card{border-radius:12px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,.06);background:var(--app-card);border:1px solid var(--app-border);transition:.3s}
.editor-card:hover{box-shadow:0 8px 36px rgba(0,0,0,.1)}
.toggle-group { display: flex; gap: 2px; }
.toggle-group button {
border-radius: 0;
margin: 0;
}
.toggle-group button:first-child { border-radius: 6px 0 0 6px; }
.toggle-group button:last-child { border-radius: 0 6px 6px 0; }
.toggle-group button.on { background: var(--app-accent); color: #fff; border-color: var(--app-accent); }
/* ====== Editor Container ====== */
.editor-section {
max-width: 1200px;
margin: 24px auto;
padding: 0 24px;
}
.editor-card {
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 24px rgba(0,0,0,0.06);
background: var(--app-card);
border: 1px solid var(--app-border);
transition: box-shadow 0.3s, background 0.3s;
}
.editor-card:hover { box-shadow: 0 8px 36px rgba(0,0,0,0.1); }
/* ====== Info Cards ====== */
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
max-width: 1200px;
margin: 24px auto;
padding: 0 24px;
}
.info-card {
background: var(--app-card);
border: 1px solid var(--app-border);
border-radius: 10px;
padding: 18px 20px;
transition: box-shadow 0.3s;
}
.info-card:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
.info-card .icon { font-size: 24px; margin-bottom: 8px; }
.info-card h4 { font-size: 14px; font-weight: 650; margin-bottom: 4px; }
.info-card p { font-size: 12px; color: var(--app-text); opacity: 0.65; margin: 0; }
/* ====== Footer ====== */
.footer {
text-align: center;
padding: 32px 24px;
font-size: 13px;
color: var(--app-text);
opacity: 0.5;
}
.footer a { color: var(--app-accent); text-decoration: none; }
/* ====== Responsive ====== */
@media (max-width: 768px) {
.header h1 { font-size: 1.5rem; }
.toolbar-strip { padding: 8px 12px; gap: 6px; }
.toolbar-strip button { padding: 5px 10px; font-size: 12px; }
.info-grid { grid-template-columns: 1fr 1fr; }
}
.info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px;max-width:1280px;margin:20px auto;padding:0 20px}
.info-card{background:var(--app-card);border:1px solid var(--app-border);border-radius:10px;padding:16px 18px;transition:.3s}
.info-card:hover{box-shadow:0 4px 16px rgba(0,0,0,.08)}
.info-card .icon{font-size:22px;margin-bottom:6px}
.info-card h4{font-size:13px;font-weight:650;margin-bottom:3px}
.info-card p{font-size:12px;color:var(--app-text);opacity:.65;margin:0}
.footer{text-align:center;padding:28px 24px;font-size:13px;color:var(--app-text);opacity:.5}
.footer a{color:var(--app-accent);text-decoration:none}
@media(max-width:768px){.header h1{font-size:1.4rem}.toolbar-strip{padding:6px 10px;gap:4px}.toolbar-strip button{padding:4px 8px;font-size:11px}.info-grid{grid-template-columns:1fr 1fr}}
</style>
</head>
<body>
@@ -203,318 +49,218 @@
<div class="badges">
<span class="badge">v0.1.14</span>
<span class="badge">零依赖</span>
<span class="badge">532 tests</span>
<span class="badge">MIT</span>
<span class="badge">535 tests</span>
<span class="badge">6 插件</span>
<span class="badge">中文优先</span>
</div>
</header>
<div class="toolbar-strip" id="controlBar">
<a href="index.html" style="text-decoration:none;font-size:18px;margin-right:8px;" title="返回首页">🏠</a>
<div class="toolbar-strip" id="bar">
<a href="index.html" style="text-decoration:none;font-size:18px;margin-right:4px" title="首页">🏠</a>
<label>主题</label>
<select id="themeSelect">
<option value="auto">🌓 跟随系统</option>
<option value="light">☀️ 亮色</option>
<option value="dark">🌙 暗色</option>
<option value="warm">🔥 暖色</option>
</select>
<select id="selTheme"><option value="auto">🌓 跟随系统</option><option value="light">☀️ 亮色</option><option value="dark">🌙 暗色</option><option value="warm">🔥 暖色</option></select>
<label>语言</label>
<select id="localeSelect">
<option value="zh-CN">中文</option>
<option value="en-US">English</option>
</select>
<select id="selLocale"><option value="zh-CN">中文</option><option value="en-US">English</option></select>
<label>模式</label>
<div class="toggle-group" id="modeBtns">
<button data-mode="edit">编辑</button>
<button data-mode="split" class="on">分屏</button>
<button data-mode="preview">预览</button>
</div>
<button data-cmd="mode" data-arg="edit">编辑</button>
<button data-cmd="mode" data-arg="split" class="on">分屏</button>
<button data-cmd="mode" data-arg="preview">预览</button>
<div class="spacer"></div>
<label>行号</label>
<div class="toggle-group" id="lineNumBtns">
<button class="on"></button>
<button></button>
</div>
<label>大纲</label>
<div class="toggle-group" id="outlineBtns">
<button></button>
<button class="on"></button>
</div>
<button onclick="demoToast()" title="演示 Toast 通知">💬 Toast</button>
<button onclick="demoOutline()" title="生成大纲">📋 大纲</button>
<button data-cmd="zen" title="Zen 专注模式">🧘 Zen</button>
<button data-cmd="outline" title="切换大纲面板">📋 大纲</button>
<button data-cmd="highlight" title="切换语法高亮">🎨 高亮</button>
<button data-cmd="wrap" title="切换自动换行">↩ 换行</button>
<button data-cmd="toast" title="Toast 通知演示">💬 Toast</button>
<button data-cmd="openFile" title="打开磁盘文件">📂 打开</button>
<button data-cmd="saveFile" title="保存到磁盘">💾 保存</button>
</div>
<div class="editor-section">
<div class="editor-card">
<div id="editor"></div>
</div>
<div class="editor-card"><div id="editor"></div></div>
</div>
<div class="info-grid">
<div class="info-card">
<div class="icon">📝</div>
<h4>丰富语法</h4>
<p>数学公式、脚注、定义列表、嵌套列表、表格对齐、任务列表、Emoji</p>
</div>
<div class="info-card">
<div class="icon">⌨️</div>
<h4>快捷键</h4>
<p>Ctrl+B 粗体 · Ctrl+I 斜体 · Ctrl+S 保存 · Ctrl+F 搜索 · Ctrl+H 替换</p>
</div>
<div class="info-card">
<div class="icon">🎨</div>
<h4>4 套主题</h4>
<p>亮色 · 暗色 · 暖色 · 跟随系统,实例级隔离,外部主题跟随</p>
</div>
<div class="info-card">
<div class="icon">🔌</div>
<h4>4 个插件</h4>
<p>自动保存草稿 · 导出 MD/HTML · 搜索替换 · 图片粘贴</p>
</div>
<div class="info-card">
<div class="icon">🧩</div>
<h4>编辑增强</h4>
<p>行号装订线 · 智能 Enter · 括号自动闭合 · 拖放文件 · 大纲面板</p>
</div>
<div class="info-card">
<div class="icon">🛡️</div>
<h4>安全</h4>
<p>XSS 防护 · URL 协议过滤 · HTML 实体保护 · sanitize 钩子</p>
</div>
<div class="info-card"><div class="icon">🎨</div><h4>语法高亮编辑区</h4><p>标题/粗体/斜体/代码/链接/图片/列表等 10 种语法实时着色</p></div>
<div class="info-card"><div class="icon">📂</div><h4>磁盘文件读写</h4><p>File System Access API 打开/保存真实磁盘 .md 文件</p></div>
<div class="info-card"><div class="icon">🔢</div><h4>行号装订线</h4><p>当前行高亮,与编辑区滚动同步</p></div>
<div class="info-card"><div class="icon">🧘</div><h4>Zen 专注模式</h4><p>工具栏自动隐藏,鼠标移到顶部滑入</p></div>
<div class="info-card"><div class="icon">⌨️</div><h4>快捷键面板</h4><p>按 ? 查看全部快捷键,Ctrl+F/H 搜索替换</p></div>
<div class="info-card"><div class="icon">📊</div><h4>Mermaid 图表</h4><p>```mermaid 代码块,加载 Mermaid.js 即可渲染</p></div>
<div class="info-card"><div class="icon">🔌</div><h4>6 个预设插件</h4><p>autoSave / exportTool / searchReplace / imagePaste / shortcutHelp / fileSystem</p></div>
<div class="info-card"><div class="icon">🛡️</div><h4>XSS 安全防护</h4><p>HTML 转义 · URL 协议过滤 · sanitize 钩子</p></div>
</div>
<footer class="footer">
MetonaEditor v0.1.14 ·
<a href="index.html">首页</a> ·
<a href="docs.html">API 文档</a> ·
<a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> ·
MIT License
<a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> · MIT
</footer>
<script src="../dist/metona-editor.js"></script>
<script>
(function () {
const demoMd = [
'# 🚀 MetonaEditor 演示',
'',
'> 轻量、零依赖、精致美观的 **Markdown Editor** 库。',
'> 单文件,开箱即用,中文优先。',
'',
'## ✨ 核心特性',
'',
'- 零依赖 · 单文件打包 · UMD / ESM / CJS',
'- 三模式视图 · 分屏拖拽 · 滚动同步',
'- 行号装订线 · 当前行高亮',
'- 智能 Enter · 括号自动闭合',
'- 4 套主题 · 实例级隔离 · 外部跟随',
'- 插件系统 v2 · 依赖排序 · 异步加载',
'',
'## 📐 数学公式',
'',
'行内公式:爱因斯坦质能方程 $E = mc^2$',
'',
'块级公式:',
'$$',
'\\int_{0}^{\\infty} e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}',
'$$',
'',
'## 📋 表格与对齐',
'',
'| 版本 | 日期 | 测试数 |',
'| :--- | :---: | ---: |',
'| v0.1.14 | 2026-07 | 532+ |',
'| v0.1.6 | 2026-07 | 521 |',
'| v0.1.5 | 2026-07 | 499 |',
'',
'## ✅ 任务列表',
'',
'- [x] 解析器增强(11 项新语法)',
'- [x] 主题系统(实例隔离 + 外部跟随)',
'- [x] 插件 v2 + i18n 增强',
'- [x] 编辑体验(行号 / 自动格式化 / 括号闭合)',
'- [ ] 更多语言翻译包',
'- [ ] VS Code 插件',
'',
'## 🎯 嵌套列表',
'',
'1. 一级有序',
' 1. 二级有序',
' 2. 二级第二项',
'2. 回到一级',
' - 混杂无序',
' - 第二项',
' - 三级嵌套',
'',
'## 📖 定义列表',
'',
'MetonaEditor',
': 一款轻量、零依赖的中文优先 Markdown 编辑器库。',
': 支持 CommonMark + GFM 扩展语法。',
'',
'Markdown',
': 由 John Gruber 创建的轻量级标记语言。',
'',
'## 🔗 链接与图片',
'',
'访问 [MetonaEditor 仓库](https://git.metona.cn/MetonaTeam/MetonaEditor \'点击访问源码\')',
'',
'图片示例:![示例](https://placehold.co/400x120/3b82f6/white?text=MetonaEditor)',
'',
'## 💻 代码块',
'',
'```js',
'import MeEditor from \'@metona-team/metona-editor\';',
'',
'const editor = MeEditor.create(\'#editor\', {',
' value: \'# Hello World\',',
' mode: \'split\',',
' lineNumbers: true,',
' autoBrackets: true,',
' plugins: [\'autoSave\', \'searchReplace\'],',
' onChange: (value) => console.log(value),',
'});',
'```',
'',
'## 🎨 文本样式',
'',
'- **粗体文本** 与 __另一种粗体__',
'- *斜体文本* 与 _另一种斜体_',
'- ~~删除线~~ 与 ==高亮标记==',
'- 化学式:H~2~O 与 数学:x^2^ + y^2^ = z^2^',
'- 行内代码:`const x = 42;`',
'- Emoji:smile: :rocket: :fire: :tada: :rainbow: :coffee:',
'',
'## 📌 脚注',
'',
'这是一个带脚注的句子[^1],这是另一个脚注[^note]。',
'',
'[^1]: 第一个脚注的详细说明内容。',
'[^note]: 脚注可以包含 **格式化** 和 `代码`。',
'',
'---',
'',
'> **提示:** 试试拖放图片到编辑器、按 `Ctrl+F` 搜索、`Ctrl+H` 替换、',
'> 在列表行尾按 `Enter` 体验智能延续、选中文字后输入 `(` 体验自动包裹。',
].join('\n');
(function(){
var demoMd=[
'# 🚀 MetonaEditor 全功能演示',
'',
'> 轻量、零依赖、中文优先的 **Markdown Editor** 库。',
'> 单文件打包,开箱即用。所有功能均在此页面启用。',
'',
'## ✨ 核心特性',
'',
'- 语法高亮编辑区(源码实时着色)',
'- 行号装订线 + 当前行高亮',
'- 智能 Enter(列表/引用自动延续)',
'- 括号/引号自动闭合',
'- 拖放图片/文件到编辑区',
'- Zen 专注模式 + 大纲面板',
'- 磁盘文件读写(File System Access API',
'- 6 个预设插件开箱即用',
'',
'## 📐 数学公式',
'',
'行内:$E = mc^2$',
'块级:$$\\int_{0}^{\\infty} e^{-x^2} dx = \\frac{\\sqrt{\\pi}}{2}$$',
'',
'## 📊 Mermaid 图表(需加载 Mermaid.js',
'',
'```mermaid',
'graph TD',
' A[Markdown] --> B[解析器]',
' B --> C[HTML]',
' C --> D[预览]',
'```',
'',
'## 📋 表格与对齐',
'',
'| 版本 | 日期 | 测试 | 主题 |',
'| :--- | :---: | ---: | --- |',
'| v0.1.14 | 2026-07 | 535+ | 语法高亮+Mermaid+文件系统 |',
'| v0.1.12 | 2026-07 | 535 | A11y+Zen+滚动同步 |',
'| v0.1.7 | 2026-07 | 532 | 编辑体验 |',
'',
'## ✅ 任务列表',
'',
'- [x] 解析器增强(数学公式/脚注/嵌套列表等)',
'- [x] 主题系统(实例隔离 + 外部跟随)',
'- [x] 插件 v2 + i18n 增强',
'- [x] 编辑体验(行号/自动格式化/括号闭合)',
'- [x] 语法高亮 + 文件系统 + Mermaid',
'- [ ] vs-code 插件',
'',
'## 🎯 嵌套列表',
'',
'1. 一级有序',
' 1. 二级有序(自动递增)',
' 2. 第二项',
'2. 回到一级',
' - 混杂无序列表',
' - 第二项',
' - [x] 三级嵌套 + 任务',
'',
'## 💻 代码块',
'',
'```js',
'import MeEditor from "@metona-team/metona-editor";',
'const editor = MeEditor.create("#editor", {',
' mode: "split",',
' syntaxHighlight: true,',
' lineNumbers: true,',
' autoBrackets: true,',
' plugins: ["autoSave","fileSystem","shortcutHelp"],',
'});',
'```',
'',
'## 🎨 文本样式',
'',
'- **粗体** / __另一种粗体__',
'- *斜体* / _另一种斜体_',
'- ~~删除线~~ / ==高亮标记==',
'- 化学:H~2~O / 数学:x^2^',
'- 代码:`const x = 42;`',
'- Emoji:smile: :rocket: :fire: :rainbow: :coffee: :hamburger:',
'',
'## 📌 脚注',
'',
'这是一个带脚注的句子[^1],另一个脚注[^note]。',
'',
'[^1]: 脚注可以包含 **格式化** 和 `代码`。',
'[^note]: 第二个脚注的说明。',
'',
'---',
'',
'> **提示:** 按 `?` 查看快捷键 · 拖放图片到编辑区 · Ctrl+F 搜索 · Ctrl+H 替换',
'> 在列表行尾 Enter 体验智能延续 · 选中文字后按 `(` 体验自动包裹',
'> 点击「打开」按钮加载磁盘 .md 文件 · 点击「保存」写入磁盘',
].join('\n');
const editor = window.MeEditor.create('#editor', {
value: demoMd,
mode: 'split',
height: 620,
lineNumbers: true,
autoBrackets: true,
wordCount: true,
outline: false,
theme: 'auto',
locale: 'zh-CN',
plugins: ['autoSave', 'exportTool', 'searchReplace', 'imagePaste'],
});
var editor=MeEditor.create('#editor',{
value:demoMd,
mode:'split',height:620,
lineNumbers:true,autoBrackets:true,wordCount:true,
syntaxHighlight:true,
theme:'auto',locale:'zh-CN',
outline:false,
plugins:['autoSave','exportTool','searchReplace','imagePaste','shortcutHelp','fileSystem'],
onLinkClick:function(uri,text,ed){
ed.toast('链接: '+uri,{type:'info',duration:2000});
}
});
// ====== Control Bar Handlers ======
// ===== 控制栏按钮 =====
var bar=document.getElementById('bar');
// Theme
document.getElementById('themeSelect').addEventListener('change', function () {
editor.setTheme(this.value);
});
// 主题
document.getElementById('selTheme').addEventListener('change',function(){
editor.setTheme(this.value);
});
// Locale
document.getElementById('localeSelect').addEventListener('change', function () {
editor.setLocale(this.value);
});
// 语言
document.getElementById('selLocale').addEventListener('change',function(){
editor.setLocale(this.value);
});
// Mode buttons
document.querySelectorAll('#modeBtns button').forEach(function (btn) {
btn.addEventListener('click', function () {
editor.setMode(this.dataset.mode);
document.querySelectorAll('#modeBtns button').forEach(function (b) { b.classList.remove('on'); });
this.classList.add('on');
});
});
// 通用按钮
bar.addEventListener('click',function(e){
var btn=e.target.closest('button[data-cmd]');
if(!btn)return;
var cmd=btn.dataset.cmd;
if(cmd==='mode'){editor.setMode(btn.dataset.arg);updateModeBtns(btn.dataset.arg);}
else if(cmd==='zen'){editor.toggleZen();btn.classList.toggle('on',editor.isZen());}
else if(cmd==='outline'){toggleOutline(btn);}
else if(cmd==='highlight'){editor.toggleSyntaxHighlight();btn.classList.toggle('on',editor.config.syntaxHighlight);}
else if(cmd==='wrap'){editor.toggleWordWrap();btn.classList.toggle('on',!editor.isWordWrap());}
else if(cmd==='toast'){
var types=['success','error','warning','info'];
var msgs={success:'✅ 操作成功',error:'❌ 操作失败',warning:'⚠️ 注意',info:'️ 提示信息'};
var t=types[Math.floor(Math.random()*4)];
editor.toast(msgs[t],{type:t,duration:2000});
}
else if(cmd==='openFile'){editor.openFile?.();}
else if(cmd==='saveFile'){editor.saveFile?.();}
});
// Line numbers toggle
var lineNumBtns = document.querySelectorAll('#lineNumBtns button');
lineNumBtns[0].addEventListener('click', function () {
editor.config.lineNumbers = true;
if (editor.gutter) editor.gutter.style.display = '';
editor._renderGutter();
lineNumBtns[0].classList.add('on');
lineNumBtns[1].classList.remove('on');
});
lineNumBtns[1].addEventListener('click', function () {
editor.config.lineNumbers = false;
if (editor.gutter) editor.gutter.style.display = 'none';
lineNumBtns[1].classList.add('on');
lineNumBtns[0].classList.remove('on');
});
function updateModeBtns(mode){
bar.querySelectorAll('[data-cmd=mode]').forEach(function(b){b.classList.toggle('on',b.dataset.arg===mode)});
}
// Outline toggle
var outlineBtns = document.querySelectorAll('#outlineBtns button');
outlineBtns[0].addEventListener('click', function () {
editor.config.outline = true;
editor._buildOutline();
outlineBtns[0].classList.add('on');
outlineBtns[1].classList.remove('on');
});
outlineBtns[1].addEventListener('click', function () {
editor.config.outline = false;
var panel = editor.el.querySelector('.me-outline');
if (panel) panel.remove();
outlineBtns[1].classList.add('on');
outlineBtns[0].classList.remove('on');
});
function toggleOutline(btn){
editor.config.outline=!editor.config.outline;
if(editor.config.outline){editor._buildOutline();btn.classList.add('on')}
else{var p=editor.el.querySelector('.me-outline');if(p)p.remove();btn.classList.remove('on')}
}
// Toast demo
window.demoToast = function () {
var types = ['success', 'error', 'warning', 'info'];
var type = types[Math.floor(Math.random() * types.length)];
var messages = {
success: '✅ 内容已自动保存',
error: '❌ 操作失败,请重试',
warning: '⚠️ 有未保存的更改',
info: 'ℹ️ 这是来自插件系统的通知',
};
editor.toast(messages[type], { type: type, duration: 2500 });
};
// 快捷键
editor.registerShortcut('Ctrl+Shift+T',function(){
editor.toast('自定义快捷键已触发!',{type:'info'});
},'Toast 通知演示');
// Outline demo
window.demoOutline = function () {
if (editor.config.outline) {
editor.config.outline = false;
var panel = editor.el.querySelector('.me-outline');
if (panel) panel.remove();
outlineBtns[0].classList.remove('on');
outlineBtns[1].classList.add('on');
} else {
editor.config.outline = true;
editor._buildOutline();
outlineBtns[0].classList.add('on');
outlineBtns[1].classList.remove('on');
}
};
// Register custom shortcut
editor.registerShortcut('Ctrl+Shift+T', function () {
editor.toast('快捷键 Ctrl+Shift+T 已触发!', { type: 'info' });
}, 'Toast test');
// Listen for theme change to update select
editor.on('themeChange', function (data) {
document.getElementById('themeSelect').value = data.theme;
});
// Sync editor mode button state
editor.on('modeChange', function (mode) {
document.querySelectorAll('#modeBtns button').forEach(function (b) {
b.classList.toggle('on', b.dataset.mode === mode);
});
});
// 事件监听
editor.on('themeChange',function(d){document.getElementById('selTheme').value=d.theme});
editor.on('modeChange',function(m){updateModeBtns(m)});
editor.on('fileOpened',function(d){editor.toast('已打开: '+d.name,{type:'success'})});
editor.on('fileSaved',function(){editor.toast('文件已保存',{type:'success'})});
editor.on('linkClick',function(d){editor.toast('链接点击: '+d.href,{type:'info',duration:1500})});
})();
</script>