WIP: Clean up the outline view #16
@ -1,7 +1,6 @@
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use sycamore::{prelude::*, web::tags::div};
|
use sycamore::{prelude::*, web::tags::div};
|
||||||
use web_sys::{
|
use web_sys::{
|
||||||
Element,
|
|
||||||
Event,
|
Event,
|
||||||
HtmlInputElement,
|
HtmlInputElement,
|
||||||
KeyboardEvent,
|
KeyboardEvent,
|
||||||
@ -9,7 +8,7 @@ use web_sys::{
|
|||||||
wasm_bindgen::JsCast
|
wasm_bindgen::JsCast
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{AppState, assembly::Constraint};
|
use crate::{AppState, assembly, assembly::Constraint};
|
||||||
|
|
||||||
// an editable view of the Lorentz product representing a constraint
|
// an editable view of the Lorentz product representing a constraint
|
||||||
#[component(inline_props)]
|
#[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
|
// a component that lists the elements of the current assembly, showing the
|
||||||
// constraints on each element as a collapsible sub-list. its implementation
|
// constraints on each element as a collapsible sub-list. its implementation
|
||||||
// is based on Kate Morley's HTML + CSS tree views:
|
// is based on Kate Morley's HTML + CSS tree views:
|
||||||
@ -81,108 +186,8 @@ pub fn Outline() -> View {
|
|||||||
) {
|
) {
|
||||||
Keyed(
|
Keyed(
|
||||||
list=elements_sorted,
|
list=elements_sorted,
|
||||||
view=|(key, elt)| {
|
view=|(key, elt)| view! {
|
||||||
let state = use_context::<AppState>();
|
ElementOutlineItem(key=key, element=elt)
|
||||||
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()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
key=|(key, elt)| (
|
key=|(key, elt)| (
|
||||||
key.clone(),
|
key.clone(),
|
||||||
|
Loading…
Reference in New Issue
Block a user