feat(panels): open documents with top-level layers collapsed
A fully expanded tree stops answering the one question the LayerPanel exists for. A six-slide deck opens as ~90 rows, so the boards themselves scroll off the panel and the user cannot see what the document contains without scrolling past every leaf of slide one. Collapse only top-level containers on load: leaves have nothing to hide and would render a dead disclosure arrow. `collapsed_layers` is view-only state — not serialized, not in the undo snapshot, no history push — so this changes what the panel shows on open and nothing about the document. Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x
This commit is contained in:
parent
ad2f0e4a6a
commit
17a8fdcfdf
|
|
@ -130,9 +130,35 @@ fn finish_loaded_state(mut state: EditorState, meta: Option<EditorMeta>) -> Edit
|
|||
} else {
|
||||
state.ui.active_page_index = first_page_with_content(&state);
|
||||
}
|
||||
collapse_top_level_layers(&mut state);
|
||||
state
|
||||
}
|
||||
|
||||
/// Start every top-level frame collapsed in the LayerPanel.
|
||||
///
|
||||
/// A fully expanded tree is unreadable the moment a document has depth: a
|
||||
/// six-slide deck opens as ~90 rows and the boards themselves scroll off the
|
||||
/// panel, so the one thing the list is for — seeing what the document
|
||||
/// contains — is the first thing lost. Collapsed roots show the six slides
|
||||
/// and let the user open the one they want.
|
||||
///
|
||||
/// `collapsed_layers` is view-only state: not serialized, not in the undo
|
||||
/// snapshot, and toggling it pushes no history. So this changes what the
|
||||
/// panel shows on open and nothing about the document.
|
||||
fn collapse_top_level_layers(state: &mut EditorState) {
|
||||
let ids: Vec<op_editor_core::NodeId> = state
|
||||
.active_children()
|
||||
.iter()
|
||||
.filter(|node| {
|
||||
// Only containers collapse; a leaf has nothing to hide and would
|
||||
// just render a dead disclosure arrow.
|
||||
op_editor_core::PenNodeExt::children(*node).is_some_and(|kids| !kids.is_empty())
|
||||
})
|
||||
.map(|node| op_editor_core::NodeId::new(op_editor_core::PenNodeExt::id_str(node)))
|
||||
.collect();
|
||||
state.editor_ui.collapsed_layers.extend(ids);
|
||||
}
|
||||
|
||||
fn first_page_with_content(state: &EditorState) -> usize {
|
||||
let Some(pages) = state.doc.pages.as_ref() else {
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -105,3 +105,39 @@ fn reports_only_adopted_sidecar_and_reliable_editor_meta_inference() {
|
|||
let _ = std::fs::remove_file(inferred);
|
||||
let _ = std::fs::remove_file(ordinary);
|
||||
}
|
||||
|
||||
/// Top-level frames open collapsed in the LayerPanel.
|
||||
///
|
||||
/// A six-slide deck expands to ~90 rows, pushing the boards themselves off
|
||||
/// the panel — the list stops answering "what is in this document", which is
|
||||
/// the only question it exists for.
|
||||
#[test]
|
||||
fn loading_collapses_top_level_frames_but_not_leaves() {
|
||||
let source = serde_json::json!({
|
||||
"version": "1.0",
|
||||
"children": [
|
||||
{
|
||||
"type": "frame", "id": "board-1", "name": "01", "width": 1920, "height": 1080,
|
||||
"children": [{"type": "text", "id": "t1", "content": "hi"}]
|
||||
},
|
||||
{
|
||||
"type": "frame", "id": "board-2", "name": "02", "width": 1920, "height": 1080,
|
||||
"children": [{"type": "text", "id": "t2", "content": "hi"}]
|
||||
},
|
||||
// A childless top-level node: collapsing it would only render a
|
||||
// disclosure arrow that does nothing.
|
||||
{"type": "rectangle", "id": "loose", "name": "Loose", "width": 10, "height": 10}
|
||||
]
|
||||
})
|
||||
.to_string();
|
||||
|
||||
let state =
|
||||
super::load_editor_state_from_source(&source, op_editor_core::Locale::EnUs).expect("loads");
|
||||
let collapsed = &state.editor_ui.collapsed_layers;
|
||||
assert!(collapsed.contains(&op_editor_core::NodeId::new("board-1")));
|
||||
assert!(collapsed.contains(&op_editor_core::NodeId::new("board-2")));
|
||||
assert!(
|
||||
!collapsed.contains(&op_editor_core::NodeId::new("loose")),
|
||||
"a leaf has nothing to collapse"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue