diff --git a/CHANGELOG.md b/CHANGELOG.md index 2113a16..a8a291a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/), and the project adheres to [Semantic Versioning](https://semver.org/). +## [0.1.13] - 2026-07-29 + +### Changed +- Viewer: the app frame is now viewport-bounded (`body` uses a fixed + `100vh`/`100dvh` height instead of `min-height`), so a long tree-mode node + list scrolls inside its own map pane instead of growing the whole page — + previously a 100+-node artifact in tree mode stretched the page to several + thousand pixels and scrolled the header away. +- Viewer: the default layout is now `split` (map left, detail right) and the + default display is now `tree`, so the exploration trajectory reads + top-to-bottom in a fixed, independently scrollable left pane on first load. + `stack` and `graph` remain available from the toolbar; unknown mode tokens + now fall back to the new defaults. + ## [0.1.12] - 2026-07-25 ### Added diff --git a/Cargo.lock b/Cargo.lock index 0e6e355..87f6b99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,7 +125,7 @@ checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "ara-cli" -version = "0.1.12" +version = "0.1.13" dependencies = [ "ara-core", "arc-swap", @@ -148,7 +148,7 @@ dependencies = [ [[package]] name = "ara-core" -version = "0.1.12" +version = "0.1.13" dependencies = [ "dagre-dgl-rs", "insta", @@ -160,7 +160,7 @@ dependencies = [ [[package]] name = "ara-viewer" -version = "0.1.12" +version = "0.1.13" dependencies = [ "ara-core", "console_error_panic_hook", @@ -178,7 +178,7 @@ dependencies = [ [[package]] name = "ara-wasm" -version = "0.1.12" +version = "0.1.13" [[package]] name = "arc-swap" diff --git a/Cargo.toml b/Cargo.toml index f3bff8b..7f53268 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "3" members = ["crates/*"] [workspace.package] -version = "0.1.12" +version = "0.1.13" edition = "2024" license = "MPL-2.0" repository = "https://github.com/ARA-Labs/ara-cli" diff --git a/crates/ara-cli/assets/viewer.source-hash b/crates/ara-cli/assets/viewer.source-hash index 81e30ef..0effda8 100644 --- a/crates/ara-cli/assets/viewer.source-hash +++ b/crates/ara-cli/assets/viewer.source-hash @@ -1 +1 @@ -154193f53a25f8cabb0fe326e0c14e578be5d3f7190bbd724c8399c6819224f5 +c8b4f3e3c84dbfd1b9f99cdc45dd3a24841d2e703a44d627c1ada9f8f42f9355 diff --git a/crates/ara-cli/assets/viewer/ara-viewer-1213ab1da86ce3ef_bg.wasm b/crates/ara-cli/assets/viewer/ara-viewer-1213ab1da86ce3ef_bg.wasm deleted file mode 100644 index 31965fa..0000000 Binary files a/crates/ara-cli/assets/viewer/ara-viewer-1213ab1da86ce3ef_bg.wasm and /dev/null differ diff --git a/crates/ara-cli/assets/viewer/ara-viewer-1213ab1da86ce3ef.js b/crates/ara-cli/assets/viewer/ara-viewer-ac78a8d0c42a85a9.js similarity index 100% rename from crates/ara-cli/assets/viewer/ara-viewer-1213ab1da86ce3ef.js rename to crates/ara-cli/assets/viewer/ara-viewer-ac78a8d0c42a85a9.js diff --git a/crates/ara-cli/assets/viewer/ara-viewer-ac78a8d0c42a85a9_bg.wasm b/crates/ara-cli/assets/viewer/ara-viewer-ac78a8d0c42a85a9_bg.wasm new file mode 100644 index 0000000..fddf27c Binary files /dev/null and b/crates/ara-cli/assets/viewer/ara-viewer-ac78a8d0c42a85a9_bg.wasm differ diff --git a/crates/ara-cli/assets/viewer/index.html b/crates/ara-cli/assets/viewer/index.html index cf18981..bf7779e 100644 --- a/crates/ara-cli/assets/viewer/index.html +++ b/crates/ara-cli/assets/viewer/index.html @@ -4,14 +4,14 @@ ARA Viewer - + - + diff --git a/crates/ara-cli/assets/viewer/styles-8e96cbefbbb65688.css b/crates/ara-cli/assets/viewer/styles-155177c35e1c149.css similarity index 99% rename from crates/ara-cli/assets/viewer/styles-8e96cbefbbb65688.css rename to crates/ara-cli/assets/viewer/styles-155177c35e1c149.css index 823371c..c78b056 100644 --- a/crates/ara-cli/assets/viewer/styles-8e96cbefbbb65688.css +++ b/crates/ara-cli/assets/viewer/styles-155177c35e1c149.css @@ -46,7 +46,12 @@ body { font-family: var(--font-body); font-size: 15px; line-height: 1.5; - min-height: 100vh; + /* Fixed app frame: the viewport bounds the page so each .panel scrolls + internally. With only a min-height, a tall tree-mode node list gives the + grid its content height and the whole page grows instead (dvh keeps the + frame correct under mobile browser toolbars; vh is the fallback). */ + height: 100vh; + height: 100dvh; display: flex; flex-direction: column; } diff --git a/crates/ara-viewer/public/styles.css b/crates/ara-viewer/public/styles.css index 823371c..c78b056 100644 --- a/crates/ara-viewer/public/styles.css +++ b/crates/ara-viewer/public/styles.css @@ -46,7 +46,12 @@ body { font-family: var(--font-body); font-size: 15px; line-height: 1.5; - min-height: 100vh; + /* Fixed app frame: the viewport bounds the page so each .panel scrolls + internally. With only a min-height, a tall tree-mode node list gives the + grid its content height and the whole page grows instead (dvh keeps the + frame correct under mobile browser toolbars; vh is the fallback). */ + height: 100vh; + height: 100dvh; display: flex; flex-direction: column; } diff --git a/crates/ara-viewer/src/lib.rs b/crates/ara-viewer/src/lib.rs index ef2661f..c48edd6 100644 --- a/crates/ara-viewer/src/lib.rs +++ b/crates/ara-viewer/src/lib.rs @@ -76,8 +76,8 @@ pub fn App() -> impl IntoView { let filter: RwSignal = RwSignal::new(FilterState::default()); // ── Layout mode (stack vs. split; survives manifest swaps) ──────────────── - // Stack (map on top, detail below) is the default — it matches the wide DAG - // shape and uses the full viewport width. Split is the opt-in side-by-side. + // Split (map left, detail right) is the default — the trajectory reads + // top-to-bottom beside the step detail. Stack is the opt-in full-width mode. let layout: RwSignal = RwSignal::new(LayoutMode::default()); // Per-mode split fractions (map fraction of the main axis). In-memory only; @@ -95,7 +95,7 @@ pub fn App() -> impl IntoView { }; // ── Display mode (graph vs. tree; survives manifest swaps) ──────────────── - // Graph (SVG DAG) is the default; Tree is the published DOM tree-list. + // Tree (the published DOM tree-list) is the default; Graph is the SVG DAG. let display: RwSignal = RwSignal::new(DisplayMode::default()); // ── Shared derived state (lifted into App — the single owner) ───────────── diff --git a/crates/ara-viewer/src/state.rs b/crates/ara-viewer/src/state.rs index a846545..54c3e4a 100644 --- a/crates/ara-viewer/src/state.rs +++ b/crates/ara-viewer/src/state.rs @@ -93,11 +93,12 @@ pub fn safe_viewbox(bounds: Option<&Rect>) -> (f64, f64, f64, f64) { #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum LayoutMode { /// Map on top (full viewport width), detail below — `grid-template-rows`. - /// The default: matches the naturally wide-and-short exploration DAG shape. - #[default] + /// Opt-in: suits a naturally wide-and-short exploration DAG. Stack, - /// Map left, detail right — `grid-template-columns`. The pre-issue-#9 - /// behaviour, kept as an opt-in mode. + /// Map left, detail right — `grid-template-columns`. The default: the + /// trajectory reads top-to-bottom on the left while the selected step's + /// detail stays beside it. + #[default] Split, } @@ -119,11 +120,11 @@ impl LayoutMode { } /// Parse a token back to a mode. Unknown input falls back to the default - /// (`Stack`) so a stale/garbage value can never wedge the layout. + /// (`Split`) so a stale/garbage value can never wedge the layout. pub fn from_token(s: &str) -> Self { match s { - "split" => LayoutMode::Split, - _ => LayoutMode::Stack, + "stack" => LayoutMode::Stack, + _ => LayoutMode::Split, } } } @@ -136,10 +137,11 @@ impl LayoutMode { /// `Copy` enum so it can live in a Leptos signal and be unit-tested on native. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum DisplayMode { - /// Today's interactive SVG DAG (pan/zoom). The default. - #[default] + /// The interactive SVG DAG (pan/zoom). Opt-in via the toolbar. Graph, - /// The published DOM indented tree-list. + /// The published DOM indented tree-list. The default: the full trajectory + /// scrolls vertically inside the map pane's own scroll range. + #[default] Tree, } @@ -162,11 +164,11 @@ impl DisplayMode { } /// Parse a token back to a mode. Unknown input falls back to the default - /// (`Graph`) so a stale/garbage value can never wedge the display. + /// (`Tree`) so a stale/garbage value can never wedge the display. pub fn from_token(s: &str) -> Self { match s { - "tree" => DisplayMode::Tree, - _ => DisplayMode::Graph, + "graph" => DisplayMode::Graph, + _ => DisplayMode::Tree, } } } @@ -345,8 +347,8 @@ mod tests { // ── LayoutMode ──────────────────────────────────────────────────────────── #[test] - fn layout_mode_default_is_stack() { - assert_eq!(LayoutMode::default(), LayoutMode::Stack); + fn layout_mode_default_is_split() { + assert_eq!(LayoutMode::default(), LayoutMode::Split); } #[test] @@ -363,16 +365,16 @@ mod tests { } #[test] - fn layout_mode_from_unknown_token_falls_back_to_stack() { - assert_eq!(LayoutMode::from_token(""), LayoutMode::Stack); - assert_eq!(LayoutMode::from_token("garbage"), LayoutMode::Stack); + fn layout_mode_from_unknown_token_falls_back_to_split() { + assert_eq!(LayoutMode::from_token(""), LayoutMode::Split); + assert_eq!(LayoutMode::from_token("garbage"), LayoutMode::Split); } // ── DisplayMode ─────────────────────────────────────────────────────────── #[test] - fn display_mode_default_is_graph() { - assert_eq!(DisplayMode::default(), DisplayMode::Graph); + fn display_mode_default_is_tree() { + assert_eq!(DisplayMode::default(), DisplayMode::Tree); } #[test] @@ -389,9 +391,9 @@ mod tests { } #[test] - fn display_mode_from_unknown_token_falls_back_to_graph() { - assert_eq!(DisplayMode::from_token(""), DisplayMode::Graph); - assert_eq!(DisplayMode::from_token("garbage"), DisplayMode::Graph); + fn display_mode_from_unknown_token_falls_back_to_tree() { + assert_eq!(DisplayMode::from_token(""), DisplayMode::Tree); + assert_eq!(DisplayMode::from_token("garbage"), DisplayMode::Tree); } // ── apply_manifest ────────────────────────────────────────────────────────