notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 9ff12cc11abca0e570414e0f7624ff4b0d3ea1be
parent 65b7cfec94ac1bb03431cda4c6956084b1e01e3b
Author: kernelkind <kernelkind@gmail.com>
Date:   Sun, 28 Sep 2025 22:16:34 -0400

render chrome nav drawer

Signed-off-by: kernelkind <kernelkind@gmail.com>

Diffstat:
Mcrates/notedeck_chrome/src/chrome.rs | 153++++++++++++++++++++++++++++++++++++-------------------------------------------
1 file changed, 70 insertions(+), 83 deletions(-)

diff --git a/crates/notedeck_chrome/src/chrome.rs b/crates/notedeck_chrome/src/chrome.rs @@ -5,10 +5,15 @@ use crate::app::NotedeckApp; use crate::ChromeOptions; use bitflags::bitflags; use eframe::CreationContext; -use egui::{vec2, Button, Color32, Label, Layout, Rect, RichText, ThemePreference, Widget}; +use egui::{ + vec2, Button, Color32, CornerRadius, Label, Layout, Rect, RichText, ThemePreference, Widget, +}; use egui_extras::{Size, StripBuilder}; +use egui_nav::RouteResponse; +use egui_nav::{NavAction, NavDrawer}; use nostrdb::{ProfileRecord, Transaction}; use notedeck::AppResponse; +use notedeck::DrawerRouter; use notedeck::Error; use notedeck::SoftKeyboardContext; use notedeck::{ @@ -32,6 +37,13 @@ pub struct Chrome { soft_kb_anim_state: AnimState, pub repaint_causes: HashMap<egui::RepaintCause, u64>, + nav: DrawerRouter, +} + +#[derive(Clone)] +enum ChromeRoute { + Chrome, + App, } pub enum ChromePanelAction { @@ -186,94 +198,68 @@ impl Chrome { fn panel( &mut self, app_ctx: &mut AppContext, - builder: StripBuilder, - amt_open: f32, + ui: &mut egui::Ui, amt_keyboard_open: f32, ) -> Option<ChromePanelAction> { - let mut got_action: Option<ChromePanelAction> = None; - - builder - .size(Size::exact(amt_open)) // collapsible sidebar - .size(Size::remainder()) // the main app contents - .clip(true) - .horizontal(|mut hstrip| { - hstrip.cell(|ui| { - let rect = ui.available_rect_before_wrap(); - if !ui.visuals().dark_mode { - let rect = ui.available_rect_before_wrap(); - ui.painter().rect( - rect, - 0, - notedeck_ui::colors::ALMOST_WHITE, - egui::Stroke::new(0.0, Color32::TRANSPARENT), - egui::StrokeKind::Inside, - ); - } - - StripBuilder::new(ui) - .size(Size::remainder()) - .size(Size::remainder()) - .vertical(|mut vstrip| { - vstrip.cell(|ui| { - _ = ui.vertical_centered(|ui| { - self.topdown_sidebar(ui, app_ctx.i18n); - }) - }); - - vstrip.cell(|ui| { - ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| { - let options = if amt_keyboard_open > 0.0 { - SidebarOptions::Compact - } else { - SidebarOptions::default() - }; - if let Some(action) = - bottomup_sidebar(self, app_ctx, ui, options) - { - got_action = Some(action); - } - }); - }); - }); - - // vertical sidebar line - ui.painter().vline( - rect.right(), - rect.y_range(), - ui.visuals().widgets.noninteractive.bg_stroke, - ); + let drawer = NavDrawer::new(&ChromeRoute::App, &ChromeRoute::Chrome) + .navigating(self.nav.navigating) + .returning(self.nav.returning) + .drawer_focused(self.nav.drawer_focused) + .opened_offset(100.0); + + let resp = drawer.show_mut(ui, |ui, route| match route { + ChromeRoute::Chrome => { + ui.painter().rect_filled( + ui.available_rect_before_wrap(), + CornerRadius::ZERO, + ui.visuals().panel_fill, + ); + _ = ui.vertical_centered(|ui| { + self.topdown_sidebar(ui, app_ctx.i18n); }); - hstrip.cell(|ui| { - /* - let rect = ui.available_rect_before_wrap(); - ui.painter().rect( - rect, - 0, - egui::Color32::RED, - egui::Stroke::new(1.0, egui::Color32::BLUE), - egui::StrokeKind::Inside, - ); - */ - - let resp = self.apps[self.active as usize].update(app_ctx, ui); - if let Some(action) = resp.action { - chrome_handle_app_action(self, app_ctx, action, ui); + ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| { + let options = if amt_keyboard_open > 0.0 { + SidebarOptions::Compact + } else { + SidebarOptions::default() + }; + let response = bottomup_sidebar(self, app_ctx, ui, options); + + RouteResponse { + response, + can_take_drag_from: Vec::new(), } - }); - }); + }) + .inner + } + ChromeRoute::App => { + let resp = self.apps[self.active as usize].update(app_ctx, ui); - got_action - } + if let Some(action) = resp.action { + chrome_handle_app_action(self, app_ctx, action, ui); + } - /// How far is the chrome panel expanded? - fn amount_open(&self, ui: &mut egui::Ui) -> f32 { - let open_id = egui::Id::new("chrome_open"); - let side_panel_width: f32 = 74.0; - ui.ctx() - .animate_bool(open_id, self.options.contains(ChromeOptions::IsOpen)) - * side_panel_width + RouteResponse { + response: None, + can_take_drag_from: resp.can_take_drag_from, + } + } + }); + + if let Some(action) = resp.action { + if matches!(action, NavAction::Returned(_)) { + self.nav.closed(); + } else if let NavAction::Navigating = action { + self.nav.navigating = false; + } else if let NavAction::Navigated = action { + self.nav.opened(); + } + } + + resp.drawer_response? } + /// Show the side menu or bar, depending on if we're on a narrow /// or wide screen. /// @@ -282,7 +268,6 @@ impl Chrome { fn show(&mut self, ctx: &mut AppContext, ui: &mut egui::Ui) -> Option<ChromePanelAction> { ui.spacing_mut().item_spacing.x = 0.0; - let amt_open = self.amount_open(ui); let skb_anim = keyboard_visibility(ui, ctx, &mut self.options, &mut self.soft_kb_anim_state); @@ -302,7 +287,7 @@ impl Chrome { .vertical(|mut strip| { // the actual content, shifted up because of the soft keyboard strip.cell(|ui| { - action = self.panel(ctx, StripBuilder::new(ui), amt_open, keyboard_height); + action = self.panel(ctx, ui, keyboard_height); }); // the filler space taken up by the soft keyboard @@ -374,6 +359,7 @@ impl Chrome { if r.on_hover_cursor(egui::CursorIcon::PointingHand).clicked() { self.active = i as i32; + self.nav.close(); } } } @@ -383,6 +369,7 @@ impl notedeck::App for Chrome { fn update(&mut self, ctx: &mut notedeck::AppContext, ui: &mut egui::Ui) -> AppResponse { if let Some(action) = self.show(ctx, ui) { action.process(ctx, self, ui); + self.nav.close(); } // TODO: unify this constant with the columns side panel width. ui crate? AppResponse::none()