diff --git a/design/10-review/process/16-mnote-web-runtime-module-maintainability-checklist-v1.md b/design/10-review/process/16-mnote-web-runtime-module-maintainability-checklist-v1.md
index a526ae12..87a0a021 100644
--- a/design/10-review/process/16-mnote-web-runtime-module-maintainability-checklist-v1.md
+++ b/design/10-review/process/16-mnote-web-runtime-module-maintainability-checklist-v1.md
@@ -250,13 +250,13 @@ cargo test --manifest-path rust/Cargo.toml -p mnote-web --lib routes::tree -- --
- [x] E3. `runtime_bridge.rs`:迁出 `dispatch_runtime_event`、`dispatch_*_to_target`、host command listener install。
- [x] E4. `block_transform.rs`:迁出 `run_block_turn_into_action`、`top_level_block_matches_action`、page/block transform helpers。
- [x] E5. `slash_menu_view.rs`:迁出 slash menu Leptos view 和 click handling。
-- [ ] E6. `block_handle_menu_view.rs`:迁出 block handle menu 和 submenu view,作为最后一刀。
+- [x] E6. `block_handle_menu_view.rs`:迁出 block handle menu 和 submenu view,作为最后一刀。
验收标准:
- [x] `lib.rs` 少于 5,000 行。
-- [ ] `block_handle_menu_view.rs` 可以超过 1,500 行,但必须有清晰入参 struct,避免二十多个 signal 直接散落。
-- [ ] 不改变 Tiptap command 行为,不新增编辑器功能。
+- [x] `block_handle_menu_view.rs` 可以超过 1,500 行,但必须有清晰入参 struct,避免二十多个 signal 直接散落。
+- [x] 不改变 Tiptap command 行为,不新增编辑器功能。
验收命令:
diff --git a/rust/spikes/leptos-tiptap-spike/src/editor_runtime/block_handle_menu_view.rs b/rust/spikes/leptos-tiptap-spike/src/editor_runtime/block_handle_menu_view.rs
new file mode 100644
index 00000000..8276ffda
--- /dev/null
+++ b/rust/spikes/leptos-tiptap-spike/src/editor_runtime/block_handle_menu_view.rs
@@ -0,0 +1,668 @@
+use crate::{
+ current_page_anchor_url, editor_block_by_id, request_ai_edit_bridge,
+ write_mnote_text_to_clipboard,
+};
+use crate::editor_runtime::{
+ block_hover_state::{BlockMenuLayout, HoveredBlockState},
+ block_transform::{
+ apply_text_align, run_block_turn_into_action, run_block_turn_into_folded_heading_action,
+ run_block_turn_into_page_action, top_level_block_is_page, top_level_block_matches_action,
+ top_level_block_range,
+ },
+ command_sync::{read_editor_snapshot, sync_persisted_editor_command},
+ dom_events::trap_scroll_inside_menu,
+ dom_selection::runtime_block_id_from_index,
+ editor_focus::schedule_editor_focus,
+ persistence::{persist_document_state, persisted_document_identity, PersistedDocumentIdentity},
+ slash_actions::{SlashActionKind, SLASH_ACTIONS},
+};
+use leptos::prelude::*;
+use leptos_tiptap::{TiptapEditorHandle, TiptapSelectionState, TiptapTextAlign};
+use serde_json::Value;
+use wasm_bindgen_futures::spawn_local;
+use web_sys::{MouseEvent, WheelEvent};
+
+#[derive(Clone, Copy)]
+struct FoldedHeadingAction {
+ level: u8,
+ id: &'static str,
+ icon: &'static str,
+ label: &'static str,
+}
+
+const FOLDED_HEADING_ACTIONS: [FoldedHeadingAction; 4] = [
+ FoldedHeadingAction {
+ level: 1,
+ id: "1",
+ icon: "H1",
+ label: "折叠主标题",
+ },
+ FoldedHeadingAction {
+ level: 2,
+ id: "2",
+ icon: "H2",
+ label: "折叠大标题",
+ },
+ FoldedHeadingAction {
+ level: 3,
+ id: "3",
+ icon: "H3",
+ label: "折叠中标题",
+ },
+ FoldedHeadingAction {
+ level: 4,
+ id: "4",
+ icon: "H4",
+ label: "折叠小标题",
+ },
+];
+
+pub(crate) struct BlockHandleMenuViewProps {
+ pub(crate) editor: TiptapEditorHandle,
+ pub(crate) block: HoveredBlockState,
+ pub(crate) duplicate_block_label: String,
+ pub(crate) delete_block_label: String,
+ pub(crate) menu_layout: BlockMenuLayout,
+ pub(crate) signals: BlockHandleMenuSignals,
+}
+
+#[derive(Clone, Copy)]
+pub(crate) struct BlockHandleMenuSignals {
+ pub(crate) document_id: ReadSignal