diff --git a/Cargo.lock b/Cargo.lock
index 9d81cbf2..4068d3fb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1477,7 +1477,7 @@ dependencies = [
[[package]]
name = "egui_tabs"
version = "0.2.1"
-source = "git+https://github.com/damus-io/egui-tabs?rev=881d86bdf8b424563bf0869eaab5ab9a69e012a4#881d86bdf8b424563bf0869eaab5ab9a69e012a4"
+source = "git+https://github.com/damus-io/egui-tabs?rev=6eb91740577b374a8a6658c09c9a4181299734d0#6eb91740577b374a8a6658c09c9a4181299734d0"
dependencies = [
"egui",
"egui_extras",
@@ -3198,6 +3198,7 @@ dependencies = [
"egui",
"egui-winit",
"egui_extras",
+ "egui_tabs",
"nostrdb",
"notedeck",
"notedeck_columns",
diff --git a/Cargo.toml b/Cargo.toml
index b6eeab35..4f58fa8c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,7 +24,7 @@ egui-wgpu = "0.31.1"
egui_extras = { version = "0.31.1", features = ["all_loaders"] }
egui-winit = { version = "0.31.1", features = ["android-game-activity", "clipboard"] }
egui_nav = { git = "https://github.com/damus-io/egui-nav", rev = "0f0cbdd3184f3ff5fdf69ada08416ffc58a70d7a" }
-egui_tabs = { git = "https://github.com/damus-io/egui-tabs", rev = "881d86bdf8b424563bf0869eaab5ab9a69e012a4" }
+egui_tabs = { git = "https://github.com/damus-io/egui-tabs", rev = "6eb91740577b374a8a6658c09c9a4181299734d0" }
#egui_virtual_list = "0.6.0"
egui_virtual_list = { git = "https://github.com/jb55/hello_egui", rev = "a66b6794f5e707a2f4109633770e02b02fb722e1" }
ehttp = "0.5.0"
diff --git a/assets/icons/home-toolbar.png b/assets/icons/home-toolbar.png
new file mode 100644
index 00000000..1e636e5e
Binary files /dev/null and b/assets/icons/home-toolbar.png differ
diff --git a/assets/icons/home-toolbar.svg b/assets/icons/home-toolbar.svg
new file mode 100644
index 00000000..5adf9664
--- /dev/null
+++ b/assets/icons/home-toolbar.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/notifications.svg b/assets/icons/notifications.svg
new file mode 100644
index 00000000..f56d4b3a
--- /dev/null
+++ b/assets/icons/notifications.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/notifications_dark_4x.png b/assets/icons/notifications_dark_4x.png
new file mode 100644
index 00000000..1a45b96f
Binary files /dev/null and b/assets/icons/notifications_dark_4x.png differ
diff --git a/crates/notedeck_chrome/Cargo.toml b/crates/notedeck_chrome/Cargo.toml
index 6dac8b07..be2a8a86 100644
--- a/crates/notedeck_chrome/Cargo.toml
+++ b/crates/notedeck_chrome/Cargo.toml
@@ -10,6 +10,7 @@ description = "The nostr browser"
[dependencies]
eframe = { workspace = true }
+egui_tabs = { workspace = true }
egui_extras = { workspace = true }
egui = { workspace = true }
notedeck_columns = { workspace = true }
diff --git a/crates/notedeck_chrome/src/chrome.rs b/crates/notedeck_chrome/src/chrome.rs
index 37638b2f..a1c6c1f9 100644
--- a/crates/notedeck_chrome/src/chrome.rs
+++ b/crates/notedeck_chrome/src/chrome.rs
@@ -2,12 +2,12 @@
//#[cfg(target_arch = "wasm32")]
//use wasm_bindgen::prelude::*;
use crate::app::NotedeckApp;
-use egui::{Button, Label, Layout, RichText, ThemePreference, Widget, vec2};
+use egui::{vec2, Button, Label, Layout, Rect, RichText, ThemePreference, Widget};
use egui_extras::{Size, StripBuilder};
use nostrdb::{ProfileRecord, Transaction};
use notedeck::{
- App, AppAction, AppContext, NotedeckTextStyle, UserAccount, WalletType,
- profile::get_profile_url,
+ profile::get_profile_url, App, AppAction, AppContext, NotedeckTextStyle, UserAccount,
+ WalletType,
};
use notedeck_columns::Damus;
use notedeck_dave::{Dave, DaveAvatar};
@@ -19,6 +19,7 @@ pub static ICON_EXPANSION_MULTIPLE: f32 = 1.2;
pub struct Chrome {
active: i32,
open: bool,
+ tab_selected: i32,
apps: Vec,
}
@@ -26,17 +27,25 @@ impl Default for Chrome {
fn default() -> Self {
Self {
active: 0,
+ tab_selected: 0,
open: true,
apps: vec![],
}
}
}
+pub enum ToolbarAction {
+ Notifications,
+ Dave,
+ Home,
+}
+
pub enum ChromePanelAction {
Support,
Settings,
Account,
Wallet,
+ Toolbar(ToolbarAction),
SaveTheme(ThemePreference),
}
@@ -67,6 +76,10 @@ impl ChromePanelAction {
ctx.theme.save(*theme);
}
+ Self::Toolbar(_toolbar_action) => {
+ tracing::info!("toolbar action");
+ }
+
Self::Support => {
Self::columns_navigate(ctx, chrome, notedeck_columns::Route::Support);
}
@@ -135,21 +148,16 @@ impl Chrome {
self.active = app;
}
- /// Show the side menu or bar, depending on if we're on a narrow
- /// or wide screen.
- ///
- /// The side menu should hover over the screen, while the side bar
- /// is collapsible but persistent on the screen.
- fn show(&mut self, ctx: &mut AppContext, ui: &mut egui::Ui) -> Option {
- ui.spacing_mut().item_spacing.x = 0.0;
-
+ /// The chrome side panel
+ fn panel(
+ &mut self,
+ app_ctx: &mut AppContext,
+ builder: StripBuilder,
+ amt_open: f32,
+ ) -> Option {
let mut got_action: Option = None;
- let side_panel_width: f32 = 70.0;
- let open_id = egui::Id::new("chrome_open");
- let amt_open = ui.ctx().animate_bool(open_id, self.open) * side_panel_width;
-
- StripBuilder::new(ui)
+ builder
.size(Size::exact(amt_open)) // collapsible sidebar
.size(Size::remainder()) // the main app contents
.clip(true)
@@ -172,7 +180,7 @@ impl Chrome {
});
ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
- if let Some(action) = bottomup_sidebar(ctx, ui) {
+ if let Some(action) = bottomup_sidebar(app_ctx, ui) {
got_action = Some(action);
}
});
@@ -197,8 +205,8 @@ impl Chrome {
);
*/
- if let Some(action) = self.apps[self.active as usize].update(ctx, ui) {
- chrome_handle_app_action(self, ctx, action, ui);
+ if let Some(action) = self.apps[self.active as usize].update(app_ctx, ui) {
+ chrome_handle_app_action(self, app_ctx, action, ui);
}
});
});
@@ -206,6 +214,90 @@ impl Chrome {
got_action
}
+ /// 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 = 70.0;
+ ui.ctx().animate_bool(open_id, self.open) * side_panel_width
+ }
+
+ fn toolbar_height() -> f32 {
+ 60.0
+ }
+
+ /// On narrow layouts, we have a toolbar
+ fn toolbar_chrome(
+ &mut self,
+ ctx: &mut AppContext,
+ ui: &mut egui::Ui,
+ ) -> Option {
+ let mut got_action: Option = None;
+ let amt_open = self.amount_open(ui);
+
+ StripBuilder::new(ui)
+ .size(Size::remainder()) // top cell
+ .size(Size::exact(Self::toolbar_height())) // bottom cell
+ .vertical(|mut strip| {
+ strip.strip(|builder| {
+ // the chrome panel is nested above the toolbar
+
+ got_action = self.panel(ctx, builder, amt_open);
+ });
+
+ strip.cell(|ui| {
+ if let Some(action) = self.toolbar(ui) {
+ got_action = Some(ChromePanelAction::Toolbar(action))
+ }
+ });
+ });
+
+ got_action
+ }
+
+ fn toolbar(&mut self, ui: &mut egui::Ui) -> Option {
+ let _tab_res = egui_tabs::Tabs::new(3)
+ .selected(self.tab_selected)
+ //.hover_bg(TabColor::none())
+ //.selected_fg(TabColor::none())
+ //.selected_bg(TabColor::none())
+ //.hover_bg(TabColor::none())
+ //.hover_bg(TabColor::custom(egui::Color32::RED))
+ .height(Self::toolbar_height())
+ .layout(Layout::centered_and_justified(egui::Direction::TopDown))
+ .show(ui, |ui, state| {
+ let index = state.index();
+
+ if index == 0 {
+ home_button(ui);
+ } else if index == 1 {
+ if let Some(dave) = self.get_dave() {
+ let rect = dave_toolbar_rect(ui);
+ let _dave_resp = dave_button(dave.avatar_mut(), ui, rect);
+ }
+ } else if index == 2 {
+ notifications_button(ui);
+ }
+ });
+
+ None
+ }
+
+ /// Show the side menu or bar, depending on if we're on a narrow
+ /// or wide screen.
+ ///
+ /// The side menu should hover over the screen, while the side bar
+ /// is collapsible but persistent on the screen.
+ fn show(&mut self, ctx: &mut AppContext, ui: &mut egui::Ui) -> Option {
+ ui.spacing_mut().item_spacing.x = 0.0;
+
+ if notedeck::ui::is_narrow(ui.ctx()) {
+ self.toolbar_chrome(ctx, ui)
+ } else {
+ let amt_open = self.amount_open(ui);
+ self.panel(ctx, StripBuilder::new(ui), amt_open)
+ }
+ }
+
fn topdown_sidebar(&mut self, ui: &mut egui::Ui) {
// macos needs a bit of space to make room for window
// minimize/close buttons
@@ -236,7 +328,8 @@ impl Chrome {
ui.add_space(32.0);
if let Some(dave) = self.get_dave() {
- let dave_resp = dave_button(dave.avatar_mut(), ui);
+ let rect = dave_sidebar_rect(ui);
+ let dave_resp = dave_button(dave.avatar_mut(), ui, rect);
if dave_resp.clicked() {
self.active = 1;
} else if dave_resp.hovered() {
@@ -340,17 +433,49 @@ fn settings_button(ui: &mut egui::Ui) -> egui::Response {
)
}
+fn notifications_button(ui: &mut egui::Ui) -> egui::Response {
+ expanding_button(
+ "notifications-button",
+ 24.0,
+ &egui::include_image!("../../../assets/icons/notifications_dark_4x.png"),
+ &egui::include_image!("../../../assets/icons/notifications_dark_4x.png"),
+ ui,
+ )
+}
+
+fn home_button(ui: &mut egui::Ui) -> egui::Response {
+ expanding_button(
+ "home-button",
+ 24.0,
+ &egui::include_image!("../../../assets/icons/home-toolbar.png"),
+ &egui::include_image!("../../../assets/icons/home-toolbar.png"),
+ ui,
+ )
+}
+
fn columns_button(ui: &mut egui::Ui) -> egui::Response {
let btn = egui::include_image!("../../../assets/icons/columns_80.png");
expanding_button("columns-button", 40.0, &btn, &btn, ui)
}
-fn dave_button(avatar: Option<&mut DaveAvatar>, ui: &mut egui::Ui) -> egui::Response {
+fn dave_sidebar_rect(ui: &mut egui::Ui) -> Rect {
+ let size = vec2(60.0, 60.0);
+ let available = ui.available_rect_before_wrap();
+ let center_x = available.center().x;
+ let center_y = available.top();
+ egui::Rect::from_center_size(egui::pos2(center_x, center_y), size)
+}
+
+fn dave_toolbar_rect(ui: &mut egui::Ui) -> Rect {
+ let size = vec2(60.0, 60.0);
+ let available = ui.available_rect_before_wrap();
+ let center_x = available.center().x;
+ let center_y = available.center().y;
+ egui::Rect::from_center_size(egui::pos2(center_x, center_y), size)
+}
+
+fn dave_button(avatar: Option<&mut DaveAvatar>, ui: &mut egui::Ui, rect: Rect) -> egui::Response {
if let Some(avatar) = avatar {
- let size = vec2(60.0, 60.0);
- let available = ui.available_rect_before_wrap();
- let center_x = available.center().x;
- let rect = egui::Rect::from_center_size(egui::pos2(center_x, available.top()), size);
avatar.render(rect, ui)
} else {
// plain icon if wgpu device not available??