对齐 Wolai 侧栏体验并收拢设计入库
This commit is contained in:
@@ -45,6 +45,8 @@ pub fn build_page_tree_dom_rows(rows: &[PageTreeRenderRow]) -> Vec<PageTreeDomRo
|
||||
.collect()
|
||||
}
|
||||
|
||||
const PAGE_TREE_CHEVRON_SVG: &str = r#"<svg class="tree-toggle-icon" viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><path d="M7.84 14.955c.206 0 .37-.07.505-.21l4.277-4.179a.79.79 0 0 0 .264-.574.78.78 0 0 0-.258-.574L8.35 5.24a.7.7 0 0 0-.51-.21.721.721 0 0 0-.498 1.247l3.814 3.721-3.814 3.709a.721.721 0 0 0 .498 1.248"></path></svg>"#;
|
||||
|
||||
fn escape_html(input: &str) -> String {
|
||||
input
|
||||
.replace('&', "&")
|
||||
@@ -54,6 +56,26 @@ fn escape_html(input: &str) -> String {
|
||||
.replace('\'', "'")
|
||||
}
|
||||
|
||||
fn render_depth_for_node(rows: &[PageTreeRenderRow], node_id: &str, fallback_depth: u32) -> u32 {
|
||||
if fallback_depth > 0 {
|
||||
return fallback_depth;
|
||||
}
|
||||
let parent_by_id = rows
|
||||
.iter()
|
||||
.map(|row| (row.node_id.as_str(), row.parent_node_id.as_deref()))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let mut depth = 0_u32;
|
||||
let mut cursor = parent_by_id.get(node_id).and_then(|parent| *parent);
|
||||
while let Some(parent_id) = cursor {
|
||||
depth += 1;
|
||||
cursor = parent_by_id.get(parent_id).and_then(|parent| *parent);
|
||||
if depth > 32 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
depth
|
||||
}
|
||||
|
||||
fn render_page_row(
|
||||
html: &mut String,
|
||||
row: &PageTreeRenderRow,
|
||||
@@ -80,11 +102,12 @@ fn render_page_row(
|
||||
.unwrap_or(false);
|
||||
let toggle_html = if row.expandable {
|
||||
format!(
|
||||
r#"<button type="button" class="tree-toggle" data-testid="tree-node-toggle" data-rust-action="toggle" data-node-id="{node_id}" aria-label="{label} {title}">{marker}</button>"#,
|
||||
r#"<button type="button" class="tree-toggle" data-testid="tree-node-toggle" data-rust-action="toggle" data-node-id="{node_id}" aria-label="{label} {title}" aria-expanded="{expanded_state}">{marker}</button>"#,
|
||||
node_id = escape_html(&row.node_id),
|
||||
label = if expanded { "折叠" } else { "展开" },
|
||||
title = escape_html(&row.title),
|
||||
marker = if expanded { "▾" } else { "▸" },
|
||||
expanded_state = if expanded { "true" } else { "false" },
|
||||
marker = PAGE_TREE_CHEVRON_SVG,
|
||||
)
|
||||
} else {
|
||||
r#"<span class="tree-spacer" aria-hidden="true"></span>"#.to_string()
|
||||
@@ -96,15 +119,18 @@ fn render_page_row(
|
||||
.and_then(|source| source.parent_node_id.as_deref())
|
||||
.map(|parent_id| format!(r#" data-parent-id="{}""#, escape_html(parent_id)))
|
||||
.unwrap_or_default();
|
||||
let render_depth = render_depth_for_node(&input.rows, &row.node_id, row.depth);
|
||||
html.push_str(&format!(
|
||||
r#"<li class="tree-node" data-node-id="{node_id}"><div class="tree-row" role="treeitem" aria-level="{aria_level}" aria-expanded="{expanded_attr}" data-rust-rendered-row="page" data-testid="wolai-sidebar-row" data-tree-testid="{test_id}" data-node-id="{node_id}"{parent_attr} data-depth="{depth}" data-shell-mode="page" data-active="{active}" data-focused="{focused}" data-draggable="true" draggable="true" tabindex="{tab_index}">{toggle_html}<span class="tree-kind-badge" data-kind="page" aria-hidden="true"></span><button type="button" class="tree-link" data-testid="tree-node-open" data-rust-action="open" data-node-id="{node_id}"><span class="tree-link-title">{title}</span></button><div class="tree-actions"><button type="button" class="tree-action" data-testid="tree-action-create" data-rust-action="create" data-node-id="{node_id}" aria-label="新建子页面">+</button><button type="button" class="tree-action" data-testid="tree-action-rename" data-rust-action="rename" data-node-id="{node_id}" aria-label="重命名">✎</button><button type="button" class="tree-action" data-testid="tree-action-menu" data-rust-action="menu" data-node-id="{node_id}" aria-label="更多操作">…</button></div></div>"#,
|
||||
r#"<li class="tree-node" data-node-id="{node_id}"><div class="tree-row" role="treeitem" aria-level="{aria_level}" aria-expanded="{expanded_attr}" data-rust-rendered-row="page" data-testid="wolai-sidebar-row" data-tree-testid="{test_id}" data-node-id="{node_id}"{parent_attr} data-depth="{depth}" data-shell-mode="page" data-active="{active}" aria-selected="{selected}"{current_attr} data-focused="{focused}" data-draggable="true" draggable="true" tabindex="{tab_index}">{toggle_html}<button type="button" class="tree-link" data-testid="tree-node-open" data-rust-action="open" data-node-id="{node_id}"><span class="tree-link-title">{title}</span></button><div class="tree-actions"><button type="button" class="tree-action" data-testid="tree-action-menu" data-rust-action="menu" data-node-id="{node_id}" aria-label="更多操作">…</button><button type="button" class="tree-action" data-testid="tree-action-create" data-rust-action="create" data-node-id="{node_id}" aria-label="新建子页面">+</button></div></div>"#,
|
||||
node_id = escape_html(&row.node_id),
|
||||
aria_level = row.depth + 1,
|
||||
aria_level = render_depth + 1,
|
||||
expanded_attr = if row.expandable && expanded { "true" } else { "false" },
|
||||
test_id = row.test_id,
|
||||
parent_attr = parent_attr,
|
||||
depth = row.depth,
|
||||
depth = render_depth,
|
||||
active = active,
|
||||
selected = active,
|
||||
current_attr = if active { r#" aria-current="page""# } else { "" },
|
||||
focused = focused,
|
||||
tab_index = if focused { "0" } else { "-1" },
|
||||
toggle_html = toggle_html,
|
||||
|
||||
Reference in New Issue
Block a user