Factor out element outline item
This commit is contained in:
		
							parent
							
								
									7f595ff27a
								
							
						
					
					
						commit
						df6db983ba
					
				
					 1 changed files with 109 additions and 104 deletions
				
			
		| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
use itertools::Itertools;
 | 
			
		||||
use sycamore::{prelude::*, web::tags::div};
 | 
			
		||||
use web_sys::{
 | 
			
		||||
    Element,
 | 
			
		||||
    Event,
 | 
			
		||||
    HtmlInputElement,
 | 
			
		||||
    KeyboardEvent,
 | 
			
		||||
| 
						 | 
				
			
			@ -9,7 +8,7 @@ use web_sys::{
 | 
			
		|||
    wasm_bindgen::JsCast
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use crate::{AppState, assembly::Constraint};
 | 
			
		||||
use crate::{AppState, assembly, assembly::Constraint};
 | 
			
		||||
 | 
			
		||||
// an editable view of the Lorentz product representing a constraint
 | 
			
		||||
#[component(inline_props)]
 | 
			
		||||
| 
						 | 
				
			
			@ -53,6 +52,112 @@ fn ConstraintOutlineItem(constraint_key: usize, element_key: usize) -> View {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// a list item that shows an element in an outline view of an assembly
 | 
			
		||||
#[component(inline_props)]
 | 
			
		||||
fn ElementOutlineItem(key: usize, element: assembly::Element) -> View {
 | 
			
		||||
    let state = use_context::<AppState>();
 | 
			
		||||
    let class = create_memo({
 | 
			
		||||
        move || {
 | 
			
		||||
            if state.selection.with(|sel| sel.contains(&key)) {
 | 
			
		||||
                "selected"
 | 
			
		||||
            } else {
 | 
			
		||||
                ""
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    let label = element.label.clone();
 | 
			
		||||
    let rep_components = element.rep.iter().map(|u| {
 | 
			
		||||
        let u_coord = u.to_string().replace("-", "\u{2212}");
 | 
			
		||||
        View::from(div().children(u_coord))
 | 
			
		||||
    }).collect::<Vec<_>>();
 | 
			
		||||
    let constrained = element.constraints.len() > 0;
 | 
			
		||||
    let details_node = create_node_ref();
 | 
			
		||||
    view! {
 | 
			
		||||
        li {
 | 
			
		||||
            details(ref=details_node) {
 | 
			
		||||
                summary(
 | 
			
		||||
                    class=class.get(),
 | 
			
		||||
                    on:keydown={
 | 
			
		||||
                        move |event: KeyboardEvent| {
 | 
			
		||||
                            match event.key().as_str() {
 | 
			
		||||
                                "Enter" => {
 | 
			
		||||
                                    if event.shift_key() {
 | 
			
		||||
                                        state.selection.update(|sel| {
 | 
			
		||||
                                            if !sel.remove(&key) {
 | 
			
		||||
                                                sel.insert(key);
 | 
			
		||||
                                            }
 | 
			
		||||
                                        });
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        state.selection.update(|sel| {
 | 
			
		||||
                                            sel.clear();
 | 
			
		||||
                                            sel.insert(key);
 | 
			
		||||
                                        });
 | 
			
		||||
                                    }
 | 
			
		||||
                                    event.prevent_default();
 | 
			
		||||
                                },
 | 
			
		||||
                                "ArrowRight" if constrained => {
 | 
			
		||||
                                    let _ = details_node
 | 
			
		||||
                                        .get()
 | 
			
		||||
                                        .unchecked_into::<web_sys::Element>()
 | 
			
		||||
                                        .set_attribute("open", "");
 | 
			
		||||
                                },
 | 
			
		||||
                                "ArrowLeft" => {
 | 
			
		||||
                                    let _ = details_node
 | 
			
		||||
                                        .get()
 | 
			
		||||
                                        .unchecked_into::<web_sys::Element>()
 | 
			
		||||
                                        .remove_attribute("open");
 | 
			
		||||
                                },
 | 
			
		||||
                                _ => ()
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                ) {
 | 
			
		||||
                    div(
 | 
			
		||||
                        class="elt-switch",
 | 
			
		||||
                        on:click=|event: MouseEvent| event.stop_propagation()
 | 
			
		||||
                    )
 | 
			
		||||
                    div(
 | 
			
		||||
                        class="elt",
 | 
			
		||||
                        on:click={
 | 
			
		||||
                            move |event: MouseEvent| {
 | 
			
		||||
                                if event.shift_key() {
 | 
			
		||||
                                    state.selection.update(|sel| {
 | 
			
		||||
                                        if !sel.remove(&key) {
 | 
			
		||||
                                            sel.insert(key);
 | 
			
		||||
                                        }
 | 
			
		||||
                                    });
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    state.selection.update(|sel| {
 | 
			
		||||
                                        sel.clear();
 | 
			
		||||
                                        sel.insert(key);
 | 
			
		||||
                                    });
 | 
			
		||||
                                }
 | 
			
		||||
                                event.stop_propagation();
 | 
			
		||||
                                event.prevent_default();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    ) {
 | 
			
		||||
                        div(class="elt-label") { (label) }
 | 
			
		||||
                        div(class="elt-rep") { (rep_components) }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                ul(class="constraints") {
 | 
			
		||||
                    Keyed(
 | 
			
		||||
                        list=element.constraints.into_iter().collect::<Vec<_>>(),
 | 
			
		||||
                        view=move |cst_key| view! {
 | 
			
		||||
                            ConstraintOutlineItem(
 | 
			
		||||
                                constraint_key=cst_key,
 | 
			
		||||
                                element_key=key
 | 
			
		||||
                            )
 | 
			
		||||
                        },
 | 
			
		||||
                        key=|cst_key| cst_key.clone()
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// a component that lists the elements of the current assembly, showing the
 | 
			
		||||
// constraints on each element as a collapsible sub-list. its implementation
 | 
			
		||||
// is based on Kate Morley's HTML + CSS tree views:
 | 
			
		||||
| 
						 | 
				
			
			@ -81,108 +186,8 @@ pub fn Outline() -> View {
 | 
			
		|||
        ) {
 | 
			
		||||
            Keyed(
 | 
			
		||||
                list=elements_sorted,
 | 
			
		||||
                view=|(key, elt)| {
 | 
			
		||||
                    let state = use_context::<AppState>();
 | 
			
		||||
                    let class = create_memo({
 | 
			
		||||
                        move || {
 | 
			
		||||
                            if state.selection.with(|sel| sel.contains(&key)) {
 | 
			
		||||
                                "selected"
 | 
			
		||||
                            } else {
 | 
			
		||||
                                ""
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                    let label = elt.label.clone();
 | 
			
		||||
                    let rep_components = elt.rep.iter().map(|u| {
 | 
			
		||||
                        let u_coord = u.to_string().replace("-", "\u{2212}");
 | 
			
		||||
                        View::from(div().children(u_coord))
 | 
			
		||||
                    }).collect::<Vec<_>>();
 | 
			
		||||
                    let constrained = elt.constraints.len() > 0;
 | 
			
		||||
                    let details_node = create_node_ref();
 | 
			
		||||
                    view! {
 | 
			
		||||
                        li {
 | 
			
		||||
                            details(ref=details_node) {
 | 
			
		||||
                                summary(
 | 
			
		||||
                                    class=class.get(),
 | 
			
		||||
                                    on:keydown={
 | 
			
		||||
                                        move |event: KeyboardEvent| {
 | 
			
		||||
                                            match event.key().as_str() {
 | 
			
		||||
                                                "Enter" => {
 | 
			
		||||
                                                    if event.shift_key() {
 | 
			
		||||
                                                        state.selection.update(|sel| {
 | 
			
		||||
                                                            if !sel.remove(&key) {
 | 
			
		||||
                                                                sel.insert(key);
 | 
			
		||||
                                                            }
 | 
			
		||||
                                                        });
 | 
			
		||||
                                                    } else {
 | 
			
		||||
                                                        state.selection.update(|sel| {
 | 
			
		||||
                                                            sel.clear();
 | 
			
		||||
                                                            sel.insert(key);
 | 
			
		||||
                                                        });
 | 
			
		||||
                                                    }
 | 
			
		||||
                                                    event.prevent_default();
 | 
			
		||||
                                                },
 | 
			
		||||
                                                "ArrowRight" if constrained => {
 | 
			
		||||
                                                    let _ = details_node
 | 
			
		||||
                                                        .get()
 | 
			
		||||
                                                        .unchecked_into::<Element>()
 | 
			
		||||
                                                        .set_attribute("open", "");
 | 
			
		||||
                                                },
 | 
			
		||||
                                                "ArrowLeft" => {
 | 
			
		||||
                                                    let _ = details_node
 | 
			
		||||
                                                        .get()
 | 
			
		||||
                                                        .unchecked_into::<Element>()
 | 
			
		||||
                                                        .remove_attribute("open");
 | 
			
		||||
                                                },
 | 
			
		||||
                                                _ => ()
 | 
			
		||||
                                            }
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                ) {
 | 
			
		||||
                                    div(
 | 
			
		||||
                                        class="elt-switch",
 | 
			
		||||
                                        on:click=|event: MouseEvent| event.stop_propagation()
 | 
			
		||||
                                    )
 | 
			
		||||
                                    div(
 | 
			
		||||
                                        class="elt",
 | 
			
		||||
                                        on:click={
 | 
			
		||||
                                            move |event: MouseEvent| {
 | 
			
		||||
                                                if event.shift_key() {
 | 
			
		||||
                                                    state.selection.update(|sel| {
 | 
			
		||||
                                                        if !sel.remove(&key) {
 | 
			
		||||
                                                            sel.insert(key);
 | 
			
		||||
                                                        }
 | 
			
		||||
                                                    });
 | 
			
		||||
                                                } else {
 | 
			
		||||
                                                    state.selection.update(|sel| {
 | 
			
		||||
                                                        sel.clear();
 | 
			
		||||
                                                        sel.insert(key);
 | 
			
		||||
                                                    });
 | 
			
		||||
                                                }
 | 
			
		||||
                                                event.stop_propagation();
 | 
			
		||||
                                                event.prevent_default();
 | 
			
		||||
                                            }
 | 
			
		||||
                                        }
 | 
			
		||||
                                    ) {
 | 
			
		||||
                                        div(class="elt-label") { (label) }
 | 
			
		||||
                                        div(class="elt-rep") { (rep_components) }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                ul(class="constraints") {
 | 
			
		||||
                                    Keyed(
 | 
			
		||||
                                        list=elt.constraints.into_iter().collect::<Vec<_>>(),
 | 
			
		||||
                                        view=move |cst_key| view! {
 | 
			
		||||
                                            ConstraintOutlineItem(
 | 
			
		||||
                                                constraint_key=cst_key,
 | 
			
		||||
                                                element_key=key
 | 
			
		||||
                                            )
 | 
			
		||||
                                        },
 | 
			
		||||
                                        key=|cst_key| cst_key.clone()
 | 
			
		||||
                                    )
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                view=|(key, elt)| view! {
 | 
			
		||||
                    ElementOutlineItem(key=key, element=elt)
 | 
			
		||||
                },
 | 
			
		||||
                key=|(key, elt)| (
 | 
			
		||||
                    key.clone(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue