refactor: split editor mount and sidebar page ai
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use leptos::ev;
|
||||
use leptos::mount::{mount_to, mount_to_body};
|
||||
use leptos::mount::mount_to_body;
|
||||
use leptos::prelude::*;
|
||||
use leptos_dom::helpers::window_event_listener;
|
||||
use leptos_tiptap::{
|
||||
@@ -9,7 +9,7 @@ use leptos_tiptap::{
|
||||
use send_wrapper::SendWrapper;
|
||||
use serde::Deserialize;
|
||||
use serde_json::{json, Value};
|
||||
use std::{cell::Cell, fmt::Display};
|
||||
use std::fmt::Display;
|
||||
use wasm_bindgen::{closure::Closure, prelude::*, JsCast, JsValue};
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use web_sys::{
|
||||
@@ -37,8 +37,8 @@ use editor_runtime::block_transform::{
|
||||
use editor_runtime::bridge_dispatch::HostCommandKind;
|
||||
use editor_runtime::bridge_events::{
|
||||
BridgeSelectorsPayload, ChangeMetaPayload, ChangePayload, HeightPayload, HostCommandEnvelope,
|
||||
HostCommandPayload, HostStatusPayload, ReadyPayload, RuntimePageOptions, StatePayload,
|
||||
BLOCK_DELTA_EVENT, COMMAND_EVENT, HEIGHT_EVENT, PROTOCOL, RUNTIME_NAME,
|
||||
HostCommandPayload, HostStatusPayload, ReadyPayload, StatePayload, BLOCK_DELTA_EVENT,
|
||||
COMMAND_EVENT, HEIGHT_EVENT, PROTOCOL, RUNTIME_NAME,
|
||||
};
|
||||
use editor_runtime::command_sync::{
|
||||
read_editor_snapshot, sync_editor_outputs, sync_persisted_editor_command,
|
||||
@@ -53,6 +53,13 @@ use editor_runtime::dom_selection::{
|
||||
};
|
||||
use editor_runtime::editor_focus::{active_editor_stage, body_has_focus, schedule_editor_focus};
|
||||
use editor_runtime::mindmap_node_view::{mount_mindmap_shell_impl, unmount_mindmap_shell_impl};
|
||||
use editor_runtime::mount::{
|
||||
initial_content, mount_app_into, runtime_delivery_mode, runtime_editor_instance_id,
|
||||
runtime_mount_context, set_runtime_mount_context, set_runtime_mount_options, MountOptions,
|
||||
RuntimeDeliveryMode, RuntimeStandaloneObject,
|
||||
};
|
||||
#[cfg(test)]
|
||||
use editor_runtime::mount::resolve_runtime_delivery_mode;
|
||||
use editor_runtime::overlays::{
|
||||
clamp_overlay_anchor, close_editor_floating_overlays_if_escape, image_element_from_target,
|
||||
image_toolbar_anchor_from_image, open_block_menu_overlay, open_image_toolbar_overlay,
|
||||
@@ -68,10 +75,9 @@ use editor_runtime::persistence::{
|
||||
persisted_document_identity, PersistedDocumentIdentity,
|
||||
};
|
||||
use editor_runtime::runtime_bridge::{
|
||||
build_command_listener, dispatch_change_event_to_target, dispatch_ready_event_to_target,
|
||||
dispatch_change_event_to_target, dispatch_ready_event_to_target,
|
||||
dispatch_runtime_event, dispatch_selection_event_to_target, dispatch_state_event_to_target,
|
||||
dispatch_status_event_to_target, register_runtime_listener, register_unmount_handle,
|
||||
take_unmount_handle,
|
||||
dispatch_status_event_to_target, register_runtime_listener, take_unmount_handle,
|
||||
};
|
||||
use editor_runtime::slash_actions::{SlashActionKind, SLASH_ACTIONS};
|
||||
use editor_runtime::style::SPIKE_STYLE;
|
||||
@@ -515,98 +521,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum RuntimeDeliveryMode {
|
||||
Standalone,
|
||||
Embedded,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct MountOptions {
|
||||
document_id: Option<String>,
|
||||
workspace_id: Option<String>,
|
||||
title: Option<String>,
|
||||
content: Option<Value>,
|
||||
html: Option<String>,
|
||||
editable: Option<bool>,
|
||||
read_only: Option<bool>,
|
||||
revision: Option<i64>,
|
||||
conflict_detection_key: Option<String>,
|
||||
page_options: Option<RuntimePageOptions>,
|
||||
#[serde(default)]
|
||||
standalone_object: Option<RuntimeStandaloneObject>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct RuntimeStandaloneObject {
|
||||
kind: Option<String>,
|
||||
document_id: Option<String>,
|
||||
mindmap_id: Option<String>,
|
||||
}
|
||||
|
||||
struct RuntimeMountContext {
|
||||
id: u32,
|
||||
target: EventTarget,
|
||||
mode: RuntimeDeliveryMode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(dead_code)]
|
||||
struct RuntimeMountOptions {
|
||||
options: MountOptions,
|
||||
mode: RuntimeDeliveryMode,
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static RUNTIME_MOUNT_CONTEXT: std::cell::RefCell<Option<RuntimeMountContext>> = const { std::cell::RefCell::new(None) };
|
||||
static RUNTIME_MOUNT_OPTIONS: std::cell::RefCell<Option<RuntimeMountOptions>> = const { std::cell::RefCell::new(None) };
|
||||
static NEXT_MOUNT_ID: Cell<u32> = const { Cell::new(1) };
|
||||
}
|
||||
|
||||
fn next_mount_id() -> u32 {
|
||||
NEXT_MOUNT_ID.with(|cell| {
|
||||
let next = cell.get();
|
||||
cell.set(next.saturating_add(1).max(1));
|
||||
next
|
||||
})
|
||||
}
|
||||
|
||||
fn set_runtime_mount_context(context: Option<RuntimeMountContext>) {
|
||||
RUNTIME_MOUNT_CONTEXT.with(|cell| {
|
||||
*cell.borrow_mut() = context;
|
||||
});
|
||||
}
|
||||
|
||||
fn runtime_mount_context() -> Option<(u32, EventTarget, RuntimeDeliveryMode)> {
|
||||
RUNTIME_MOUNT_CONTEXT.with(|cell| {
|
||||
cell.borrow()
|
||||
.as_ref()
|
||||
.map(|context| (context.id, context.target.clone(), context.mode))
|
||||
})
|
||||
}
|
||||
|
||||
fn runtime_delivery_mode() -> RuntimeDeliveryMode {
|
||||
resolve_runtime_delivery_mode(
|
||||
runtime_mount_context().map(|(_, _, mode)| mode),
|
||||
url_requests_embedded_mode(),
|
||||
)
|
||||
}
|
||||
|
||||
fn set_runtime_mount_options(options: Option<RuntimeMountOptions>) {
|
||||
RUNTIME_MOUNT_OPTIONS.with(|cell| {
|
||||
*cell.borrow_mut() = options;
|
||||
});
|
||||
}
|
||||
|
||||
fn runtime_editor_instance_id(mount_id: Option<u32>) -> String {
|
||||
mount_id
|
||||
.filter(|value| *value > 0)
|
||||
.map(|value| format!("mnote-leptos-tiptap-spike-{value}"))
|
||||
.unwrap_or_else(|| "mnote-leptos-tiptap-spike-standalone".to_string())
|
||||
}
|
||||
|
||||
fn editor_block_by_id(block_id: &str) -> Option<Element> {
|
||||
find_mnote_block_anchor(block_id)
|
||||
}
|
||||
@@ -728,7 +642,7 @@ pub fn unmount(mount_id: u32) -> Result<(), JsValue> {
|
||||
if let Some(handle) = take_unmount_handle(mount_id) {
|
||||
if runtime_mount_context().map(|(id, _, _)| id) == Some(mount_id) {
|
||||
set_runtime_mount_context(None);
|
||||
set_runtime_mount_options(None);
|
||||
set_runtime_mount_options(None, RuntimeDeliveryMode::Embedded);
|
||||
}
|
||||
drop(handle);
|
||||
Ok(())
|
||||
@@ -737,35 +651,6 @@ pub fn unmount(mount_id: u32) -> Result<(), JsValue> {
|
||||
}
|
||||
}
|
||||
|
||||
fn mount_app_into(target: HtmlElement, options: MountOptions, mode: RuntimeDeliveryMode) -> u32 {
|
||||
let mount_id = next_mount_id();
|
||||
let context_target: EventTarget = target.clone().into();
|
||||
let mount_options = RuntimeMountOptions {
|
||||
options: options.clone(),
|
||||
mode,
|
||||
};
|
||||
|
||||
set_runtime_mount_options(Some(mount_options.clone()));
|
||||
set_runtime_mount_context(Some(RuntimeMountContext {
|
||||
id: mount_id,
|
||||
target: context_target.clone(),
|
||||
mode,
|
||||
}));
|
||||
|
||||
let handle = mount_to(target, move || {
|
||||
view! {
|
||||
<App mount_options=options />
|
||||
}
|
||||
});
|
||||
|
||||
let command_listener = build_command_listener(mount_id);
|
||||
let _ = context_target
|
||||
.add_event_listener_with_callback(COMMAND_EVENT, command_listener.as_ref().unchecked_ref());
|
||||
|
||||
register_unmount_handle(mount_id, context_target, command_listener, handle);
|
||||
mount_id
|
||||
}
|
||||
|
||||
fn default_title() -> String {
|
||||
"Leptos Tiptap 主编辑器 P0".to_string()
|
||||
}
|
||||
@@ -818,28 +703,6 @@ fn runtime_persisted_identity(
|
||||
persisted_document_identity(document_id.get_untracked(), workspace_id.get_untracked())
|
||||
}
|
||||
|
||||
fn url_requests_embedded_mode() -> bool {
|
||||
window()
|
||||
.and_then(|win| win.location().search().ok())
|
||||
.map(|search| search.contains("embedded=1"))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn resolve_runtime_delivery_mode(
|
||||
explicit_mode: Option<RuntimeDeliveryMode>,
|
||||
url_embedded: bool,
|
||||
) -> RuntimeDeliveryMode {
|
||||
if let Some(mode) = explicit_mode {
|
||||
return mode;
|
||||
}
|
||||
|
||||
if url_embedded {
|
||||
RuntimeDeliveryMode::Embedded
|
||||
} else {
|
||||
RuntimeDeliveryMode::Standalone
|
||||
}
|
||||
}
|
||||
|
||||
fn is_embedded_mode() -> bool {
|
||||
runtime_delivery_mode() == RuntimeDeliveryMode::Embedded
|
||||
}
|
||||
@@ -4386,13 +4249,6 @@ fn App(mount_options: MountOptions) -> impl IntoView {
|
||||
}
|
||||
}
|
||||
|
||||
fn initial_content() -> TiptapContent {
|
||||
TiptapContent::json(serde_json::json!({
|
||||
"type": "doc",
|
||||
"content": []
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn standalone_main() {
|
||||
console_error_panic_hook::set_once();
|
||||
mount_to_body(|| {
|
||||
|
||||
Reference in New Issue
Block a user