Files
MetonaEditor/site/demo.html
T
thzxx c6db68af59 revert: remove syntax highlighting feature entirely
Syntax highlighting overlay approach proved too fragile:
- pixel alignment between textarea and overlay unreliable
- transparent textarea caused invisible content bugs
- dynamic gutter width positioning added complexity

Removed:
- _highlightEditor, _doHighlight, toggleSyntaxHighlight, _positionHighlightLayer
- highlightLayer DOM element creation
- .me-highlight-layer, .mh-*, .me-textarea-highlight CSS
- syntaxHighlight config option from DEFAULTS
- highlight toggle button from demo.html

Kept: Mermaid, fileSystem, preview links, all other v0.1.14 features
2026-07-24 18:10:27 +08:00

276 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN" data-md-theme="auto">
<head>
<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>
<style>
*,*::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}
.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)}
.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}
.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)}
.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>
<header class="header">
<h1><span class="grad">Metona</span>Editor</h1>
<div class="badges">
<span class="badge">v0.1.14</span>
<span class="badge">零依赖</span>
<span class="badge">535 tests</span>
<span class="badge">6 插件</span>
<span class="badge">中文优先</span>
</div>
</header>
<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="selTheme"><option value="auto">🌓 跟随系统</option><option value="light">☀️ 亮色</option><option value="dark">🌙 暗色</option><option value="warm">🔥 暖色</option></select>
<label>语言</label>
<select id="selLocale"><option value="zh-CN">中文</option><option value="en-US">English</option></select>
<label>模式</label>
<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>
<button data-cmd="zen" title="Zen 专注模式">🧘 Zen</button>
<button data-cmd="outline" 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>
<div class="info-grid">
<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
</footer>
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script src="../dist/metona-editor.js"></script>
<script>
(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');
var editor=MeEditor.create('#editor',{
value:demoMd,
mode:'split',height:620,
lineNumbers:true,autoBrackets:true,wordCount: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});
}
});
// ===== 控制栏按钮 =====
var bar=document.getElementById('bar');
// 主题
document.getElementById('selTheme').addEventListener('change',function(){
editor.setTheme(this.value);
});
// 语言
document.getElementById('selLocale').addEventListener('change',function(){
editor.setLocale(this.value);
});
// 通用按钮
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==='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?.();}
});
function updateModeBtns(mode){
bar.querySelectorAll('[data-cmd=mode]').forEach(function(b){b.classList.toggle('on',b.dataset.arg===mode)});
}
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')}
}
// 快捷键
editor.registerShortcut('Ctrl+Shift+T',function(){
editor.toast('自定义快捷键已触发!',{type:'info'});
},'Toast 通知演示');
// 事件监听
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})});
// Mermaid 图表渲染(v0.1.14
function renderMermaid(){
if(typeof mermaid==='undefined')return;
try{mermaid.run({querySelector:'.me-mermaid .mermaid'})}catch(e){}
}
mermaid.initialize({startOnLoad:false,theme:'default'});
editor.on('afterRender',renderMermaid);
setTimeout(renderMermaid,300);
})();
</script>
</body>
</html>