diff --git a/Cargo.lock b/Cargo.lock index 01fc023..e226011 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -151,7 +151,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -272,7 +272,7 @@ checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -480,7 +480,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.107", "version_check", ] @@ -497,18 +497,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -549,6 +549,12 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "ryu" version = "1.0.12" @@ -583,7 +589,7 @@ checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -633,6 +639,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "thiserror" version = "1.0.38" @@ -650,7 +667,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -725,26 +742,14 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" dependencies = [ "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", "once_cell", - "proc-macro2", - "quote", - "syn", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] @@ -762,9 +767,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -772,22 +777,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn", - "wasm-bindgen-backend", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" diff --git a/src/algo/calendar_tree.rs b/src/algo/calendar_tree.rs index 82ef235..69946e4 100644 --- a/src/algo/calendar_tree.rs +++ b/src/algo/calendar_tree.rs @@ -3,7 +3,10 @@ use crate::prelude::*; #[derive(Debug, Clone)] pub struct FlattenedCalendarBlock { pub block: CalendarBlock, + /// The block's distance from the root pub stack_position: usize, + /// Height of the block's cluster (deepest leaf node to subtree parent) + pub cluster_height: usize, } pub struct CalendarBlockTree { @@ -42,18 +45,6 @@ impl CalendarBlockTree { block: CalendarBlock, destination: Option, ) -> Result<(), Box> { - // Recursive Add - // 1. find overlaps - // if no overlap - // add edge from destination to new block - // return - // else if new block gets swallowed - // call add with new destination - // TODO:else - // add edge from destination to new block - // add edges from new block to overlapping blocks - // remove edges from destination to overlapping blocks - let destination = destination.unwrap_or(self.root_idx); let mut forward_neighbors = self @@ -112,17 +103,17 @@ impl CalendarBlockTree { } pub fn traverse(&self) -> Vec { - let mut traversal_queue: VecDeque<(NodeIndex, usize)> = + let mut traversal_queue: VecDeque<(NodeIndex, usize, usize)> = VecDeque::with_capacity(self.id_to_block_map.iter().len()); - let mut buffer: Vec<(NodeIndex, usize)> = + let mut buffer: Vec<(NodeIndex, usize, usize)> = Vec::with_capacity(self.id_to_block_map.iter().len()); - traversal_queue.push_back((self.root_idx, 0)); + traversal_queue.push_back((self.root_idx, 0, 0)); while !traversal_queue.is_empty() { - let (node_idx, stack_position) = traversal_queue.pop_front().unwrap(); - buffer.push((node_idx, stack_position)); + let (node_idx, stack_position, cluster_height) = traversal_queue.pop_front().unwrap(); + buffer.push((node_idx, stack_position, cluster_height)); let forward_neighbors = self .adjacency @@ -130,18 +121,25 @@ impl CalendarBlockTree { .map(|e| e.target()); forward_neighbors.for_each(|n| { - traversal_queue.push_back((n, stack_position + 1)); + let child_cluster_height = if stack_position == 0 { + let block_id = self.adjacency[n]; + 1 + self.id_to_block_map.get(&block_id).unwrap().subtree_depth + } else { + cluster_height + }; + traversal_queue.push_back((n, stack_position + 1, child_cluster_height)); }); } buffer .iter() - .map(|(node_idx, stack_position)| { + .map(|(node_idx, stack_position, cluster_height)| { let current_block_id = self.adjacency[*node_idx]; let current_block = self.id_to_block_map.get(¤t_block_id).unwrap(); FlattenedCalendarBlock { block: current_block.clone(), stack_position: *stack_position, + cluster_height: *cluster_height, } }) .collect() diff --git a/src/components/calendar.rs b/src/components/calendar.rs index 473f4b9..b709c7e 100644 --- a/src/components/calendar.rs +++ b/src/components/calendar.rs @@ -14,7 +14,7 @@ fn get_time_from_minutes(minutes: u32) -> String { } #[allow(non_snake_case)] -pub fn Calendar<'app>(cx: Scope<'app, CalendarProps<'app>>) -> Element { +pub fn Calendar<'app>(cx: Scope<'app, CalendarProps<'app>>) -> Element<'app> { let ghost_block_top = use_state(&cx, || 0_f64); let click_offset = use_state(&cx, || 0_f64); let dragged_block = use_state(&cx, || None::); @@ -104,7 +104,7 @@ pub fn Calendar<'app>(cx: Scope<'app, CalendarProps<'app>>) -> Element { None => rsx!(empty_element::EmptyElement {}), }; - return cx.render(rsx! { + cx.render(rsx! { button { class: "btn", onclick: move |_| { @@ -129,7 +129,14 @@ pub fn Calendar<'app>(cx: Scope<'app, CalendarProps<'app>>) -> Element { }; let (left, width) = match use_subtree_depth_algorithm.get() { - true => get_subtree_depth_transforms(flattened_block.stack_position, flattened_block.block.subtree_depth), + true => { + let height = flattened_block.cluster_height as f64; + get_subtree_depth_transforms( + (flattened_block.stack_position as f64 - 1.0) / height, + 1.0 / height, + flattened_block.block.subtree_depth == 0, + ) + }, false => get_position_offsets(flattened_block.stack_position) }; let top = format!("{}px", flattened_block.block.start_minute); @@ -142,7 +149,7 @@ pub fn Calendar<'app>(cx: Scope<'app, CalendarProps<'app>>) -> Element { let id = flattened_block.block.id; let block_type = flattened_block.block.block_type; - return rsx!(calendar_block::CalendarBlockListItem { + rsx!(calendar_block::CalendarBlockListItem { key: "{id}", left: left, top: top, @@ -157,11 +164,11 @@ pub fn Calendar<'app>(cx: Scope<'app, CalendarProps<'app>>) -> Element { click_offset.set(evt.client_y as f64 - flattened_block.block.start_minute as f64); }, onmouseup: handle_move_calendar_block, - }); + }) } ) rsx!(ghost_block) } } - }); + }) } diff --git a/src/components/calendar_block.rs b/src/components/calendar_block.rs index 2fbf33e..349bfba 100644 --- a/src/components/calendar_block.rs +++ b/src/components/calendar_block.rs @@ -18,7 +18,7 @@ pub struct CalendarBlockListItemProps<'block> { #[allow(non_snake_case)] pub fn CalendarBlockListItem<'block>( cx: Scope<'block, CalendarBlockListItemProps<'block>>, -) -> Element { +) -> Element<'block> { let block_type_class = match cx.props.block_type { CalendarBlockType::Wrapper => "wrapper", CalendarBlockType::Busy => "busy", @@ -29,7 +29,7 @@ pub fn CalendarBlockListItem<'block>( None => "".to_string(), }; - return cx.render(rsx!(div { + cx.render(rsx!(div { class: "absolute calendar-block {block_type_class} {classes}", title: "{cx.props.label}", top: "{cx.props.top}", @@ -49,5 +49,5 @@ pub fn CalendarBlockListItem<'block>( } }, "{cx.props.label}" - })); + })) } diff --git a/src/components/calendar_block_list.rs b/src/components/calendar_block_list.rs deleted file mode 100644 index af0efd9..0000000 --- a/src/components/calendar_block_list.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::prelude::*; - -#[derive(Props, PartialEq)] -pub struct CalendarBlockListProps { - flattened_blocks: Vec, -} - -#[allow(non_snake_case)] -pub fn CalendarBlockList(cx: Scope) -> Element { - return cx.render(rsx!(div { - class: "calendar flex noselect", - cx.props.flattened_blocks.iter().map(move |flattened_block| - rsx!(calendar_block::CalendarBlockListItem { - calendar_block: flattened_block.block, - stack_position: flattened_block.stack_position, - }) - ) - })); -} diff --git a/src/get_position_offsets.rs b/src/get_position_offsets.rs index c688742..c71cd5c 100644 --- a/src/get_position_offsets.rs +++ b/src/get_position_offsets.rs @@ -14,27 +14,29 @@ pub fn get_position_offsets(stack_position: usize) -> (String, String) { } } +/// Returns the CSS `transform` offsets for a block. +/// +/// The block's left edge as a fraction of the container +/// left_fraction: f64, +/// One column's width as a fraction of the container +/// column_fraction: f64, +/// Whether the block is a leaf (i.e., spans the full container width) +/// is_leaf: bool, +/// pub fn get_subtree_depth_transforms( - stack_position: usize, - subtree_depth: usize, + left_fraction: f64, + column_fraction: f64, + is_leaf: bool, ) -> (String, String) { - let stack_position = stack_position as f64; - let subtree_depth = subtree_depth as f64; - - let width_divisor = stack_position + subtree_depth; + let width = match is_leaf { + // leaf: fill from its own left edge to the container's right edge + true => 1.0 - left_fraction, + // non-leaf: one column plus a half-column overlap into its child + false => 1.5 * column_fraction, + }; - match stack_position < 1.0 { - true => (0.to_string(), MAX_COL_WIDTH.to_string()), - false => { - let width = match subtree_depth > 0.0 { - true => 1.8 / width_divisor, - false => 1.0 / width_divisor, - }; - - ( - format!("calc(100% * {})", (stack_position - 1.0) / width_divisor), - format!("calc(100% * {width})"), - ) - } - } + ( + format!("calc(100% * {left_fraction})"), + format!("calc(100% * {width})"), + ) } diff --git a/src/main.rs b/src/main.rs index 952c231..7f9c7be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,12 +12,11 @@ mod prelude { pub use core::fmt; pub use dioxus::events::MouseEvent; pub use dioxus::prelude::*; - pub use log::{info, Level}; + pub use log::info; pub use petgraph::dot::Dot; pub use petgraph::graph::{Graph, NodeIndex}; pub use petgraph::visit::EdgeRef; - pub use serde::Deserialize; - pub use thiserror::Error; + pub use uuid::Uuid; pub use crate::algo::calendar_block::*;