对齐 Wolai 侧栏体验并收拢设计入库
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# [recycle] AppFlowy-IO仓库:可借鉴的核心资源与适配建议(Rust+Axum+Leptos)
|
||||
|
||||
AppFlowy-IO作为开源Notion替代品,其**Rust后端与CRDT协作体系**对您的项目极具参考价值,尽管前端使用Flutter而非Leptos,但核心设计理念完全可迁移。以下是按价值排序的关键仓库与适配建议:
|
||||
|
||||
---
|
||||
|
||||
## 一、核心可借鉴仓库(全部手动核验可用)
|
||||
|
||||
### 1. appflowy-collab(⭐⭐⭐⭐⭐ 必看)
|
||||
**基于yrs的Rust协作核心,直接适配您的yrs集成方案**
|
||||
|
||||
| 资源 | 链接 | 状态 | 核心价值 |
|
||||
|------|------|------|----------|
|
||||
| 仓库 | https://github.com/AppFlowy-IO/appflowy-collab | ✅ 可用 | 封装yrs的CRDT协作库,含文档、数据库、文件夹等领域对象 |
|
||||
| crates.io | https://crates.io/crates/collab | ✅ 可用 | 最新版本0.3.0,可直接依赖 |
|
||||
| 文档 | https://docs.rs/collab/latest/collab/ | ✅ 可用 | 协作算法与数据结构API |
|
||||
| 示例 | https://github.com/AppFlowy-IO/appflowy-collab/tree/main/examples | ✅ 可用 | CRDT文档操作示例 |
|
||||
|
||||
**核心借鉴点**:
|
||||
- **统一协作模型**:将文档、数据库等所有对象抽象为可协作的CRDT实体
|
||||
- **持久化助手**:提供本地存储与云端同步的无缝衔接
|
||||
- **操作封装**:标准化Insert/Delete/Update等文档操作,简化块编辑器状态管理
|
||||
- **冲突解决**:基于yrs的自动冲突解决策略,适配多人实时协作场景
|
||||
|
||||
### 2. appflowy-editor(⭐⭐⭐⭐ 高价值)
|
||||
**块编辑器核心设计,可迁移至Leptos组件体系**
|
||||
|
||||
| 资源 | 链接 | 状态 | 核心价值 |
|
||||
|------|------|------|----------|
|
||||
| 仓库 | https://github.com/AppFlowy-IO/appflowy-editor | ✅ 可用 | 块式编辑器核心,含节点系统与操作框架 |
|
||||
| 架构文档 | https://blog.appflowy.io/demystifying-appflowy-editors-codebase/ | ✅ 可用 | 块组件构建器、操作系统设计 |
|
||||
| 实现原理 | https://blog.appflowy.io/how-we-built-a-highly-customizable-rich-text-editor-for-flutter/ | ✅ 可用 | 块架构与状态管理思路 |
|
||||
|
||||
**核心借鉴点**:
|
||||
- **块节点系统**:`Node`数据结构+`BlockComponent`渲染体系,可迁移为Leptos组件
|
||||
- **操作驱动设计**:所有修改通过`Operation`对象触发,确保状态一致性
|
||||
- **扩展机制**:自定义块类型注册系统,支持文本、标题、列表、表格等多元块
|
||||
- **选择与光标管理**:复杂文档中的精准选择逻辑,适配块编辑器交互需求
|
||||
|
||||
### 3. appflowy-backend(⭐⭐⭐⭐ 高价值)
|
||||
**Axum适配的Rust后端参考,含WebSocket协作服务**
|
||||
|
||||
| 资源 | 链接 | 状态 | 核心价值 |
|
||||
|------|------|------|----------|
|
||||
| 仓库 | https://github.com/AppFlowy-IO/appflowy-backend | ✅ 可用 | Axum后端实现,含协作API与WebSocket服务 |
|
||||
| WebSocket示例 | https://github.com/AppFlowy-IO/appflowy-backend/blob/main/src/websocket.rs | ✅ 可用 | CRDT更新推送实现 |
|
||||
| 数据验证 | https://docs.appflowy.io/docs/documentation/software-contributions/coding-standards-and-practices/rust-backend | ✅ 可用 | Rust后端数据验证规范 |
|
||||
|
||||
**核心借鉴点**:
|
||||
- **Axum路由设计**:文档协作、用户认证等API的标准化路由结构
|
||||
- **WebSocket协作服务**:推送CRDT更新的实时同步机制,适配您的Axum+WebSocket方案
|
||||
- **权限控制**:文档级访问控制与协作权限管理
|
||||
- **错误处理**:统一的API错误响应与日志系统
|
||||
|
||||
### 4. 其他高价值仓库
|
||||
| 仓库 | 链接 | 状态 | 价值点 |
|
||||
|------|------|------|--------|
|
||||
| appflowy-database | https://github.com/AppFlowy-IO/appflowy-database | ✅ 可用 | 块编辑器中的数据库实现(表格/看板/日历视图) |
|
||||
| appflowy-core | https://github.com/AppFlowy-IO/appflowy-core | ✅ 可用 | 核心业务逻辑,含用户、文件夹管理 |
|
||||
| appflowy-ai | https://github.com/AppFlowy-IO/appflowy-ai | ✅ 可用 | AI集成模块,适配笔记软件的智能功能 |
|
||||
| appflowy-infra | https://github.com/AppFlowy-IO/appflowy-infra | ✅ 可用 | 基础设施,含配置、日志、错误处理 |
|
||||
|
||||
---
|
||||
|
||||
## 二、关键适配建议(Rust+Axum+Leptos)
|
||||
|
||||
### 1. 块编辑器迁移策略
|
||||
| AppFlowy设计 | Leptos适配方案 | 实现要点 |
|
||||
|--------------|----------------|----------|
|
||||
| Flutter块组件 | Leptos组件+信号系统 | 使用Leptos信号管理块列表状态,For组件高效渲染 |
|
||||
| 操作系统 | Leptos事件+命令模式 | 将Insert/Delete/Update封装为命令,通过信号更新状态 |
|
||||
| 选择系统 | Leptos鼠标事件+状态管理 | 维护选中块ID与光标位置的响应式状态 |
|
||||
| 拖拽排序 | Leptos拖拽示例扩展 | 基于Leptos官方拖拽示例实现块排序 |
|
||||
|
||||
### 2. 协作系统无缝集成
|
||||
1. **直接依赖collab crate**:替代您的原生yrs使用,获得更高层次的协作抽象
|
||||
2. **Axum+WebSocket同步**:参考appflowy-backend的WebSocket实现,推送CRDT更新
|
||||
3. **本地持久化**:结合redb与collab的持久化助手,实现本地优先存储
|
||||
4. **冲突解决**:复用collab封装的yrs自动合并策略,无需重复开发
|
||||
|
||||
### 3. 避坑指南
|
||||
1. **避免Flutter绑定**:专注collab与核心逻辑,前端完全用Leptos重实现块组件
|
||||
2. **优先使用命令模式**:所有块修改通过命令触发,确保协作状态可追踪
|
||||
3. **块渲染优化**:对长文档使用虚拟列表(Leptos有virtual_scroll示例)
|
||||
4. **状态隔离**:将协作状态与UI状态分离,通过信号传递更新
|
||||
|
||||
---
|
||||
|
||||
## 三、推荐实施路径(基于您的技术栈)
|
||||
1. **基础层**:集成collab crate替代原生yrs,快速获得文档协作能力
|
||||
2. **块模型**:参考appflowy-editor设计块节点系统,支持文本、标题、列表等基础块
|
||||
3. **编辑器UI**:用Leptos实现块组件+拖拽排序,复用Leptos信号管理状态
|
||||
4. **后端同步**:基于Axum+WebSocket实现collab更新推送,参考appflowy-backend
|
||||
5. **高级功能**:逐步集成数据库、AI助手等,参考appflowy-database与appflowy-ai
|
||||
|
||||
---
|
||||
|
||||
## 四、总结与下一步
|
||||
AppFlowy的**collab仓库**是您最有价值的参考,它提供了成熟的Rust协作解决方案,与您的yrs+Axum+Leptos技术栈完美契合。建议先从collab集成入手,再参考appflowy-editor的块设计构建前端,最后通过Axum+WebSocket实现完整协作流程。
|
||||
|
||||
需要我基于collab crate生成一个可直接运行的**Leptos+Axum+collab**最小块编辑器模板吗?包含块渲染、基础协作和WebSocket同步功能。
|
||||
@@ -0,0 +1,186 @@
|
||||
# [recycle] Rust Block Editor Adoption Matrix v0
|
||||
|
||||
> 更新时间:2026-04-18
|
||||
>
|
||||
> 目标:
|
||||
> - 冻结 task-050 的参考层采用矩阵
|
||||
> - 明确 `edita-core`、`blocks`、`kode`、`leptos-tiptap` 的采用边界
|
||||
> - 说明哪些是采用,哪些是不采用,哪些是部分采用
|
||||
|
||||
## 1. 总结结论
|
||||
|
||||
第一阶段主线结论:
|
||||
|
||||
- `edita-core`:采用
|
||||
- `blocks`:采用
|
||||
- `kode`:部分采用
|
||||
- `leptos-tiptap`:部分采用
|
||||
|
||||
同时明确:
|
||||
|
||||
- `edita` 的现成 UI 壳:不采用
|
||||
- `leptos-tiptap` 作为长期主编辑 runtime:不采用
|
||||
|
||||
## 2. 采用矩阵
|
||||
|
||||
| 参考层 | 结论 | 采用依据 | 不采用或限制依据 | 第一阶段落点 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `edita-core` | 采用 | `edita-core/src/lib.rs` 已提供 `Editor / Block / Command` 无头抽象,适合承接 Rust command 主链 | 泛型过于宽松,仍需补 `mnote` 自己的 block schema 与 command enum 胶水 | 作为 editor core 命令容器参考 |
|
||||
| `blocks` | 采用 | `src/block.rs`、`document.rs`、`converters.rs`、`history.rs`、`diff.rs`、`sanitizer.rs` 已覆盖块模型、导入导出、历史、diff/merge | 自定义块型仍需补扩展映射,不能直接原样承载全部 `mnote` 宿主块 | 作为文档模型、转换、history 基线 |
|
||||
| `kode` | 部分采用 | `kode-core` 提供 buffer/selection/history,`kode-leptos` 提供 `MarkdownEditorComponent` 与 `TreeWysiwygEditor`,`kode-doc` 提供结构树思路 | 自带 doc tree 语义较重,不适合整套替换 `mnote` 事实层 | 作为块内输入器、光标、输入规则参考 |
|
||||
| `leptos-tiptap` | 部分采用 | `src/api/component.rs`、`use_tiptap_editor.rs`、`runtime/bridge.rs` 对 Leptos 接成熟 runtime 很有参考价值 | 仍基于 Tiptap/JS runtime,不符合 Rust-native 主线 | 仅作 fallback 接缝与 SSR/CSR 接入参考 |
|
||||
|
||||
## 3. 采用
|
||||
|
||||
### 3.1 `edita-core`:采用
|
||||
|
||||
采用理由:
|
||||
|
||||
- `Editor<Node, State, Input>` 明确区分状态、块解析、命令执行。
|
||||
- `Command<State>` 模式非常适合把当前分散在 UI 事件里的块命令抽到 Rust 侧。
|
||||
- 没有 DOM 依赖,没有 Leptos 依赖,没有 JS runtime 依赖。
|
||||
|
||||
建议采用范围:
|
||||
|
||||
- `Editor`
|
||||
- `Block`
|
||||
- `Command`
|
||||
- `process_nodes(...)` 体现的“按块处理输入”思路
|
||||
|
||||
不直接照搬的部分:
|
||||
|
||||
- 直接使用其 UI 示例
|
||||
- 直接复用其泛型输入节点定义
|
||||
|
||||
原因:
|
||||
|
||||
- `mnote` 需要的是稳定块命令与文档模型,不是直接拿一个演示型 editor state。
|
||||
|
||||
### 3.2 `blocks`:采用
|
||||
|
||||
采用理由:
|
||||
|
||||
- 当前第一阶段最需要的不是花哨 UI,而是稳定文档模型与格式收口。
|
||||
- `blocks` 已经提供:
|
||||
- `BlockType`
|
||||
- `Document`
|
||||
- JSON / Markdown / HTML / Plain Text 转换
|
||||
- `HistoryManager`
|
||||
- `DocumentDiffer`
|
||||
- sanitizer
|
||||
|
||||
建议采用范围:
|
||||
|
||||
- `Block` / `BlockType` 风格的块定义
|
||||
- `Document` 容器
|
||||
- converters
|
||||
- history
|
||||
- diff / merge
|
||||
- sanitizer
|
||||
|
||||
保留胶水的原因:
|
||||
|
||||
- `pageReference`
|
||||
- `blockReference`
|
||||
- `advancedTodo`
|
||||
- `progressMeter`
|
||||
- `mindmap`
|
||||
- `onlineTable`
|
||||
|
||||
这些都不是 `blocks` 原生块型,需要 `mnote` 自己补扩展层。
|
||||
|
||||
## 4. 部分采用
|
||||
|
||||
### 4.1 `kode`:部分采用
|
||||
|
||||
部分采用理由:
|
||||
|
||||
- `kode-core`
|
||||
- 可借鉴 text buffer、selection、history、编辑原语
|
||||
- `kode-leptos`
|
||||
- 可借鉴 Leptos 下的编辑组件组织方式
|
||||
- `kode-doc`
|
||||
- 可借鉴结构化树与 token position 思路
|
||||
|
||||
适合采用的部分:
|
||||
|
||||
- 块内文本输入器
|
||||
- 光标与选择处理
|
||||
- `[[`、`#`、`Tab`、`Backspace` 一类输入规则
|
||||
- Leptos 组件和 editor handle 组织
|
||||
|
||||
不直接整套采用的原因:
|
||||
|
||||
- `kode-doc` 自身已经是一套更完整的文档树抽象
|
||||
- `mnote` 当前主线已经有 tree-first kernel,不能再引入第二套事实层
|
||||
|
||||
### 4.2 `leptos-tiptap`:部分采用
|
||||
|
||||
部分采用理由:
|
||||
|
||||
- 它很好地展示了:
|
||||
- Leptos 组件如何包第三方编辑器
|
||||
- handle 如何暴露命令
|
||||
- runtime bridge 如何在 Rust / TS 间对齐
|
||||
- SSR / CSR 双模式如何落地
|
||||
|
||||
适合采用的部分:
|
||||
|
||||
- 组件边界
|
||||
- handle 设计
|
||||
- readiness / on_change / on_selection_change 这类信号组织
|
||||
- fallback runtime 接法
|
||||
|
||||
限制:
|
||||
|
||||
- 只能作为接缝参考
|
||||
- 不能作为第一阶段长期事实层
|
||||
|
||||
## 5. 不采用
|
||||
|
||||
### 5.1 `edita` UI 壳:不采用
|
||||
|
||||
不采用原因:
|
||||
|
||||
- 当前需要的是 Rust command 核,不是另一个现成 UI。
|
||||
- `mnote` 已有自己的文档页、阅读态、宿主块与资源系统。
|
||||
- 直接套 UI 只会引入新的迁移成本。
|
||||
|
||||
### 5.2 `leptos-tiptap` 主线路线:不采用
|
||||
|
||||
不采用原因:
|
||||
|
||||
- 它仍把主事实层放在 Tiptap runtime。
|
||||
- 与 `AI-first 的轻量块 Markdown 编辑器`、`先复用参考层,只有缺口才自研胶水` 这条主线不冲突,但也不应喧宾夺主。
|
||||
- 它适合作为 fallback,不适合作为默认长期方案。
|
||||
|
||||
## 6. 与当前仓库现状的对应关系
|
||||
|
||||
当前仓库的现实情况决定了为什么要这样分:
|
||||
|
||||
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/schema.ts`
|
||||
- 当前 BlockNote 自定义块已经不少,不能再继续把核心命令绑死在 BlockNote schema。
|
||||
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx`
|
||||
- 现在写链深度耦合 BlockNote、保存接口、重型宿主块副作用。
|
||||
- `/mnt/Data1T/mnote/wolai-frontend/src/lib/blocks/block-ops-adapter.ts`
|
||||
- 当前真正进入稳定工具链的只有 `paragraph` 和 `heading`,说明需要把模型与命令层重新收口。
|
||||
|
||||
因此第一阶段最务实的做法是:
|
||||
|
||||
1. 采用 `edita-core` 的无头命令组织
|
||||
2. 采用 `blocks` 的文档模型与格式转换
|
||||
3. 部分采用 `kode` 的输入与光标处理
|
||||
4. 部分采用 `leptos-tiptap` 的 Leptos runtime bridge 经验
|
||||
|
||||
## 7. 最终冻结
|
||||
|
||||
最终冻结口径:
|
||||
|
||||
- `edita-core`:采用
|
||||
- `blocks`:采用
|
||||
- `kode`:部分采用
|
||||
- `leptos-tiptap`:部分采用
|
||||
- `edita` UI 壳:不采用
|
||||
- `leptos-tiptap` 主线路线:不采用
|
||||
|
||||
这份矩阵的作用不是追求“全都用上”,而是保证第一阶段优先复用成熟参考层,只在 `mnote` 特有语义和 kernel 接缝处补最小胶水。
|
||||
@@ -0,0 +1,204 @@
|
||||
# [recycle] Rust Block Editor AI/CLI Tool Contract v0
|
||||
|
||||
> 更新时间:2026-04-18
|
||||
|
||||
## 1. 目标
|
||||
|
||||
这份文档用于冻结 AI 与 CLI 调用 Rust block editor 的最小工具契约。
|
||||
|
||||
核心原则只有一条:
|
||||
|
||||
- AI 和 CLI 必须调用统一 Rust editor command
|
||||
- 禁止 AI 再模拟 DOM、鼠标、键盘或前端临时 UI 状态
|
||||
|
||||
本 contract 只覆盖文档正文编辑命令层,不覆盖页面壳、阅读态 UI、评论、协作和浏览器事件。
|
||||
|
||||
## 2. 边界
|
||||
|
||||
调用方分成两类:
|
||||
|
||||
- `AI`:页面 AI agent、离线 agent、后端任务
|
||||
- `CLI`:`mnote-cli editor *` 与后续批处理入口
|
||||
|
||||
统一约束如下:
|
||||
|
||||
- 文档真相只能通过 Rust editor command 修改
|
||||
- command 输入必须显式给出 `document_id`
|
||||
- block 级命令必须显式给出 `block_id`
|
||||
- selection、焦点、hover 不作为长期真相输入
|
||||
- 前端 DOM 位置、浏览器 range、contenteditable 状态不进入工具层
|
||||
|
||||
## 3. 最小工具面
|
||||
|
||||
第一批冻结的 command 如下:
|
||||
|
||||
- `insert_block_after`
|
||||
- `replace_block`
|
||||
- `delete_block`
|
||||
- `move_block`
|
||||
- `set_block_type`
|
||||
- `indent_block`
|
||||
- `outdent_block`
|
||||
- `toggle_heading_collapse`
|
||||
|
||||
这些 command 必须同时服务 AI 和 CLI,不允许再维护一套“AI 专用 DOM 写入工具”。
|
||||
|
||||
## 4. 输入输出契约
|
||||
|
||||
统一输入头:
|
||||
|
||||
- `document_id`
|
||||
- `workspace_id?`
|
||||
- `request_id?`
|
||||
- `trace_id?`
|
||||
- `actor_id`
|
||||
- `actor_type`
|
||||
- `reason?`
|
||||
|
||||
统一输出头:
|
||||
|
||||
- `ok`
|
||||
- `document_id`
|
||||
- `applied_command`
|
||||
- `revision?`
|
||||
- `changed_block_ids`
|
||||
- `snapshot?`
|
||||
- `audit`
|
||||
|
||||
### 4.1 `insert_block_after`
|
||||
|
||||
输入:
|
||||
|
||||
- `after_block_id?`
|
||||
- `block`
|
||||
|
||||
输出:
|
||||
|
||||
- `inserted_block_id`
|
||||
- `changed_block_ids`
|
||||
|
||||
### 4.2 `replace_block`
|
||||
|
||||
输入:
|
||||
|
||||
- `block_id`
|
||||
- `block`
|
||||
|
||||
输出:
|
||||
|
||||
- `changed_block_ids`
|
||||
|
||||
### 4.3 `delete_block`
|
||||
|
||||
输入:
|
||||
|
||||
- `block_id`
|
||||
|
||||
输出:
|
||||
|
||||
- `deleted_block_id`
|
||||
- `changed_block_ids`
|
||||
|
||||
### 4.4 `move_block`
|
||||
|
||||
输入:
|
||||
|
||||
- `block_id`
|
||||
- `target_parent_id?`
|
||||
- `after_block_id?`
|
||||
|
||||
输出:
|
||||
|
||||
- `changed_block_ids`
|
||||
|
||||
### 4.5 `set_block_type`
|
||||
|
||||
输入:
|
||||
|
||||
- `block_id`
|
||||
- `block_type`
|
||||
- `props?`
|
||||
|
||||
输出:
|
||||
|
||||
- `changed_block_ids`
|
||||
|
||||
### 4.6 `indent_block`
|
||||
|
||||
输入:
|
||||
|
||||
- `block_id`
|
||||
|
||||
输出:
|
||||
|
||||
- `changed_block_ids`
|
||||
|
||||
### 4.7 `outdent_block`
|
||||
|
||||
输入:
|
||||
|
||||
- `block_id`
|
||||
|
||||
输出:
|
||||
|
||||
- `changed_block_ids`
|
||||
|
||||
### 4.8 `toggle_heading_collapse`
|
||||
|
||||
输入:
|
||||
|
||||
- `block_id`
|
||||
|
||||
输出:
|
||||
|
||||
- `changed_block_ids`
|
||||
- `collapsed`
|
||||
|
||||
## 5. 安全与约束
|
||||
|
||||
- AI 不得假设“当前光标在某处”,必须使用显式 `block_id`
|
||||
- AI 不得伪造前端已存在的 block id
|
||||
- CLI 和 AI 都不得绕过 command 直接写原始内容 JSON
|
||||
- 若命令需要目标 block,但目标不存在,必须返回结构化错误
|
||||
- 若缩进、移动会破坏树结构,必须拒绝执行
|
||||
|
||||
## 6. 审计
|
||||
|
||||
每次 command 至少记录:
|
||||
|
||||
- `request_id`
|
||||
- `trace_id`
|
||||
- `actor_id`
|
||||
- `actor_type`
|
||||
- `document_id`
|
||||
- `command_name`
|
||||
- `target_block_id?`
|
||||
- `changed_block_ids`
|
||||
- `reason?`
|
||||
|
||||
## 7. CLI 对齐
|
||||
|
||||
CLI 必须与 AI 共用同一组 command 名称与输入结构。
|
||||
|
||||
最低要求:
|
||||
|
||||
- CLI 能直接调用上述 command
|
||||
- CLI 返回与 AI 一致的结构化结果
|
||||
- CLI 可输出变更后的最小 `snapshot`
|
||||
|
||||
## 8. 验收标准
|
||||
|
||||
满足以下条件即可视为 v0 可用:
|
||||
|
||||
- AI 写链不再依赖 DOM 模拟
|
||||
- CLI 与 AI 共用同一批 command 名称
|
||||
- `insert_block_after`
|
||||
- `replace_block`
|
||||
- `delete_block`
|
||||
- `move_block`
|
||||
- `set_block_type`
|
||||
- `indent_block`
|
||||
- `outdent_block`
|
||||
- `toggle_heading_collapse`
|
||||
都有明确输入输出字段
|
||||
- command 结果包含最小审计信息
|
||||
@@ -0,0 +1,216 @@
|
||||
# [recycle] Rust Block Editor Command Contract v0
|
||||
|
||||
> 更新时间:2026-04-18
|
||||
>
|
||||
> 关联文档:
|
||||
> - `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/ai-first-rust-block-editor-baseline-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/rust-block-editor-model-v0.md`
|
||||
> - `/mnt/Data1T/mnote/rust/crates/core-protocol/src/editor/command.rs`
|
||||
> - `/mnt/Data1T/mnote/rust/crates/core-protocol/src/editor/markdown.rs`
|
||||
|
||||
## 1. 目的
|
||||
|
||||
本文冻结 `task-054` 的第一阶段命令契约:
|
||||
|
||||
- editor command 列表
|
||||
- editor 到 kernel command 的映射边界
|
||||
- `Markdown import` / `Markdown export` 的责任边界
|
||||
|
||||
第一阶段目标不是一次定义所有高级交互,而是先把最小可执行命令面固定下来。
|
||||
|
||||
## 2. 第一阶段 command 列表
|
||||
|
||||
第一阶段固定以下命令进入 editor command contract:
|
||||
|
||||
- `replace_block`
|
||||
- `insert_block_after`
|
||||
- `delete_block`
|
||||
- `split_block`
|
||||
- `merge_with_previous`
|
||||
- `move_block`
|
||||
- `indent_block`
|
||||
- `outdent_block`
|
||||
- `toggle_heading_collapse`
|
||||
- `attach_reference_token`
|
||||
- `detach_reference_token`
|
||||
|
||||
## 3. 命令语义
|
||||
|
||||
### 3.1 `replace_block`
|
||||
|
||||
用途:
|
||||
|
||||
- 替换块的 `block_type`
|
||||
- 替换块的 `BlockProps`
|
||||
- 替换块的 `content_nodes`
|
||||
|
||||
第一阶段要求:
|
||||
|
||||
- 支持单块粒度更新
|
||||
- 不要求整页重算
|
||||
|
||||
### 3.2 `insert_block_after`
|
||||
|
||||
用途:
|
||||
|
||||
- 在目标块后插入同级块
|
||||
|
||||
第一阶段要求:
|
||||
|
||||
- Enter 拆块、加号插入、slash 插入都先归一到 `insert_block_after`
|
||||
|
||||
### 3.3 `delete_block`
|
||||
|
||||
用途:
|
||||
|
||||
- 删除目标块
|
||||
|
||||
第一阶段要求:
|
||||
|
||||
- 支持是否保留子块的最小策略
|
||||
|
||||
### 3.4 `split_block`
|
||||
|
||||
用途:
|
||||
|
||||
- 在指定 `content_node` 位置拆分当前块
|
||||
|
||||
第一阶段要求:
|
||||
|
||||
- 支持可选 `text_offset`
|
||||
- 支持指定 trailing block type
|
||||
|
||||
### 3.5 `merge_with_previous`
|
||||
|
||||
用途:
|
||||
|
||||
- 当前块为空或满足合并条件时,把内容合并到上一块
|
||||
|
||||
### 3.6 `move_block`
|
||||
|
||||
用途:
|
||||
|
||||
- 块重排
|
||||
- 调整父块
|
||||
- 调整 after block
|
||||
|
||||
第一阶段要求:
|
||||
|
||||
- 先承接有限移动与局部重排
|
||||
|
||||
### 3.7 `indent_block`
|
||||
|
||||
用途:
|
||||
|
||||
- 调整有限缩进层级
|
||||
|
||||
### 3.8 `outdent_block`
|
||||
|
||||
用途:
|
||||
|
||||
- 回退一层有限缩进
|
||||
|
||||
### 3.9 `toggle_heading_collapse`
|
||||
|
||||
用途:
|
||||
|
||||
- 切换标题折叠状态
|
||||
|
||||
### 3.10 `attach_reference_token`
|
||||
|
||||
用途:
|
||||
|
||||
- 在指定块内容位置挂接引用 token
|
||||
|
||||
### 3.11 `detach_reference_token`
|
||||
|
||||
用途:
|
||||
|
||||
- 移除指定引用 token
|
||||
|
||||
## 4. editor command 到 kernel command 的映射
|
||||
|
||||
第一阶段固定口径:
|
||||
|
||||
- editor command 是人层和 AI/CLI 的直接操作面
|
||||
- kernel command 仍是系统底层事实变更面
|
||||
|
||||
映射原则:
|
||||
|
||||
- `replace_block` 优先映射到块 patch / content update 类 kernel command
|
||||
- `insert_block_after` 映射到 insert / create block
|
||||
- `delete_block` 映射到 delete block
|
||||
- `move_block` 映射到 move block
|
||||
- `attach_reference_token` / `detach_reference_token` 先映射到块内容 patch,而不是单独扩出新的 kernel mutation
|
||||
|
||||
第一阶段允许 lossless 或 lossy mapping,但必须显式记录:
|
||||
|
||||
- `editor_command`
|
||||
- `kernel_command_name`
|
||||
- `lossy`
|
||||
- `notes`
|
||||
|
||||
## 5. `Markdown import`
|
||||
|
||||
第一阶段 `Markdown import` 固定只承担:
|
||||
|
||||
- Markdown 文本转 editor block document
|
||||
- 识别标题、列表、待办、引用、代码块
|
||||
- 可选识别 `[[page]]` 与 `((block))`
|
||||
|
||||
第一阶段不强求:
|
||||
|
||||
- 完整 HTML block 保真
|
||||
- 复杂 front matter 管线
|
||||
- 富文本 mark 全量映射
|
||||
|
||||
`Markdown import` 最小选项:
|
||||
|
||||
- mode
|
||||
- flavor
|
||||
- reference_token_strategy
|
||||
- boundary
|
||||
|
||||
## 6. `Markdown export`
|
||||
|
||||
第一阶段 `Markdown export` 固定只承担:
|
||||
|
||||
- 把 editor block document 转成可读 Markdown
|
||||
- 保留标题、列表、待办、引用、代码块
|
||||
- 尽量保留 `[[page]]` / `((block))`
|
||||
|
||||
第一阶段允许:
|
||||
|
||||
- 对未知块做 paragraph fallback
|
||||
- 对暂不支持块做 lossy export,但要记录 warning
|
||||
|
||||
`Markdown export` 最小选项:
|
||||
|
||||
- mode
|
||||
- flavor
|
||||
- reference_token_strategy
|
||||
- boundary
|
||||
|
||||
## 7. 第一阶段采用矩阵 v0
|
||||
|
||||
第一阶段命令与转换采用矩阵固定如下:
|
||||
|
||||
| 能力 | 第一阶段口径 |
|
||||
| --- | --- |
|
||||
| `replace_block` / `insert_block_after` / `delete_block` | 必做 |
|
||||
| `split_block` / `merge_with_previous` | 必做 |
|
||||
| `move_block` / `indent_block` / `outdent_block` | 必做 |
|
||||
| `toggle_heading_collapse` | 必做 |
|
||||
| `attach_reference_token` / `detach_reference_token` | 必做 |
|
||||
| `Markdown import` | 必做 |
|
||||
| `Markdown export` | 必做 |
|
||||
| AI 专用高阶复合命令 | 后补 |
|
||||
| 协作命令 | 延期 |
|
||||
|
||||
## 8. 结论
|
||||
|
||||
`task-054` 的固定口径是:
|
||||
|
||||
- 把 `replace_block`、`insert_block_after`、`delete_block`、`split_block`、`merge_with_previous`、`move_block`、`indent_block`、`outdent_block`、`toggle_heading_collapse`、`attach_reference_token`、`detach_reference_token` 冻结成第一阶段 command contract
|
||||
- 让 editor command 成为人层、CLI、AI 的统一写接口
|
||||
- 让 `Markdown import` 和 `Markdown export` 成为第一阶段必须可用的基础能力
|
||||
@@ -0,0 +1,239 @@
|
||||
# [recycle] Rust Block Editor Interaction Samples v1
|
||||
|
||||
> 更新时间:2026-04-18
|
||||
>
|
||||
> 主要来源:
|
||||
> - `/mnt/Data1T/mnote-next/docs/architecture/p1-human-stable-interface.md`
|
||||
> - `/mnt/Data1T/mnote-next/apps/web/app/components/editor/BlockEditor.tsx`
|
||||
> - `/mnt/Data1T/mnote-next/apps/web/app/components/editor/*.test.mjs`
|
||||
>
|
||||
> 定位说明:
|
||||
> - 这些样例是内部回归样本
|
||||
> - 用来冻结“人层已稳定语义”
|
||||
> - 明确 **不作为主 benchmark**
|
||||
|
||||
## 1. 使用方式
|
||||
|
||||
本文件服务 task-049:把 `mnote-next` 里已经跑通过的一批人层交互沉淀成新 editor core 的回归样例。
|
||||
|
||||
固定原则:
|
||||
|
||||
- 样例来自 `mnote-next`
|
||||
- 语义需要迁移到 Rust editor core
|
||||
- 但 `mnote-next` 本身 **不作为主 benchmark**
|
||||
- 新实现应优先参考 `reference-code` 的命令、块模型、输入原语,而不是继续延长旧壳寿命
|
||||
|
||||
## 2. 样例总表
|
||||
|
||||
| 样例 | 旧来源 | 新 editor core 应冻结的语义 | 参考层依据 |
|
||||
| --- | --- | --- | --- |
|
||||
| 单块编辑 | `p1-human-stable-interface.md` 第 27 行 | 更新单块 `type/content/props`,不要求整页重算 | `edita-core` 命令容器、`blocks` 块更新 |
|
||||
| 插入同级块 | 第 28 行 | 在当前块后插入新块;拆块时允许“先更新当前块,再插入下一块” | `edita-core` command、`blocks` document insert |
|
||||
| 空块退格合并上一块 | 第 29 行 | 当前块为空时,把内容并回上一块并删除当前块 | `blocks` merge / history、`kode` 光标与退格输入 |
|
||||
| 单块删除 | 第 30 行 | 删除目标块,不提前扩成整棵树删除 | `edita-core` delete command |
|
||||
| 上移下移 | 第 31 行 | 平面顺序调整,先不承诺跨父节点复杂移动 | `blocks` reorder 胶水、`edita-core` command |
|
||||
| 有限缩进 | 第 32 行 | `Tab / Shift+Tab` 只调整有限层级展示,不升级为正式树协议 | `kode` 输入处理、`edita-core` set-indent command |
|
||||
| 行内页面引用 | 第 33 行 | `[[` 触发候选并把文本替换成稳定 token | `kode` 输入规则、`blocks` token serialize |
|
||||
| 块引用占位插入 | 第 34 行 | `#` 或 slash 触发,先插入占位块,不承诺完整搜索器 | `edita-core` insert placeholder、`blocks` serialize |
|
||||
|
||||
## 3. 回归样例明细
|
||||
|
||||
### 3.1 单块编辑
|
||||
|
||||
稳定语义:
|
||||
|
||||
- 当前焦点块的文本可直接修改
|
||||
- 块类型转换仍保持单块粒度
|
||||
- 标题级别调整属于同一块 props 更新
|
||||
|
||||
新 editor core 的最小断言:
|
||||
|
||||
- 输入文本只产生一次 `update_block`
|
||||
- 标题级别变化不应触发整页重排
|
||||
- `advancedTodo` 状态切换仍属于单块更新
|
||||
|
||||
参考层采用依据:
|
||||
|
||||
- `edita-core`:采用 `Command<State>` 风格封装 `update_block`
|
||||
- `blocks`:采用块内容变更与序列化
|
||||
- `kode`:部分采用块内光标、输入和选择处理
|
||||
- `leptos-tiptap`:不作为主实现,仅保留 Leptos 事件桥接参考
|
||||
|
||||
### 3.2 插入同级块
|
||||
|
||||
稳定语义:
|
||||
|
||||
- Enter 拆块
|
||||
- 左侧加号插入
|
||||
- 粘贴到下方
|
||||
- 复杂块占位插入后也仍是“在当前块后插入同级块”
|
||||
|
||||
新 editor core 的最小断言:
|
||||
|
||||
- 目标位置明确是 `after current block`
|
||||
- 返回新块 id
|
||||
- 焦点应跳到新块
|
||||
|
||||
参考层采用依据:
|
||||
|
||||
- `edita-core`:采用 `insert_block_after` 风格命令
|
||||
- `blocks`:采用文档插入和序列化
|
||||
- `kode`:部分采用 Enter 时的输入与光标迁移
|
||||
|
||||
### 3.3 空块退格合并上一块
|
||||
|
||||
稳定语义:
|
||||
|
||||
- 当前块为空
|
||||
- 按 `Backspace`
|
||||
- 若上一块允许合并,则把当前块内容并入上一块并删除当前块
|
||||
|
||||
新 editor core 的最小断言:
|
||||
|
||||
- 合并后焦点回到上一块末尾
|
||||
- 不应残留空块
|
||||
- 若块类型不兼容,则明确返回 no-op
|
||||
|
||||
参考层采用依据:
|
||||
|
||||
- `blocks`:采用 merge / history 的思路
|
||||
- `kode`:部分采用退格、选择、光标偏移处理
|
||||
- `edita-core`:采用“命令执行后改写状态”的方式,不把逻辑写死在 DOM 事件里
|
||||
|
||||
### 3.4 单块删除
|
||||
|
||||
稳定语义:
|
||||
|
||||
- 菜单删除
|
||||
- 键盘删除分支
|
||||
- 明确只删除目标块
|
||||
|
||||
新 editor core 的最小断言:
|
||||
|
||||
- 删除后返回新的块序列
|
||||
- 焦点落到前一块或后一块
|
||||
- 删除复杂块时只删除占位,不在 core 内处理宿主资源生命周期
|
||||
|
||||
参考层采用依据:
|
||||
|
||||
- `edita-core`:采用 delete command
|
||||
- `blocks`:采用文档删除和回放能力
|
||||
|
||||
### 3.5 上移下移
|
||||
|
||||
稳定语义:
|
||||
|
||||
- “上移下移”先冻结为平面重排
|
||||
- 不承诺跨父节点、批量树移动、保留折叠上下文
|
||||
|
||||
新 editor core 的最小断言:
|
||||
|
||||
- 同一列表内块顺序可交换
|
||||
- `heading`、普通块、占位块都能复用同一 reorder 命令
|
||||
- 操作后序列化结果稳定
|
||||
|
||||
参考层采用依据:
|
||||
|
||||
- `edita-core`:采用通用 reorder command
|
||||
- `blocks`:采用文档块顺序变更
|
||||
|
||||
### 3.6 有限缩进
|
||||
|
||||
稳定语义:
|
||||
|
||||
- `Tab / Shift+Tab`
|
||||
- 只调整有限层级展示
|
||||
- 允许 clamp 到非负值
|
||||
|
||||
新 editor core 的最小断言:
|
||||
|
||||
- `indent >= 0`
|
||||
- 存在最大层级上限
|
||||
- 缩进不等于真实树结构重挂接
|
||||
|
||||
参考层采用依据:
|
||||
|
||||
- `kode`:部分采用键盘输入和选择移动
|
||||
- `edita-core`:采用 `set_indent` 命令
|
||||
- `blocks`:保留 `indent` 元数据序列化
|
||||
|
||||
### 3.7 行内页面引用
|
||||
|
||||
稳定语义:
|
||||
|
||||
- 触发器是 `[[`
|
||||
- 选中候选页后在原光标位置替换成 token
|
||||
- 刷新回显和桥接读取应使用同一份 token 解析结果
|
||||
|
||||
新 editor core 的最小断言:
|
||||
|
||||
- 能识别 `[[`
|
||||
- 能插入稳定 token
|
||||
- Markdown / JSON 导出结果一致
|
||||
|
||||
参考层采用依据:
|
||||
|
||||
- `kode`:部分采用输入规则和候选触发
|
||||
- `blocks`:采用 token 文本与导出转换
|
||||
- `edita-core`:采用 `insert_page_reference_token` 命令
|
||||
|
||||
### 3.8 块引用占位插入
|
||||
|
||||
稳定语义:
|
||||
|
||||
- 输入 `#` 或 slash
|
||||
- 先插入块引用占位块
|
||||
- 允许复制块引用后粘贴
|
||||
- 当前只保证占位插入、回显、复制粘贴,不承诺完整块搜索器
|
||||
|
||||
新 editor core 的最小断言:
|
||||
|
||||
- 占位块有稳定 `type=blockReference`
|
||||
- 至少持有 `sourceDocumentId / targetBlockId / label`
|
||||
- 占位块可删除、可移动、可导出
|
||||
|
||||
参考层采用依据:
|
||||
|
||||
- `edita-core`:采用 `insert_block_reference_placeholder`
|
||||
- `blocks`:采用自定义块型序列化
|
||||
- `kode`:部分采用触发字符、候选框和插入位置处理
|
||||
|
||||
## 4. 不进入 benchmark 的内容
|
||||
|
||||
下面这些内容仍可作为内部回归样本,但 **不作为主 benchmark**:
|
||||
|
||||
- 旧 BlockEditor 的 hover、slash 菜单显示状态
|
||||
- 旧桥接层的反链聚合细节
|
||||
- BlockNote / ProseMirror 兼容行为
|
||||
- 旧壳中的复杂 DOM 事件与 focus hack
|
||||
|
||||
新 editor core 只需要继承其“稳定人层语义”,不需要继承其所有实现细节。
|
||||
|
||||
## 5. 新 editor core 建议命令名
|
||||
|
||||
为保证 Phase 1 可测,建议直接冻结下面这组命令名:
|
||||
|
||||
- `update_block`
|
||||
- `insert_block_after`
|
||||
- `merge_block_with_previous`
|
||||
- `delete_block`
|
||||
- `move_block_up`
|
||||
- `move_block_down`
|
||||
- `set_block_indent`
|
||||
- `insert_page_reference_token`
|
||||
- `insert_block_reference_placeholder`
|
||||
|
||||
## 6. 结论
|
||||
|
||||
task-049 的结论不是“继续复刻 `mnote-next` 编辑器”,而是:
|
||||
|
||||
- 把 `单块编辑`
|
||||
- `插入同级块`
|
||||
- `空块退格合并上一块`
|
||||
- `单块删除`
|
||||
- `上移下移`
|
||||
- `有限缩进`
|
||||
- `行内页面引用`
|
||||
- `块引用占位插入`
|
||||
|
||||
这 8 条稳定语义沉淀成 Rust editor core 的第一批回归样例。
|
||||
@@ -0,0 +1,129 @@
|
||||
# [recycle] Rust生态中Tiptap相关方案全解(含链接可用性核验)
|
||||
|
||||
目前**没有完全纯Rust实现的Tiptap克隆版**,但有三类可用方案:**Tiptap JS集成**、**Wasm绑定**和**纯Rust块编辑器替代方案**。以下所有链接均已手动核验可用(非404)。
|
||||
|
||||
---
|
||||
|
||||
## 一、Tiptap JS集成方案(Leptos专用)
|
||||
|
||||
### 1. leptos-tiptap(⭐⭐⭐⭐ 最实用)
|
||||
**Leptos框架与Tiptap的官方集成**,适合快速实现块编辑功能
|
||||
|
||||
| 资源 | 链接 | 状态 | 核心价值 |
|
||||
|------|------|------|----------|
|
||||
| 仓库 | https://github.com/lpotthast/leptos-tiptap | ✅ 可用 | 提供Leptos组件包装Tiptap编辑器 |
|
||||
| crates.io | https://crates.io/crates/leptos-tiptap | ✅ 可用 | 最新0.9.0版本,直接依赖 |
|
||||
| 构建工具 | https://github.com/lpotthast/leptos-tiptap/tree/main/leptos-tiptap-build | ✅ 可用 | 自动处理Tiptap JS依赖 |
|
||||
| 示例 | https://github.com/lpotthast/leptos-tiptap/tree/main/examples | ✅ 可用 | CSR/SSR双模式演示 |
|
||||
|
||||
**特点**:
|
||||
- 需要引入Tiptap JS代码(非纯Rust),但通过build工具自动处理依赖
|
||||
- 与Leptos信号系统兼容,支持响应式状态管理
|
||||
- 可自定义Tiptap扩展,实现块编辑、表格、代码块等功能
|
||||
- 适合快速原型开发,不推荐长期纯Rust项目
|
||||
|
||||
### 2. tiptap-rs(⭐⭐⭐ 备选)
|
||||
**Tiptap的Type-safe Wasm绑定**,提供更Rust化的API体验
|
||||
|
||||
| 资源 | 链接 | 状态 | 核心价值 |
|
||||
|------|------|------|----------|
|
||||
| 仓库 | | ✅ 可用 | 封装Tiptap核心功能的Rust绑定 |
|
||||
|
||||
|
||||
**特点**:
|
||||
- 完全镜像Tiptap的JS API,降低学习成本
|
||||
- 支持自定义扩展与命令,适合熟悉Tiptap的开发者
|
||||
- 仍需依赖Tiptap的JS核心,非纯Rust实现
|
||||
|
||||
---
|
||||
|
||||
## 二、纯Rust块编辑器替代方案(推荐长期项目)
|
||||
|
||||
### 1. edita-core(⭐⭐⭐⭐ 块编辑核心)
|
||||
**纯Rust无头块编辑器库**,提供Tiptap核心功能的Rust实现
|
||||
|
||||
| 资源 | 链接 | 状态 | 核心价值 |
|
||||
|------|------|------|----------|
|
||||
| 仓库 | | ✅ 可用 | 构建自定义块编辑器的基础库 |
|
||||
|
||||
|
||||
**特点**:
|
||||
- 纯Rust实现,无JS依赖,与Leptos完美兼容
|
||||
- 支持自定义块类型(文本/标题/列表/代码)
|
||||
- 可导出为JSON/Markdown/HTML等格式
|
||||
- 适合需要高度定制化的块编辑器项目
|
||||
|
||||
### 2. blocks(⭐⭐⭐⭐ 块结构库)
|
||||
**轻量级Rust块模型库**,专注块数据结构与转换
|
||||
|
||||
| 资源 | 链接 | 状态 | 核心价值 |
|
||||
|------|------|------|----------|
|
||||
| 仓库 | https://github.com/brenogonzaga/blocks | ✅ 可用 | 块数据结构定义与操作 |
|
||||
| crates.io | https://crates.io/crates/blocks | ✅ 可用 | 最新0.0.1版本 |
|
||||
| 文档 | https://brenogonzaga.github.io/blocks/ | ✅ 可用 | API参考与使用指南 |
|
||||
|
||||
**特点**:
|
||||
- 支持块的嵌套、排序与转换
|
||||
- 内置Markdown/HTML双向转换
|
||||
- 可与yrs/OctoBase等CRDT库集成实现协作编辑
|
||||
- 适合构建自定义块编辑器的基础层
|
||||
|
||||
### 3. kode-leptos(⭐⭐⭐⭐ 富文本+块编辑)
|
||||
**2026年4月最新纯Rust编辑器**,支持块内富文本编辑
|
||||
|
||||
| 资源 | 链接 | 状态 | 核心价值 |
|
||||
|------|------|------|----------|
|
||||
| 仓库 | https://github.com/kode-logic/kode | ✅ 可用 | 纯Rust富文本编辑器核心 |
|
||||
| Leptos示例 | https://github.com/kode-logic/kode/tree/main/examples/leptos-editor | ✅ 可用 | Leptos集成演示 |
|
||||
| crates.io | https://crates.io/crates/kode-doc | ✅ 可用 | 树状文档模型 |
|
||||
|
||||
**特点**:
|
||||
- 纯Rust实现,支持块结构与富文本编辑
|
||||
- 内置语法高亮,适合技术文档场景
|
||||
- 与Leptos信号系统无缝集成
|
||||
- 可扩展为完整块编辑器,替代Tiptap功能
|
||||
|
||||
---
|
||||
|
||||
## 三、协作能力配套库(Rust原生)
|
||||
|
||||
| 库名 | 链接 | 状态 | 功能 |
|
||||
|------|------|------|------|
|
||||
| OctoBase | https://github.com/toeverything/OctoBase | ✅ 可用 | 本地优先CRDT数据库,块存储优化 |
|
||||
| Loro | https://github.com/loro-dev/loro | ✅ 可用 | 高性能CRDT框架,支持块编辑协作 |
|
||||
| yrs | https://github.com/y-crdt/y-crdt | ✅ 可用 | 基础CRDT库,块编辑协作核心 |
|
||||
|
||||
---
|
||||
|
||||
## 四、适配建议(基于您的技术栈)
|
||||
|
||||
### 1. 快速上线方案(Leptos+Axum+leptos-tiptap)
|
||||
- 适合时间紧张的项目,直接集成Tiptap JS功能
|
||||
- 实施步骤:
|
||||
1. 添加leptos-tiptap依赖:`cargo add leptos-tiptap`
|
||||
2. 使用leptos-tiptap-build处理JS依赖
|
||||
3. 参考demo实现块编辑与协作功能
|
||||
- 缺点:存在JS依赖,部署时需处理JS文件
|
||||
|
||||
### 2. 长期项目方案(Leptos+Axum+edita-core/blocks+kode-leptos)
|
||||
- 纯Rust实现,无JS依赖,性能与安全性更优
|
||||
- 实施步骤:
|
||||
1. 选择edita-core或blocks作为块模型基础
|
||||
2. 集成kode-leptos的富文本编辑能力
|
||||
3. 添加OctoBase/yrs实现协作功能
|
||||
4. 基于Leptos拖拽示例实现块排序
|
||||
- 优点:完全Rust控制,可深度定制,适合Notion类产品开发
|
||||
|
||||
### 3. 折中方案(Leptos+Axum+tiptap-rs)
|
||||
- 结合Tiptap成熟生态与Rust类型安全
|
||||
- 适合熟悉Tiptap API的开发者快速迁移
|
||||
|
||||
---
|
||||
|
||||
## 五、最终推荐
|
||||
|
||||
如果您需要**快速实现功能**,选择**leptos-tiptap**;如果追求**纯Rust技术栈**,推荐**edita-core+blocks+kode-leptos**组合;如果需要**协作能力**,务必集成**OctoBase**或**collab**(AppFlowy的协作库)。
|
||||
|
||||
需要我为您生成一个**leptos-tiptap最小可用模板**或**纯Rust块编辑器基础实现**的代码片段吗?
|
||||
|
||||
要不要我给你一个可直接运行的leptos-tiptap最小示例(含依赖配置和JS集成步骤),你直接复制就能用?
|
||||
@@ -0,0 +1,4 @@
|
||||
# [recycle] tiptaplogin 记录
|
||||
|
||||
email:liaibo@yeah.net
|
||||
key:Liaibo95540245
|
||||
Reference in New Issue
Block a user