refactor: split sidebar settings and slash menu view
This commit is contained in:
@@ -80,6 +80,9 @@ use editor_runtime::runtime_bridge::{
|
||||
dispatch_status_event_to_target, register_runtime_listener, take_unmount_handle,
|
||||
};
|
||||
use editor_runtime::slash_actions::{SlashActionKind, SLASH_ACTIONS};
|
||||
use editor_runtime::slash_menu_view::{
|
||||
slash_menu_view, SlashMenuRuntimeContext, SlashMenuSignals, SlashMenuViewProps,
|
||||
};
|
||||
use editor_runtime::style::SPIKE_STYLE;
|
||||
use editor_runtime::table_toolbar_view::table_toolbar_view;
|
||||
|
||||
@@ -2240,6 +2243,54 @@ fn App(mount_options: MountOptions) -> impl IntoView {
|
||||
}
|
||||
};
|
||||
|
||||
let slash_menu_runtime = SlashMenuRuntimeContext {
|
||||
change_event_target: slash_change_event_target.clone(),
|
||||
dispatch_runtime_state: std::sync::Arc::new(move |target: &EventTarget| {
|
||||
dispatch_runtime_state_to_target(
|
||||
target,
|
||||
document_id.get_untracked(),
|
||||
workspace_id.get_untracked(),
|
||||
title.get_untracked(),
|
||||
dirty_count.get_untracked(),
|
||||
hovered_block.get_untracked(),
|
||||
editor_focused.get_untracked(),
|
||||
slash_open.get_untracked(),
|
||||
turn_into_open.get_untracked(),
|
||||
color_menu_open.get_untracked(),
|
||||
more_menu_open.get_untracked(),
|
||||
read_only.get_untracked(),
|
||||
);
|
||||
}),
|
||||
};
|
||||
let slash_menu_props = SlashMenuViewProps {
|
||||
editor,
|
||||
signals: SlashMenuSignals {
|
||||
slash_open,
|
||||
set_slash_open,
|
||||
slash_index,
|
||||
slash_query,
|
||||
dirty_count,
|
||||
set_dirty_count,
|
||||
document_json: set_document_json,
|
||||
html_output: set_html_output,
|
||||
json_output: set_json_output,
|
||||
document_id,
|
||||
workspace_id,
|
||||
title,
|
||||
editor_focused,
|
||||
hovered_block,
|
||||
turn_into_open,
|
||||
color_menu_open,
|
||||
more_menu_open,
|
||||
revision,
|
||||
conflict_detection_key,
|
||||
read_only,
|
||||
command_feedback: set_command_feedback,
|
||||
},
|
||||
runtime: slash_menu_runtime,
|
||||
anchor_style: std::sync::Arc::new(slash_menu_anchor_style),
|
||||
};
|
||||
|
||||
view! {
|
||||
<style>{SPIKE_STYLE}</style>
|
||||
<main
|
||||
@@ -3828,192 +3879,7 @@ fn App(mount_options: MountOptions) -> impl IntoView {
|
||||
}
|
||||
}}
|
||||
|
||||
{move || {
|
||||
if slash_open.get() {
|
||||
view! {
|
||||
<div
|
||||
class="slash-menu"
|
||||
data-testid="mnote-leptos-tiptap-slash-menu"
|
||||
style=slash_menu_anchor_style()
|
||||
>
|
||||
<div class="slash-list">
|
||||
{move || {
|
||||
let query = slash_query.get().trim().to_ascii_lowercase();
|
||||
let show_turn_into = !query.is_empty()
|
||||
&& ("zhw".contains(query.as_str())
|
||||
|| "转换为".contains(query.as_str()));
|
||||
let show_page = !query.is_empty()
|
||||
&& ("ym".contains(query.as_str())
|
||||
|| "页面".contains(query.as_str()));
|
||||
if show_turn_into || show_page {
|
||||
view! {
|
||||
<>
|
||||
{if show_turn_into {
|
||||
view! {
|
||||
<>
|
||||
<div class="slash-section-label">"转换为"</div>
|
||||
<button
|
||||
class="slash-item"
|
||||
data-active="false"
|
||||
data-testid="slash-item-turn-into"
|
||||
on:click=move |_| {
|
||||
set_command_feedback.set("转换为入口请通过块菜单或选区工具栏执行".to_string());
|
||||
}
|
||||
>
|
||||
<span class="slash-item-row">
|
||||
<span class="slash-item-icon">"↻"</span>
|
||||
<span class="slash-item-copy">
|
||||
<strong>"转换为"</strong>
|
||||
<span>"打开块类型转换入口"</span>
|
||||
</span>
|
||||
<span class="slash-item-shortcut">"/zhw"</span>
|
||||
</span>
|
||||
</button>
|
||||
</>
|
||||
}.into_any()
|
||||
} else {
|
||||
().into_any()
|
||||
}}
|
||||
{if show_page {
|
||||
view! {
|
||||
<>
|
||||
<div class="slash-section-label">"基础块列表"</div>
|
||||
<button
|
||||
class="slash-item"
|
||||
data-active="false"
|
||||
data-testid="slash-item-page"
|
||||
on:click=move |_| {
|
||||
set_command_feedback.set("页面入口请通过转换为页面真源链路执行".to_string());
|
||||
}
|
||||
>
|
||||
<span class="slash-item-row">
|
||||
<span class="slash-item-icon">"▣"</span>
|
||||
<span class="slash-item-copy">
|
||||
<strong>"页面"</strong>
|
||||
<span>"创建或转换为页面块"</span>
|
||||
</span>
|
||||
<span class="slash-item-shortcut">"/ym"</span>
|
||||
</span>
|
||||
</button>
|
||||
</>
|
||||
}.into_any()
|
||||
} else {
|
||||
().into_any()
|
||||
}}
|
||||
</>
|
||||
}.into_any()
|
||||
} else {
|
||||
().into_any()
|
||||
}
|
||||
}}
|
||||
{SLASH_ACTIONS.iter().enumerate().map(|(index, action)| {
|
||||
let is_selected = move || slash_index.get() == index;
|
||||
let kind = action.kind;
|
||||
let label = action.label;
|
||||
let description = action.description;
|
||||
let shortcut = action.shortcut;
|
||||
let icon = action.icon;
|
||||
let category = action.category;
|
||||
let show_category = index == 0
|
||||
|| SLASH_ACTIONS[index - 1].category != category;
|
||||
let testid = format!("slash-item-{}", action.id);
|
||||
let slash_change_event_target = slash_change_event_target.clone();
|
||||
view! {
|
||||
<>
|
||||
{if show_category {
|
||||
view! { <div class="slash-section-label">{category}</div> }.into_any()
|
||||
} else {
|
||||
().into_any()
|
||||
}}
|
||||
<button
|
||||
class="slash-item"
|
||||
data-active=move || is_selected().to_string()
|
||||
data-testid=testid
|
||||
on:click=move |_| {
|
||||
match run_slash_action(editor, kind) {
|
||||
Ok(message) => {
|
||||
set_slash_open.set(false);
|
||||
set_dirty_count.update(|count| *count += 1);
|
||||
let (html, snapshot, json_text) = read_editor_snapshot(editor);
|
||||
set_html_output.set(html.clone());
|
||||
set_document_json.set(snapshot.clone());
|
||||
set_json_output.set(json_text);
|
||||
if let Some(target) = slash_change_event_target.as_ref() {
|
||||
dispatch_change_event_to_target(
|
||||
target,
|
||||
&ChangePayload {
|
||||
document_id: document_id.get_untracked(),
|
||||
workspace_id: workspace_id.get_untracked(),
|
||||
title: title.get_untracked(),
|
||||
content: snapshot.clone(),
|
||||
meta: ChangeMetaPayload {
|
||||
dirty_count: dirty_count.get_untracked(),
|
||||
editor_focused: editor_focused.get_untracked(),
|
||||
slash_open: slash_open.get_untracked(),
|
||||
toolbar_open: toolbar_overlay_locked(
|
||||
turn_into_open.get_untracked(),
|
||||
color_menu_open.get_untracked(),
|
||||
more_menu_open.get_untracked(),
|
||||
),
|
||||
selected_block_index: hovered_block.get_untracked().map(|block| block.index),
|
||||
revision: revision.get_untracked(),
|
||||
conflict_detection_key: conflict_detection_key.get_untracked(),
|
||||
read_only: read_only.get_untracked(),
|
||||
},
|
||||
},
|
||||
);
|
||||
dispatch_runtime_state_to_target(
|
||||
target,
|
||||
document_id.get_untracked(),
|
||||
workspace_id.get_untracked(),
|
||||
title.get_untracked(),
|
||||
dirty_count.get_untracked(),
|
||||
hovered_block.get_untracked(),
|
||||
editor_focused.get_untracked(),
|
||||
slash_open.get_untracked(),
|
||||
turn_into_open.get_untracked(),
|
||||
color_menu_open.get_untracked(),
|
||||
more_menu_open.get_untracked(),
|
||||
read_only.get_untracked(),
|
||||
);
|
||||
}
|
||||
match persist_document_state(
|
||||
&runtime_persisted_identity(document_id, workspace_id),
|
||||
&title.get_untracked(),
|
||||
&snapshot,
|
||||
Some(html),
|
||||
) {
|
||||
Ok(()) => set_command_feedback.set(format!("{message},并已写入本地草稿")),
|
||||
Err(err) => set_command_feedback.set(format!("{message},但本地保存失败:{err}")),
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
set_slash_open.set(false);
|
||||
set_command_feedback.set(format!("命令执行失败:{err}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
<span class="slash-item-row">
|
||||
<span class="slash-item-icon">{icon}</span>
|
||||
<span class="slash-item-copy">
|
||||
<strong>{label}</strong>
|
||||
<span>{description}</span>
|
||||
</span>
|
||||
<span class="slash-item-shortcut">{shortcut}</span>
|
||||
</span>
|
||||
</button>
|
||||
</>
|
||||
}
|
||||
}).collect_view()}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
.into_any()
|
||||
} else {
|
||||
().into_any()
|
||||
}
|
||||
}}
|
||||
{slash_menu_view(slash_menu_props)}
|
||||
|
||||
<TiptapEditor
|
||||
id=editor_instance_id.clone()
|
||||
|
||||
Reference in New Issue
Block a user