Initial tab bar
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -1477,7 +1477,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "egui_tabs"
|
name = "egui_tabs"
|
||||||
version = "0.2.1"
|
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 = [
|
dependencies = [
|
||||||
"egui",
|
"egui",
|
||||||
"egui_extras",
|
"egui_extras",
|
||||||
@@ -3198,6 +3198,7 @@ dependencies = [
|
|||||||
"egui",
|
"egui",
|
||||||
"egui-winit",
|
"egui-winit",
|
||||||
"egui_extras",
|
"egui_extras",
|
||||||
|
"egui_tabs",
|
||||||
"nostrdb",
|
"nostrdb",
|
||||||
"notedeck",
|
"notedeck",
|
||||||
"notedeck_columns",
|
"notedeck_columns",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ egui-wgpu = "0.31.1"
|
|||||||
egui_extras = { version = "0.31.1", features = ["all_loaders"] }
|
egui_extras = { version = "0.31.1", features = ["all_loaders"] }
|
||||||
egui-winit = { version = "0.31.1", features = ["android-game-activity", "clipboard"] }
|
egui-winit = { version = "0.31.1", features = ["android-game-activity", "clipboard"] }
|
||||||
egui_nav = { git = "https://github.com/damus-io/egui-nav", rev = "0f0cbdd3184f3ff5fdf69ada08416ffc58a70d7a" }
|
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 = "0.6.0"
|
||||||
egui_virtual_list = { git = "https://github.com/jb55/hello_egui", rev = "a66b6794f5e707a2f4109633770e02b02fb722e1" }
|
egui_virtual_list = { git = "https://github.com/jb55/hello_egui", rev = "a66b6794f5e707a2f4109633770e02b02fb722e1" }
|
||||||
ehttp = "0.5.0"
|
ehttp = "0.5.0"
|
||||||
|
|||||||
BIN
assets/icons/home-toolbar.png
Normal file
BIN
assets/icons/home-toolbar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
4
assets/icons/home-toolbar.svg
Normal file
4
assets/icons/home-toolbar.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path opacity="0.12" d="M6 14V8H10V14" fill="white"/>
|
||||||
|
<path d="M5.99992 14V9.06667C5.99992 8.69327 5.99992 8.5066 6.07259 8.364C6.1365 8.23853 6.23849 8.1366 6.36392 8.07267C6.50654 8 6.69325 8 7.06659 8H8.93325C9.30665 8 9.49332 8 9.63592 8.07267C9.76139 8.1366 9.86332 8.23853 9.92725 8.364C9.99992 8.5066 9.99992 8.69327 9.99992 9.06667V14M1.33325 6.33333L7.35992 1.81333C7.58945 1.64121 7.70419 1.55514 7.83019 1.52196C7.94145 1.49268 8.05838 1.49268 8.16965 1.52197C8.29565 1.55514 8.41038 1.64121 8.63992 1.81333L14.6666 6.33333M2.66659 5.33333V11.8667C2.66659 12.6134 2.66659 12.9868 2.81191 13.272C2.93975 13.5229 3.14372 13.7269 3.3946 13.8547C3.67982 14 4.05318 14 4.79992 14H11.1999C11.9467 14 12.3201 14 12.6053 13.8547C12.8561 13.7269 13.0601 13.5229 13.1879 13.272C13.3333 12.9868 13.3333 12.6134 13.3333 11.8667V5.33333L9.27992 2.29333C8.82092 1.94907 8.59138 1.77695 8.33932 1.71059C8.11685 1.65203 7.88298 1.65203 7.66052 1.71059C7.40845 1.77695 7.17892 1.94907 6.71992 2.29333L2.66659 5.33333Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
4
assets/icons/notifications.svg
Normal file
4
assets/icons/notifications.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path opacity="0.12" d="M12.0001 5.33337C12.0001 4.27251 11.5787 3.25509 10.8286 2.50495C10.0784 1.7548 9.06095 1.33337 8.00008 1.33337C6.93922 1.33337 5.92182 1.7548 5.17167 2.50495C4.42152 3.25509 4.0001 4.27251 4.0001 5.33337C4.0001 7.39351 3.48041 8.80404 2.89987 9.73697C2.41018 10.524 2.16534 10.9174 2.17431 11.0272C2.18426 11.1488 2.21 11.1951 2.30794 11.2678C2.3964 11.3334 2.79516 11.3334 3.59266 11.3334H12.4075C13.205 11.3334 13.6038 11.3334 13.6922 11.2678C13.7902 11.1951 13.8159 11.1488 13.8259 11.0272C13.8349 10.9174 13.59 10.524 13.1003 9.73697C12.5197 8.80404 12.0001 7.39351 12.0001 5.33337Z" fill="white"/>
|
||||||
|
<path d="M9.33342 14H6.66675M12.0001 5.33337C12.0001 4.27251 11.5787 3.25509 10.8286 2.50495C10.0784 1.7548 9.06095 1.33337 8.00008 1.33337C6.93922 1.33337 5.92182 1.7548 5.17167 2.50495C4.42152 3.25509 4.0001 4.27251 4.0001 5.33337C4.0001 7.39351 3.48041 8.80404 2.89987 9.73697C2.41018 10.524 2.16534 10.9174 2.17431 11.0272C2.18426 11.1488 2.21 11.1951 2.30794 11.2678C2.3964 11.3334 2.79516 11.3334 3.59266 11.3334H12.4075C13.205 11.3334 13.6038 11.3334 13.6922 11.2678C13.7902 11.1951 13.8159 11.1488 13.8259 11.0272C13.8349 10.9174 13.59 10.524 13.1003 9.73697C12.5197 8.80404 12.0001 7.39351 12.0001 5.33337Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/icons/notifications_dark_4x.png
Normal file
BIN
assets/icons/notifications_dark_4x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -10,6 +10,7 @@ description = "The nostr browser"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
eframe = { workspace = true }
|
eframe = { workspace = true }
|
||||||
|
egui_tabs = { workspace = true }
|
||||||
egui_extras = { workspace = true }
|
egui_extras = { workspace = true }
|
||||||
egui = { workspace = true }
|
egui = { workspace = true }
|
||||||
notedeck_columns = { workspace = true }
|
notedeck_columns = { workspace = true }
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
//#[cfg(target_arch = "wasm32")]
|
//#[cfg(target_arch = "wasm32")]
|
||||||
//use wasm_bindgen::prelude::*;
|
//use wasm_bindgen::prelude::*;
|
||||||
use crate::app::NotedeckApp;
|
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 egui_extras::{Size, StripBuilder};
|
||||||
use nostrdb::{ProfileRecord, Transaction};
|
use nostrdb::{ProfileRecord, Transaction};
|
||||||
use notedeck::{
|
use notedeck::{
|
||||||
App, AppAction, AppContext, NotedeckTextStyle, UserAccount, WalletType,
|
profile::get_profile_url, App, AppAction, AppContext, NotedeckTextStyle, UserAccount,
|
||||||
profile::get_profile_url,
|
WalletType,
|
||||||
};
|
};
|
||||||
use notedeck_columns::Damus;
|
use notedeck_columns::Damus;
|
||||||
use notedeck_dave::{Dave, DaveAvatar};
|
use notedeck_dave::{Dave, DaveAvatar};
|
||||||
@@ -19,6 +19,7 @@ pub static ICON_EXPANSION_MULTIPLE: f32 = 1.2;
|
|||||||
pub struct Chrome {
|
pub struct Chrome {
|
||||||
active: i32,
|
active: i32,
|
||||||
open: bool,
|
open: bool,
|
||||||
|
tab_selected: i32,
|
||||||
apps: Vec<NotedeckApp>,
|
apps: Vec<NotedeckApp>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,17 +27,25 @@ impl Default for Chrome {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
active: 0,
|
active: 0,
|
||||||
|
tab_selected: 0,
|
||||||
open: true,
|
open: true,
|
||||||
apps: vec![],
|
apps: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ToolbarAction {
|
||||||
|
Notifications,
|
||||||
|
Dave,
|
||||||
|
Home,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum ChromePanelAction {
|
pub enum ChromePanelAction {
|
||||||
Support,
|
Support,
|
||||||
Settings,
|
Settings,
|
||||||
Account,
|
Account,
|
||||||
Wallet,
|
Wallet,
|
||||||
|
Toolbar(ToolbarAction),
|
||||||
SaveTheme(ThemePreference),
|
SaveTheme(ThemePreference),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +76,10 @@ impl ChromePanelAction {
|
|||||||
ctx.theme.save(*theme);
|
ctx.theme.save(*theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Self::Toolbar(_toolbar_action) => {
|
||||||
|
tracing::info!("toolbar action");
|
||||||
|
}
|
||||||
|
|
||||||
Self::Support => {
|
Self::Support => {
|
||||||
Self::columns_navigate(ctx, chrome, notedeck_columns::Route::Support);
|
Self::columns_navigate(ctx, chrome, notedeck_columns::Route::Support);
|
||||||
}
|
}
|
||||||
@@ -135,21 +148,16 @@ impl Chrome {
|
|||||||
self.active = app;
|
self.active = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show the side menu or bar, depending on if we're on a narrow
|
/// The chrome side panel
|
||||||
/// or wide screen.
|
fn panel(
|
||||||
///
|
&mut self,
|
||||||
/// The side menu should hover over the screen, while the side bar
|
app_ctx: &mut AppContext,
|
||||||
/// is collapsible but persistent on the screen.
|
builder: StripBuilder,
|
||||||
fn show(&mut self, ctx: &mut AppContext, ui: &mut egui::Ui) -> Option<ChromePanelAction> {
|
amt_open: f32,
|
||||||
ui.spacing_mut().item_spacing.x = 0.0;
|
) -> Option<ChromePanelAction> {
|
||||||
|
|
||||||
let mut got_action: Option<ChromePanelAction> = None;
|
let mut got_action: Option<ChromePanelAction> = None;
|
||||||
let side_panel_width: f32 = 70.0;
|
|
||||||
|
|
||||||
let open_id = egui::Id::new("chrome_open");
|
builder
|
||||||
let amt_open = ui.ctx().animate_bool(open_id, self.open) * side_panel_width;
|
|
||||||
|
|
||||||
StripBuilder::new(ui)
|
|
||||||
.size(Size::exact(amt_open)) // collapsible sidebar
|
.size(Size::exact(amt_open)) // collapsible sidebar
|
||||||
.size(Size::remainder()) // the main app contents
|
.size(Size::remainder()) // the main app contents
|
||||||
.clip(true)
|
.clip(true)
|
||||||
@@ -172,7 +180,7 @@ impl Chrome {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ui.with_layout(Layout::bottom_up(egui::Align::Center), |ui| {
|
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);
|
got_action = Some(action);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -197,8 +205,8 @@ impl Chrome {
|
|||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if let Some(action) = self.apps[self.active as usize].update(ctx, ui) {
|
if let Some(action) = self.apps[self.active as usize].update(app_ctx, ui) {
|
||||||
chrome_handle_app_action(self, ctx, action, ui);
|
chrome_handle_app_action(self, app_ctx, action, ui);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -206,6 +214,90 @@ impl Chrome {
|
|||||||
got_action
|
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<ChromePanelAction> {
|
||||||
|
let mut got_action: Option<ChromePanelAction> = 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<ToolbarAction> {
|
||||||
|
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<ChromePanelAction> {
|
||||||
|
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) {
|
fn topdown_sidebar(&mut self, ui: &mut egui::Ui) {
|
||||||
// macos needs a bit of space to make room for window
|
// macos needs a bit of space to make room for window
|
||||||
// minimize/close buttons
|
// minimize/close buttons
|
||||||
@@ -236,7 +328,8 @@ impl Chrome {
|
|||||||
ui.add_space(32.0);
|
ui.add_space(32.0);
|
||||||
|
|
||||||
if let Some(dave) = self.get_dave() {
|
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() {
|
if dave_resp.clicked() {
|
||||||
self.active = 1;
|
self.active = 1;
|
||||||
} else if dave_resp.hovered() {
|
} 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 {
|
fn columns_button(ui: &mut egui::Ui) -> egui::Response {
|
||||||
let btn = egui::include_image!("../../../assets/icons/columns_80.png");
|
let btn = egui::include_image!("../../../assets/icons/columns_80.png");
|
||||||
expanding_button("columns-button", 40.0, &btn, &btn, ui)
|
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 {
|
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)
|
avatar.render(rect, ui)
|
||||||
} else {
|
} else {
|
||||||
// plain icon if wgpu device not available??
|
// plain icon if wgpu device not available??
|
||||||
|
|||||||
Reference in New Issue
Block a user