Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bbbb7ff70 | ||
|
|
1dd22be0a8 | ||
|
|
20b6d03617 |
@@ -1,8 +1,8 @@
|
||||
# MarkLite v0.4.1 — 架构设计文档
|
||||
# MarkLite v0.4.3 — 架构设计文档
|
||||
|
||||
## 1. 项目概述
|
||||
|
||||
MarkLite 是一款轻量级的 Windows 本地 Markdown 编辑器桌面应用程序。基于 Electron + React + TypeScript 构建,采用 MetonaEditor v0.1.3 编辑器(三模式视图 + 插件系统)、Zustand 状态管理、IndexedDB 持久化、unified/rehype Markdown 渲染管线。
|
||||
MarkLite 是一款轻量级的 Windows 本地 Markdown 编辑器桌面应用程序。基于 Electron + React + TypeScript 构建,采用 MetonaEditor v0.1.14 编辑器(三模式视图 + 插件系统)、Zustand 状态管理、IndexedDB 持久化、unified/rehype Markdown 渲染管线。
|
||||
|
||||
### 1.1 核心原则
|
||||
|
||||
@@ -20,7 +20,7 @@ MarkLite 是一款轻量级的 Windows 本地 Markdown 编辑器桌面应用程
|
||||
| 桌面框架 | Electron | v28 | 跨平台桌面应用框架 |
|
||||
| 前端框架 | React | v18 | 函数组件 + Hooks |
|
||||
| 类型系统 | TypeScript | v5.6 | 全量类型安全 |
|
||||
| 编辑器 | MetonaEditor | v0.1.3 | 零依赖 Markdown 编辑器,三模式视图 + 插件系统 |
|
||||
| 编辑器 | MetonaEditor | v0.1.14 | 零依赖 Markdown 编辑器,三模式视图 + 插件系统 |
|
||||
| 状态管理 | Zustand | v5 | 轻量级状态管理 |
|
||||
| 持久化 | Dexie.js (IndexedDB) | v4 | 标签页状态 / 用户设置 / 最近文件 |
|
||||
| Markdown 解析 | unified / remark / rehype | v11 | 插件化渲染管线(作为 MetonaEditor render 钩子) |
|
||||
@@ -218,7 +218,7 @@ db.version(1).stores({
|
||||
| `window:confirmClose` | 无 | 请求确认关闭 |
|
||||
| `sidebar:dirChanged` | 无 | 目录结构变化 |
|
||||
|
||||
## 6. 编辑器架构 — MetonaEditor v0.1.3
|
||||
## 6. 编辑器架构 — MetonaEditor v0.1.14
|
||||
|
||||
### 6.1 三模式视图
|
||||
|
||||
@@ -404,7 +404,7 @@ npm run build:portable # 便携版(免安装)
|
||||
| zustand | ^5.0 | 状态管理 |
|
||||
| dexie | ^4.0 | IndexedDB 封装 |
|
||||
| nanoid | ^5.0 | 唯一 ID 生成 |
|
||||
| @metona-team/metona-editor | ^0.1.3 | Markdown 编辑器(零依赖) |
|
||||
| @metona-team/metona-editor | 0.1.14 | Markdown 编辑器(零依赖) |
|
||||
| @metona-team/metona-toast | ^2.0.1 | Toast 通知组件 |
|
||||
| unified / remark / rehype | ^11.0 | Markdown 渲染管线 |
|
||||
| rehype-highlight | ^7.0 | 代码语法高亮 |
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# MarkLite v0.4.1 — 开发环境配置指南
|
||||
# MarkLite v0.4.3 — 开发环境配置指南
|
||||
|
||||
以下涵盖从 Node 版本管理、镜像源配置到 electron-builder 打包的全流程。
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<img src="https://img.shields.io/badge/TypeScript-5.6-3178C6?style=flat-square&logo=typescript" alt="TypeScript">
|
||||
<img src="https://img.shields.io/badge/React-18-61DAFB?style=flat-square&logo=react" alt="React">
|
||||
<img src="https://img.shields.io/badge/License-MIT-green?style=flat-square" alt="License">
|
||||
<img src="https://img.shields.io/badge/Version-v0.4.1-orange?style=flat-square" alt="Version">
|
||||
<img src="https://img.shields.io/badge/Version-v0.4.3-orange?style=flat-square" alt="Version">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -143,7 +143,7 @@ npm run test:coverage
|
||||
| 桌面框架 | [Electron](https://www.electronjs.org/) v28 | 跨平台桌面应用框架 |
|
||||
| 前端框架 | [React](https://react.dev/) v18 | 函数组件 + Hooks |
|
||||
| 类型系统 | [TypeScript](https://www.typescriptlang.org/) v5.6 | 全量类型安全 |
|
||||
| 编辑器 | [MetonaEditor](https://git.metona.cn/MetonaTeam/MetonaEditor) v0.1.3 | 零依赖 Markdown 编辑器,三模式视图 + 插件系统 |
|
||||
| 编辑器 | [MetonaEditor](https://git.metona.cn/MetonaTeam/MetonaEditor) v0.1.14 | 零依赖 Markdown 编辑器,三模式视图 + 插件系统 |
|
||||
| 状态管理 | [Zustand](https://zustand-demo.pmnd.rs/) v5 | 轻量级状态管理 |
|
||||
| 持久化 | [Dexie.js](https://dexie.org/) v4 (IndexedDB) | 标签页状态 & 用户设置持久化 |
|
||||
| Markdown 解析 | [unified](https://unifiedjs.com/) / [remark](https://remark.js.org/) / [rehype](https://rehype.js.org/) | 插件化 Markdown 渲染管线 |
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
|
||||
<!-- 6. Action Toast -->
|
||||
<div class="card">
|
||||
<div class="label">⚡ Action Toast <span style="color:#34d399;font-size:10px;">v2.0</span></div>
|
||||
<div class="label">⚡ Action Toast</div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-e" onclick="demoActionDelete()">删除+撤销</button>
|
||||
<button class="btn c-i" onclick="demoActionMulti()">多按钮</button>
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<!-- 7. 分组管理 -->
|
||||
<div class="card">
|
||||
<div class="label">📁 分组管理 <span style="color:#34d399;font-size:10px;">v2.0</span></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>
|
||||
@@ -209,9 +209,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 12. v2.0 新功能 -->
|
||||
<!-- 12. 高级特性 -->
|
||||
<div class="card">
|
||||
<div class="label">🆕 v2.0 新功能 <span style="color:#34d399;font-size:10px;">resetTimer · onUpdate · render · notify</span></div>
|
||||
<div class="label">🔥 高级特性 <span style="color:#34d399;font-size:10px;">resetTimer · onUpdate · render · notify</span></div>
|
||||
<div class="btn-row">
|
||||
<button class="btn c-i" onclick="demoResetTimer()">resetTimerOnUpdate</button>
|
||||
<button class="btn c-p" onclick="demoOnUpdate()">onUpdate 回调</button>
|
||||
@@ -242,7 +242,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 14. 交互特性 -->
|
||||
<!-- 14. 错误回调 -->
|
||||
<div class="card">
|
||||
<div class="label">🛡️ onError 错误捕获 <span style="color:#34d399;font-size:10px;">v0.1.2</span></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. 交互特性 -->
|
||||
<div class="card">
|
||||
<div class="label">✋ 交互特性</div>
|
||||
<div class="btn-row">
|
||||
@@ -254,7 +263,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 15. 国际化切换 -->
|
||||
<!-- 16. 国际化切换 -->
|
||||
<div class="card">
|
||||
<div class="label">🌍 国际化 & 格式化</div>
|
||||
<div class="btn-row">
|
||||
@@ -264,7 +273,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 16. 107种预设图标 -->
|
||||
<!-- 17. 107种预设图标 -->
|
||||
<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>
|
||||
@@ -273,7 +282,7 @@
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
MetonaToast v2.0.1 · MIT · <a href="index.html">首页</a> · <a href="docs.html">文档</a> · <a href="https://git.metona.cn/MetonaTeam/MetonaToast">Gitea</a>
|
||||
MetonaToast v0.1.2 · 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>
|
||||
@@ -351,7 +360,7 @@
|
||||
MeToast.info('自定义插件已安装(消息后追加计数)');
|
||||
}
|
||||
|
||||
// === v2.0 new features ===
|
||||
// === 高级特性 ===
|
||||
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);
|
||||
@@ -387,6 +396,25 @@
|
||||
});
|
||||
}
|
||||
|
||||
// === onError ===
|
||||
function demoOnError() {
|
||||
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 });
|
||||
setTimeout(function() { Toast.off('afterShow', badFn); }, 3000);
|
||||
}
|
||||
function demoOnErrorReset() {
|
||||
MeToast.configure({ onError: null });
|
||||
MeToast.info('onError 已重置为 null');
|
||||
}
|
||||
|
||||
// === i18n ===
|
||||
function switchLocale(loc) {
|
||||
try{MeToast.i18n.switchLocale(loc);MeToast.configure({locale:loc});MeToast.success(loc==='zh-CN'?'已切换到中文':'Switched to English',{theme:'dark'});}
|
||||
|
||||
+12
-10
@@ -69,9 +69,9 @@
|
||||
<a href="#countdown">countdown()</a>
|
||||
<a href="#queue">queue()</a>
|
||||
<a href="#stack">stack()</a>
|
||||
<a href="#action">action() <span class="badge badge-new">NEW</span></a>
|
||||
<a href="#action">action()</a>
|
||||
<div class="section">管理方法</div>
|
||||
<a href="#group">group() <span class="badge badge-new">NEW</span></a>
|
||||
<a href="#group">group()</a>
|
||||
<a href="#dismiss">dismiss()</a>
|
||||
<a href="#clear">clear()</a>
|
||||
<a href="#configure">configure()</a>
|
||||
@@ -87,7 +87,7 @@
|
||||
<main class="main">
|
||||
|
||||
<h1>API 文档</h1>
|
||||
<p>MetonaToast v2.0.1 完整 API 参考。所有基础通知方法(show/success/error/warning/info/loading)支持两种调用形式,均可传入任何 <a href="#config">配置项</a> 作为可选第二参数。</p>
|
||||
<p>MetonaToast v0.1.2 完整 API 参考。所有基础通知方法(show/success/error/warning/info/loading)支持两种调用形式,均可传入任何 <a href="#config">配置项</a> 作为可选第二参数。</p>
|
||||
|
||||
<!-- ===== 基础通知 ===== -->
|
||||
<h2 id="show">show(message, opts?)</h2>
|
||||
@@ -309,7 +309,7 @@ q.<span class="fn">cancel</span>(); <span class="cm">// 中途取消</span>
|
||||
<span class="fn">type</span>: <span class="s">'info'</span>,
|
||||
});</pre>
|
||||
|
||||
<h2 id="action">action(message, actions, opts?) <span class="badge badge-new">v2.0</span></h2>
|
||||
<h2 id="action">action(message, actions, opts?)</h2>
|
||||
<p>Action Toast:内嵌操作按钮。默认 duration=0 不自动关闭,closeButton=true。</p>
|
||||
<table>
|
||||
<tr><th>参数</th><th>类型</th><th>默认值</th><th>说明</th></tr>
|
||||
@@ -331,7 +331,7 @@ q.<span class="fn">cancel</span>(); <span class="cm">// 中途取消</span>
|
||||
]);</pre>
|
||||
|
||||
<!-- ===== 管理方法 ===== -->
|
||||
<h2 id="group">group(name) <span class="badge badge-new">v2.0</span></h2>
|
||||
<h2 id="group">group(name)</h2>
|
||||
<p>创建 Toast 分组,返回 GroupAPI 对象。该对象所有方法自动传入 <code>group: name</code>,按组管理。</p>
|
||||
<table>
|
||||
<tr><th>参数</th><th>类型</th><th>说明</th></tr>
|
||||
@@ -409,7 +409,7 @@ MeToast.<span class="fn">use</span>(<span class="s">'accessibility'</span>); <sp
|
||||
|
||||
<!-- ===== 配置参考 ===== -->
|
||||
<h2 id="config">全部配置项</h2>
|
||||
<p>以下配置可用于 <code>configure()</code>、<code>init()</code> 或单个 Toast 方法的 opts 参数。带 <span class="badge badge-new">v2.0</span> 标识的为 v2.0 新增。</p>
|
||||
<p>以下配置可用于 <code>configure()</code>、<code>init()</code> 或单个 Toast 方法的 opts 参数。</p>
|
||||
<table>
|
||||
<tr><th>配置项</th><th>类型</th><th>默认值</th><th>说明</th></tr>
|
||||
<tr><td>position</td><td>string</td><td>'top-right'</td><td>位置:top-left / top-center / top-right / bottom-left / bottom-center / bottom-right</td></tr>
|
||||
@@ -431,9 +431,10 @@ MeToast.<span class="fn">use</span>(<span class="s">'accessibility'</span>); <sp
|
||||
<tr><td>className</td><td>string</td><td>''</td><td>附加到 Toast 元素上的 CSS 类名</td></tr>
|
||||
<tr><td>style</td><td>object</td><td>{}</td><td>附加到 Toast 元素上的内联样式对象</td></tr>
|
||||
<tr><td>locale</td><td>string</td><td>'zh-CN'</td><td>语言代码(zh-CN / en-US 等)</td></tr>
|
||||
<tr><td>resetTimerOnUpdate <span class="badge badge-new">v2.0</span></td><td>boolean</td><td>false</td><td>调用 update() 时重置 duration 倒计时</td></tr>
|
||||
<tr><td>notifyWhenHidden <span class="badge badge-new">v2.0</span></td><td>boolean</td><td>false</td><td>页面不可见时自动通过 Notification API 发送系统通知</td></tr>
|
||||
<tr><td>render <span class="badge badge-new">v2.0</span></td><td>function</td><td>—</td><td>自定义渲染函数 <code>(toast) => htmlString</code>,完全接管 DOM 构建</td></tr>
|
||||
<tr><td>resetTimerOnUpdate</td><td>boolean</td><td>false</td><td>调用 update() 时重置 duration 倒计时</td></tr>
|
||||
<tr><td>notifyWhenHidden</td><td>boolean</td><td>false</td><td>页面不可见时自动通过 Notification API 发送系统通知</td></tr>
|
||||
<tr><td>render</td><td>function</td><td>—</td><td>自定义渲染函数 <code>(toast) => htmlString</code>,完全接管 DOM 构建</td></tr>
|
||||
<tr><td>onError</td><td>function</td><td>—</td><td>全局错误回调 <code>({ hook, source, error, toast }) => void</code>,钩子异常或定时器错误时触发</td></tr>
|
||||
</table>
|
||||
|
||||
<h2 id="callbacks">回调函数</h2>
|
||||
@@ -442,7 +443,8 @@ MeToast.<span class="fn">use</span>(<span class="s">'accessibility'</span>); <sp
|
||||
<tr><td>onShow</td><td>(toast: ToastInstance) => void</td><td>Toast DOM 创建并播放入场动画后</td></tr>
|
||||
<tr><td>onClose</td><td>(toast: ToastInstance) => void</td><td>Toast DOM 被移除后(离场动画完成时)</td></tr>
|
||||
<tr><td>onClick</td><td>(toast: ToastInstance) => void</td><td>Toast 被点击时(closeOnClick 为 true 时还会自动关闭)</td></tr>
|
||||
<tr><td>onUpdate <span class="badge badge-new">v2.0</span></td><td>(toast: ToastInstance) => void</td><td>Toast 内容通过 update() 更新后</td></tr>
|
||||
<tr><td>onUpdate</td><td>(toast: ToastInstance) => void</td><td>Toast 内容通过 update() 更新后</td></tr>
|
||||
<tr><td>onError</td><td>({ hook, source, error, toast }) => void</td><td>钩子回调或定时器发生异常时(全局配置,适用于接入错误监控)</td></tr>
|
||||
</table>
|
||||
|
||||
<h2 id="animations">动画列表</h2>
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "marklite",
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.3",
|
||||
"description": "Lightweight Markdown Editor for Windows",
|
||||
"main": "./dist/main/index.js",
|
||||
"scripts": {
|
||||
@@ -28,8 +28,8 @@
|
||||
"author": "MarkLite",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@metona-team/metona-editor": "^0.1.10",
|
||||
"@metona-team/metona-toast": "^2.0.1",
|
||||
"@metona-team/metona-editor": "0.1.14",
|
||||
"@metona-team/metona-toast": "^0.1.2",
|
||||
"dexie": "^4.0.11",
|
||||
"nanoid": "^5.1.5",
|
||||
"react": "^18.3.1",
|
||||
|
||||
@@ -128,6 +128,22 @@ body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* FIX: Allow text selection in the preview pane.
|
||||
global.css sets user-select:none on html/body to prevent
|
||||
selection in UI chrome (toolbar, tabs, sidebar), but this
|
||||
also blocked mouse-drag selection in the Markdown preview.
|
||||
Override back to the browser default for the preview area. */
|
||||
.metona-editor-wrapper .me-preview,
|
||||
.metona-editor-wrapper .me-preview * {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
/* Also restore selection in the editor textarea (MetonaEditor
|
||||
explicitly sets user-select:none on it in some themes) */
|
||||
.metona-editor-wrapper textarea {
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
/* Tab Bar */
|
||||
#tab-bar {
|
||||
height: 36px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// 共享常量 — 主进程和渲染进程共用
|
||||
export const APP_VERSION = 'v0.4.1'
|
||||
export const APP_VERSION = 'v0.4.3'
|
||||
export const MAX_FILE_SIZE = 20 * 1024 * 1024 // 20MB
|
||||
export const ALLOWED_EXTENSIONS = ['.md', '.markdown', '.txt'] as const
|
||||
export const SKIP_DIRS = new Set([
|
||||
|
||||
Reference in New Issue
Block a user