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 879c90d7..3899d4e5 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
@@ -209,7 +209,7 @@ cargo test --manifest-path rust/Cargo.toml -p mnote-web --lib ssr::pages::layout
- [ ] D3. `tree-shell-filetree-runtime.js`:filetree row normalization、resource meta、open target。
- [ ] D4. `tree-shell-picker-runtime.js`:picker search/focus/pick root。
- [ ] D5. `tree-shell-dom-runtime.js`:DOM patch/render helpers。
-- [ ] D6. `tree-shell-icons-runtime.js`:icon templates 和 resource kind badge。
+- [x] D6. `tree-shell-icons-runtime.js`:icon templates 和 resource kind badge。
- [ ] D7. entrypoint 少于 2,500 行。
验收命令:
diff --git a/rust/crates/mnote-web/browser/tree-shell-icons-runtime.js b/rust/crates/mnote-web/browser/tree-shell-icons-runtime.js
new file mode 100644
index 00000000..d205db5d
--- /dev/null
+++ b/rust/crates/mnote-web/browser/tree-shell-icons-runtime.js
@@ -0,0 +1,133 @@
+// MNote debug /tree shell icon templates and small DOM factories.
+
+export const TREE_SHELL_ICONS = {
+ add: `
+
+ `,
+ more: `
+
+ `,
+ edit: `
+
+ `,
+ up: `
+
+ `,
+ page: `
+
+ `,
+ index: `
+
+ `,
+ mindmap: `
+
+ `,
+ table: `
+
+ `,
+ pdf: `
+
+ `,
+ book: `
+
+ `,
+ image: `
+
+ `,
+ video: `
+
+ `,
+ audio: `
+
+ `,
+ file: `
+
+ `,
+};
+
+export function createTreeShellKindBadge(kind) {
+ const badge = document.createElement("span");
+ badge.className = "tree-kind-badge";
+ badge.dataset.kind = kind;
+ badge.innerHTML =
+ kind === "mindmap"
+ ? TREE_SHELL_ICONS.mindmap
+ : kind === "table"
+ ? TREE_SHELL_ICONS.table
+ : kind === "pdf"
+ ? TREE_SHELL_ICONS.pdf
+ : kind === "book"
+ ? TREE_SHELL_ICONS.book
+ : kind === "image"
+ ? TREE_SHELL_ICONS.image
+ : kind === "video"
+ ? TREE_SHELL_ICONS.video
+ : kind === "audio"
+ ? TREE_SHELL_ICONS.audio
+ : kind === "index"
+ ? TREE_SHELL_ICONS.index
+ : kind === "page"
+ ? TREE_SHELL_ICONS.page
+ : TREE_SHELL_ICONS.file;
+ return badge;
+}
+
+export function createTreeShellActionButton(icon, testId, title, onClick, disabled, busy) {
+ const button = document.createElement("button");
+ button.type = "button";
+ button.className = "tree-action";
+ button.dataset.testid = testId;
+ button.title = title;
+ button.setAttribute("aria-label", title);
+ button.innerHTML = icon;
+ button.disabled = disabled || busy;
+ button.addEventListener("click", (event) => {
+ event.stopPropagation();
+ onClick(button);
+ });
+ return button;
+}
diff --git a/rust/crates/mnote-web/browser/tree-shell-runtime.js b/rust/crates/mnote-web/browser/tree-shell-runtime.js
index a753b27e..a969c40b 100644
--- a/rust/crates/mnote-web/browser/tree-shell-runtime.js
+++ b/rust/crates/mnote-web/browser/tree-shell-runtime.js
@@ -5,6 +5,11 @@ import {
reconcilePageRuntimeResult,
reducePageActionWithRuntime,
} from "./tree-shell-page-runtime.js";
+import {
+ TREE_SHELL_ICONS as ICONS,
+ createTreeShellActionButton,
+ createTreeShellKindBadge as createKindBadge,
+} from "./tree-shell-icons-runtime.js";
function buildFileTreeRuntimeEnvironment(runtimeContext) {
const fileTreeRowById = runtimeContext.fileTreeRowById || new Map();
@@ -1759,95 +1764,6 @@ function startTreeShellRuntime() {
return text ? text.slice(0, 180) : "树命令执行失败";
};
- const ICONS = {
- add: `
-
- `,
- more: `
-
- `,
- edit: `
-
- `,
- up: `
-
- `,
- page: `
-
- `,
- index: `
-
- `,
- mindmap: `
-
- `,
- table: `
-
- `,
- pdf: `
-
- `,
- book: `
-
- `,
- image: `
-
- `,
- video: `
-
- `,
- audio: `
-
- `,
- file: `
-
- `,
- };
-
const sendCommand = async (payload) => {
setBusy(true);
setStatus("正在提交树命令…");
@@ -3768,48 +3684,8 @@ function startTreeShellRuntime() {
return false;
};
- const createKindBadge = (kind) => {
- const badge = document.createElement("span");
- badge.className = "tree-kind-badge";
- badge.dataset.kind = kind;
- badge.innerHTML =
- kind === "mindmap"
- ? ICONS.mindmap
- : kind === "table"
- ? ICONS.table
- : kind === "pdf"
- ? ICONS.pdf
- : kind === "book"
- ? ICONS.book
- : kind === "image"
- ? ICONS.image
- : kind === "video"
- ? ICONS.video
- : kind === "audio"
- ? ICONS.audio
- : kind === "index"
- ? ICONS.index
- : kind === "page"
- ? ICONS.page
- : ICONS.file;
- return badge;
- };
-
- const createActionButton = (icon, testId, title, onClick, disabled) => {
- const button = document.createElement("button");
- button.type = "button";
- button.className = "tree-action";
- button.dataset.testid = testId;
- button.title = title;
- button.setAttribute("aria-label", title);
- button.innerHTML = icon;
- button.disabled = disabled || busy;
- button.addEventListener("click", (event) => {
- event.stopPropagation();
- onClick(button);
- });
- return button;
- };
+ const createActionButton = (icon, testId, title, onClick, disabled) =>
+ createTreeShellActionButton(icon, testId, title, onClick, disabled, busy);
const renderNode = (item) => {
const hasChildren = item.childCount > 0;
diff --git a/rust/crates/mnote-web/src/routes/mod.rs b/rust/crates/mnote-web/src/routes/mod.rs
index 9d18d845..129868b6 100644
--- a/rust/crates/mnote-web/src/routes/mod.rs
+++ b/rust/crates/mnote-web/src/routes/mod.rs
@@ -170,6 +170,10 @@ pub fn build_router(state: AppState) -> Router {
"/api/mnote-browser-runtime/tree-shell-page-runtime.js",
get(web_shell::tree_shell_page_runtime_asset),
)
+ .route(
+ "/api/mnote-browser-runtime/tree-shell-icons-runtime.js",
+ get(web_shell::tree_shell_icons_runtime_asset),
+ )
.route(
"/api/mnote-browser-runtime/document-conflict-panel-runtime.js",
get(web_shell::document_conflict_panel_runtime_asset),
@@ -622,6 +626,7 @@ mod tests {
"/api/mnote-browser-runtime/tree-live-controller.js",
"/api/mnote-browser-runtime/tree-shell-runtime.js",
"/api/mnote-browser-runtime/tree-shell-page-runtime.js",
+ "/api/mnote-browser-runtime/tree-shell-icons-runtime.js",
"/api/mnote-browser-runtime/document-conflict-panel-runtime.js",
"/api/mnote-browser-runtime/document-pane-runtime.js",
"/api/mnote-browser-runtime/document-mindmap-host-runtime.js",
diff --git a/rust/crates/mnote-web/src/routes/web_shell.rs b/rust/crates/mnote-web/src/routes/web_shell.rs
index fbfc751c..3abb1e28 100644
--- a/rust/crates/mnote-web/src/routes/web_shell.rs
+++ b/rust/crates/mnote-web/src/routes/web_shell.rs
@@ -952,6 +952,20 @@ pub async fn tree_shell_page_runtime_asset() -> Response {
.unwrap_or_else(|_| Response::new(Body::empty()))
}
+pub async fn tree_shell_icons_runtime_asset() -> Response {
+ const JS: &str = include_str!("../../browser/tree-shell-icons-runtime.js");
+ Response::builder()
+ .status(StatusCode::OK)
+ .header(
+ header::CONTENT_TYPE,
+ "application/javascript; charset=utf-8",
+ )
+ .header(header::CACHE_CONTROL, "no-store")
+ .header(HEADER_MNOTE_WEB_OWNER, "mnote-web")
+ .body(Body::from(JS))
+ .unwrap_or_else(|_| Response::new(Body::empty()))
+}
+
pub async fn document_conflict_panel_runtime_asset() -> Response {
// include_str! 路径相对于当前源文件 (src/routes/web_shell.rs -> ../../browser/)
const JS: &str = include_str!("../../browser/document-conflict-panel-runtime.js");