mirror of
https://github.com/librekeys/picoforge.git
synced 2026-07-28 08:01:19 -07:00
fix: ui children overflowing out of the window when window size is too small
This commit is contained in:
+2
-2
@@ -49,8 +49,8 @@ fn main() {
|
||||
window_decorations: Some(gpui::WindowDecorations::Client),
|
||||
|
||||
window_min_size: Some(gpui::Size {
|
||||
width: px(650.),
|
||||
height: px(400.),
|
||||
width: px(450.),
|
||||
height: px(200.),
|
||||
}),
|
||||
kind: WindowKind::Normal,
|
||||
..Default::default()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub mod sidebar;
|
||||
|
||||
@@ -1,2 +1,331 @@
|
||||
pub struct Sidebar;
|
||||
impl Render for Sidebar {}
|
||||
use crate::device::types::{DeviceMethod, FullDeviceStatus};
|
||||
use crate::ui::colors;
|
||||
use gpui::*;
|
||||
use gpui_component::{
|
||||
ActiveTheme, Icon, IconName, Side,
|
||||
button::{Button, ButtonVariants},
|
||||
h_flex,
|
||||
sidebar::*,
|
||||
v_flex,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum ActiveView {
|
||||
Home,
|
||||
Passkeys,
|
||||
Configuration,
|
||||
Security,
|
||||
Logs,
|
||||
About,
|
||||
}
|
||||
|
||||
pub struct AppSidebar<V: 'static> {
|
||||
active_view: ActiveView,
|
||||
width: Pixels,
|
||||
collapsed: bool,
|
||||
device_status: Option<FullDeviceStatus>,
|
||||
device_error: Option<String>,
|
||||
on_select: Option<Rc<dyn Fn(&mut V, ActiveView, &mut Window, &mut Context<V>)>>,
|
||||
on_refresh: Option<Rc<dyn Fn(&mut V, &mut Window, &mut Context<V>)>>,
|
||||
}
|
||||
|
||||
impl<V: 'static> AppSidebar<V> {
|
||||
pub fn new(
|
||||
active_view: ActiveView,
|
||||
width: Pixels,
|
||||
collapsed: bool,
|
||||
device_status: Option<FullDeviceStatus>,
|
||||
device_error: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
active_view,
|
||||
width,
|
||||
collapsed,
|
||||
device_status,
|
||||
device_error,
|
||||
on_select: None,
|
||||
on_refresh: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_select(
|
||||
mut self,
|
||||
handler: impl Fn(&mut V, ActiveView, &mut Window, &mut Context<V>) + 'static,
|
||||
) -> Self {
|
||||
self.on_select = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_refresh(
|
||||
mut self,
|
||||
handler: impl Fn(&mut V, &mut Window, &mut Context<V>) + 'static,
|
||||
) -> Self {
|
||||
self.on_refresh = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn render(self, cx: &mut Context<V>) -> impl IntoElement {
|
||||
let width = self.width;
|
||||
let collapsed = self.collapsed;
|
||||
// active_view was unused
|
||||
let device_status = self.device_status.clone();
|
||||
let device_error = self.device_error.clone();
|
||||
|
||||
let border_color = cx.theme().sidebar_border;
|
||||
// bg_color was unused
|
||||
let muted_foreground = cx.theme().muted_foreground;
|
||||
|
||||
v_flex()
|
||||
.h_full()
|
||||
.bg(rgb(colors::zinc::ZINC900))
|
||||
.w(width)
|
||||
.child({
|
||||
let header = h_flex()
|
||||
.w_full()
|
||||
.items_center()
|
||||
.bg(rgb(colors::zinc::ZINC900))
|
||||
.border_r_1()
|
||||
.border_color(border_color)
|
||||
.pt_4();
|
||||
|
||||
let current_width = width;
|
||||
let t = ((current_width - px(48.)) / (px(255.) - px(48.))).clamp(0.0, 1.0);
|
||||
|
||||
// Animate padding-left from 8px (collapsed) to 16px (expanded)
|
||||
let padding_left = px(8.) + (px(16.) - px(8.)) * t;
|
||||
|
||||
let header = header.justify_start().pl(padding_left);
|
||||
|
||||
// Icon Animation: Stays 48px until width drops below 120px, then shrinks to 32px
|
||||
// Range: [48px ... 120px] -> [32px ... 48px]
|
||||
let width_icon_start = px(120.);
|
||||
let t_icon =
|
||||
((current_width - px(48.)) / (width_icon_start - px(48.))).clamp(0.0, 1.0);
|
||||
let icon_size = px(32.) + (px(48.) - px(32.)) * t_icon;
|
||||
|
||||
// Text Animation: Fades out first, before icon starts shrinking
|
||||
// Range: [200px ... 255px] -> [0.0 ... 1.0]
|
||||
let width_text_start = px(200.);
|
||||
let text_opacity: f32 = if current_width > width_text_start {
|
||||
((current_width - width_text_start) / (px(255.) - width_text_start))
|
||||
.clamp(0.0, 1.0)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
header
|
||||
.child(
|
||||
img("appIcons/in.suyogtandel.picoforge.svg")
|
||||
.w(icon_size)
|
||||
.h(icon_size)
|
||||
.flex_shrink_0(),
|
||||
)
|
||||
.children(if width > px(60.) {
|
||||
Some(
|
||||
div()
|
||||
.ml_2()
|
||||
.opacity(text_opacity)
|
||||
.child("PicoForge")
|
||||
.font_weight(gpui::FontWeight::EXTRA_BOLD)
|
||||
.text_color(rgb(colors::zinc::ZINC100)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
})
|
||||
.child(
|
||||
Sidebar::new(Side::Left)
|
||||
.collapsed(width < px(120.))
|
||||
.collapsible(false)
|
||||
.h_auto()
|
||||
.w_full()
|
||||
.flex_grow()
|
||||
.bg(rgb(colors::zinc::ZINC900))
|
||||
.child(
|
||||
SidebarGroup::new("Menu").child(
|
||||
SidebarMenu::new()
|
||||
.child(self.menu_item(
|
||||
cx,
|
||||
"Home",
|
||||
"icons/house.svg",
|
||||
ActiveView::Home,
|
||||
))
|
||||
.child(self.menu_item(
|
||||
cx,
|
||||
"Passkeys",
|
||||
"icons/key-round.svg",
|
||||
ActiveView::Passkeys,
|
||||
))
|
||||
.child(self.menu_item(
|
||||
cx,
|
||||
"Configuration",
|
||||
"icons/settings.svg",
|
||||
ActiveView::Configuration,
|
||||
))
|
||||
.child(self.menu_item(
|
||||
cx,
|
||||
"Security",
|
||||
"icons/shield-check.svg",
|
||||
ActiveView::Security,
|
||||
))
|
||||
.child(self.menu_item(
|
||||
cx,
|
||||
"Logs",
|
||||
"icons/scroll-text.svg",
|
||||
ActiveView::Logs,
|
||||
))
|
||||
.child(self.menu_item_icon_name(
|
||||
cx,
|
||||
"About",
|
||||
IconName::Info,
|
||||
ActiveView::About,
|
||||
)),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.w_full()
|
||||
.bg(rgb(0x111113))
|
||||
.border_r_1()
|
||||
.border_color(border_color)
|
||||
.p_2()
|
||||
.gap_3()
|
||||
.child(if collapsed {
|
||||
// Collapsed View
|
||||
v_flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.gap_2()
|
||||
.child(
|
||||
Button::new("refresh-btn-collapsed")
|
||||
.ghost()
|
||||
.child(Icon::default().path("icons/refresh-cw.svg"))
|
||||
.on_click(cx.listener({
|
||||
let on_refresh = self.on_refresh.clone();
|
||||
move |view, _, window, cx| {
|
||||
if let Some(f) = &on_refresh {
|
||||
f(view, window, cx)
|
||||
}
|
||||
}
|
||||
})),
|
||||
)
|
||||
.child(div().w(px(8.)).h(px(8.)).rounded_full().bg(
|
||||
if let Some(status) = &device_status {
|
||||
if status.method == DeviceMethod::Fido {
|
||||
rgb(0xf59e0b)
|
||||
} else {
|
||||
rgb(0x22c55e)
|
||||
}
|
||||
} else if device_error.is_some() {
|
||||
rgb(0xf59e0b)
|
||||
} else {
|
||||
rgb(0xef4444)
|
||||
},
|
||||
))
|
||||
} else {
|
||||
// Expanded View
|
||||
v_flex()
|
||||
.gap_3()
|
||||
.child(
|
||||
h_flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(12.))
|
||||
.font_weight(gpui::FontWeight::MEDIUM)
|
||||
.text_color(muted_foreground)
|
||||
.child("Device Status"),
|
||||
)
|
||||
.child({
|
||||
let (text, color_bg, color_text) =
|
||||
if let Some(status) = &device_status {
|
||||
if status.method == DeviceMethod::Fido {
|
||||
("Online - Fido", rgb(0xf59e0b), rgb(0xffffff))
|
||||
} else {
|
||||
("Online", rgb(0x16a34a), rgb(0xffffff))
|
||||
}
|
||||
} else if device_error.is_some() {
|
||||
("Error", rgb(0xd97706), rgb(0xffffff))
|
||||
} else {
|
||||
("Offline", rgb(0xef4444), rgb(0xffffff))
|
||||
};
|
||||
|
||||
div()
|
||||
.px(px(6.))
|
||||
.h(px(20.))
|
||||
.flex()
|
||||
.items_center()
|
||||
.rounded(px(10.))
|
||||
.bg(color_bg)
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(10.))
|
||||
.font_weight(gpui::FontWeight::BOLD)
|
||||
.text_color(color_text)
|
||||
.child(text),
|
||||
)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("refresh-btn")
|
||||
.outline()
|
||||
.w_full()
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.justify_center()
|
||||
.child(Icon::default().path("icons/refresh-cw.svg"))
|
||||
.child("Refresh"),
|
||||
)
|
||||
.on_click(cx.listener({
|
||||
let on_refresh = self.on_refresh.clone();
|
||||
move |view, _, window, cx| {
|
||||
if let Some(f) = &on_refresh {
|
||||
f(view, window, cx)
|
||||
}
|
||||
}
|
||||
})),
|
||||
)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn menu_item(
|
||||
&self,
|
||||
cx: &mut Context<V>,
|
||||
label: &'static str,
|
||||
icon_path: &'static str,
|
||||
view: ActiveView,
|
||||
) -> SidebarMenuItem {
|
||||
let on_select = self.on_select.clone();
|
||||
SidebarMenuItem::new(label)
|
||||
.icon(Icon::default().path(icon_path))
|
||||
.active(self.active_view == view)
|
||||
.on_click(cx.listener(move |element, _, window, cx| {
|
||||
if let Some(f) = &on_select {
|
||||
f(element, view, window, cx);
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
fn menu_item_icon_name(
|
||||
&self,
|
||||
cx: &mut Context<V>,
|
||||
label: &'static str,
|
||||
icon: IconName,
|
||||
view: ActiveView,
|
||||
) -> SidebarMenuItem {
|
||||
let on_select = self.on_select.clone();
|
||||
SidebarMenuItem::new(label)
|
||||
.icon(icon)
|
||||
.active(self.active_view == view)
|
||||
.on_click(cx.listener(move |element, _, window, cx| {
|
||||
if let Some(f) = &on_select {
|
||||
f(element, view, window, cx);
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod assets;
|
||||
pub mod colors;
|
||||
pub mod components;
|
||||
pub mod rootview;
|
||||
pub mod views;
|
||||
|
||||
+65
-284
@@ -1,4 +1,5 @@
|
||||
use crate::device::types::{DeviceMethod, FullDeviceStatus};
|
||||
use crate::device::types::FullDeviceStatus;
|
||||
use crate::ui::components::sidebar::{ActiveView, AppSidebar};
|
||||
use crate::ui::{
|
||||
colors,
|
||||
views::{
|
||||
@@ -8,24 +9,13 @@ use crate::ui::{
|
||||
};
|
||||
use gpui::*;
|
||||
use gpui_component::{
|
||||
ActiveTheme, Icon, IconName, Side, TitleBar,
|
||||
ActiveTheme, IconName, TitleBar,
|
||||
button::{Button, ButtonVariants},
|
||||
h_flex,
|
||||
scroll::ScrollableElement,
|
||||
sidebar::*,
|
||||
v_flex,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum ActiveView {
|
||||
Home,
|
||||
Passkeys,
|
||||
Configuration,
|
||||
Security,
|
||||
Logs,
|
||||
About,
|
||||
}
|
||||
|
||||
pub struct ApplicationRoot {
|
||||
active_view: ActiveView,
|
||||
collapsed: bool,
|
||||
@@ -65,11 +55,6 @@ impl ApplicationRoot {
|
||||
|
||||
impl Render for ApplicationRoot {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let device_status = self.device_status.clone();
|
||||
|
||||
let device_error = self.device_error.clone();
|
||||
let collapsed = self.collapsed;
|
||||
|
||||
let target_width = if self.collapsed { px(48.) } else { px(255.) };
|
||||
if (self.sidebar_width - target_width).abs() > px(0.1) {
|
||||
self.sidebar_width = self.sidebar_width + (target_width - self.sidebar_width) * 0.2;
|
||||
@@ -78,276 +63,72 @@ impl Render for ApplicationRoot {
|
||||
self.sidebar_width = target_width;
|
||||
}
|
||||
|
||||
h_flex()
|
||||
.size_full()
|
||||
.child(
|
||||
v_flex()
|
||||
.h_full()
|
||||
.bg(rgb(colors::zinc::ZINC900))
|
||||
.w(self.sidebar_width)
|
||||
.child({
|
||||
let header = h_flex()
|
||||
.w_full()
|
||||
.items_center()
|
||||
.bg(rgb(colors::zinc::ZINC900))
|
||||
.border_r_1()
|
||||
.border_color(cx.theme().sidebar_border)
|
||||
.pt_4();
|
||||
|
||||
let current_width = self.sidebar_width;
|
||||
let t = ((current_width - px(48.)) / (px(255.) - px(48.))).clamp(0.0, 1.0);
|
||||
|
||||
// Animate padding-left from 8px (collapsed) to 16px (expanded)
|
||||
let padding_left = px(8.) + (px(16.) - px(8.)) * t;
|
||||
|
||||
let header = header.justify_start().pl(padding_left);
|
||||
|
||||
// Icon Animation: Stays 48px until width drops below 120px, then shrinks to 32px
|
||||
// Range: [48px ... 120px] -> [32px ... 48px]
|
||||
let width_icon_start = px(120.);
|
||||
let t_icon = ((current_width - px(48.)) / (width_icon_start - px(48.)))
|
||||
.clamp(0.0, 1.0);
|
||||
let icon_size = px(32.) + (px(48.) - px(32.)) * t_icon;
|
||||
|
||||
// Text Animation: Fades out first, before icon starts shrinking
|
||||
// Range: [200px ... 255px] -> [0.0 ... 1.0]
|
||||
let width_text_start = px(200.);
|
||||
let text_opacity: f32 = if current_width > width_text_start {
|
||||
((current_width - width_text_start) / (px(255.) - width_text_start))
|
||||
.clamp(0.0, 1.0)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
header
|
||||
.child(
|
||||
img("appIcons/in.suyogtandel.picoforge.svg")
|
||||
.w(icon_size)
|
||||
.h(icon_size)
|
||||
.flex_shrink_0(),
|
||||
)
|
||||
.children(if self.sidebar_width > px(60.) {
|
||||
Some(
|
||||
div()
|
||||
.ml_2()
|
||||
.opacity(text_opacity)
|
||||
.child("PicoForge")
|
||||
.font_weight(gpui::FontWeight::EXTRA_BOLD)
|
||||
.text_color(rgb(colors::zinc::ZINC100)),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
div().size_full().overflow_hidden().child(
|
||||
h_flex()
|
||||
.size_full()
|
||||
.child(
|
||||
AppSidebar::new(
|
||||
self.active_view,
|
||||
self.sidebar_width,
|
||||
self.collapsed,
|
||||
self.device_status.clone(),
|
||||
self.device_error.clone(),
|
||||
)
|
||||
.on_select(|this: &mut Self, view, _, _| {
|
||||
this.active_view = view;
|
||||
})
|
||||
.child(
|
||||
Sidebar::new(Side::Left)
|
||||
.collapsed(self.sidebar_width < px(120.))
|
||||
.collapsible(false)
|
||||
.h_auto()
|
||||
.w_full()
|
||||
.flex_grow()
|
||||
.bg(rgb(colors::zinc::ZINC900))
|
||||
.child(
|
||||
SidebarGroup::new("Menu").child(
|
||||
SidebarMenu::new()
|
||||
.child(
|
||||
SidebarMenuItem::new("Home")
|
||||
.icon(Icon::default().path("icons/house.svg"))
|
||||
.active(self.active_view == ActiveView::Home)
|
||||
.on_click(cx.listener(|this, _, _, _| {
|
||||
this.active_view = ActiveView::Home;
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
SidebarMenuItem::new("Passkeys")
|
||||
.icon(Icon::default().path("icons/key-round.svg"))
|
||||
.active(self.active_view == ActiveView::Passkeys)
|
||||
.on_click(cx.listener(|this, _, _, _| {
|
||||
this.active_view = ActiveView::Passkeys;
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
SidebarMenuItem::new("Configuration")
|
||||
.icon(Icon::default().path("icons/settings.svg"))
|
||||
.active(
|
||||
self.active_view == ActiveView::Configuration,
|
||||
)
|
||||
.on_click(cx.listener(|this, _, _, _| {
|
||||
this.active_view = ActiveView::Configuration;
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
SidebarMenuItem::new("Security")
|
||||
.icon(
|
||||
Icon::default().path("icons/shield-check.svg"),
|
||||
)
|
||||
.active(self.active_view == ActiveView::Security)
|
||||
.on_click(cx.listener(|this, _, _, _| {
|
||||
this.active_view = ActiveView::Security;
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
SidebarMenuItem::new("Logs")
|
||||
.icon(Icon::default().path("icons/scroll-text.svg"))
|
||||
.active(self.active_view == ActiveView::Logs)
|
||||
.on_click(cx.listener(|this, _, _, _| {
|
||||
this.active_view = ActiveView::Logs;
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
SidebarMenuItem::new("About")
|
||||
.icon(IconName::Info)
|
||||
.active(self.active_view == ActiveView::About)
|
||||
.on_click(cx.listener(|this, _, _, _| {
|
||||
this.active_view = ActiveView::About;
|
||||
})),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.w_full()
|
||||
.bg(rgb(0x111113))
|
||||
.border_r_1()
|
||||
.border_color(cx.theme().sidebar_border)
|
||||
.p_2()
|
||||
.gap_3()
|
||||
.child(if collapsed {
|
||||
// Collapsed View
|
||||
v_flex()
|
||||
.on_refresh(|this: &mut Self, _, cx| {
|
||||
this.refresh_device_status(cx);
|
||||
})
|
||||
.render(cx),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.size_full()
|
||||
.child(
|
||||
TitleBar::new().bg(rgba(colors::zinc::ZINC950)).child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.bg(rgba(colors::zinc::ZINC950))
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.gap_2()
|
||||
.cursor(gpui::CursorStyle::OpenHand)
|
||||
.child(
|
||||
Button::new("refresh-btn-collapsed")
|
||||
Button::new("sidebar_toggle")
|
||||
.ghost()
|
||||
.child(Icon::default().path("icons/refresh-cw.svg"))
|
||||
.on_click(cx.listener(|this, _, _, cx| {
|
||||
this.refresh_device_status(cx);
|
||||
})),
|
||||
)
|
||||
.child(div().w(px(8.)).h(px(8.)).rounded_full().bg(
|
||||
if let Some(status) = &device_status {
|
||||
if status.method == DeviceMethod::Fido {
|
||||
rgb(0xf59e0b)
|
||||
} else {
|
||||
rgb(0x22c55e)
|
||||
}
|
||||
} else if device_error.is_some() {
|
||||
rgb(0xf59e0b)
|
||||
} else {
|
||||
rgb(0xef4444)
|
||||
},
|
||||
))
|
||||
} else {
|
||||
// Expanded View
|
||||
v_flex()
|
||||
.gap_3()
|
||||
.child(
|
||||
h_flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(12.))
|
||||
.font_weight(gpui::FontWeight::MEDIUM)
|
||||
.text_color(cx.theme().muted_foreground)
|
||||
.child("Device Status"),
|
||||
)
|
||||
.child({
|
||||
let (text, color_bg, color_text) =
|
||||
if let Some(status) = &device_status {
|
||||
if status.method == DeviceMethod::Fido {
|
||||
(
|
||||
"Online - Fido",
|
||||
rgb(0xf59e0b),
|
||||
rgb(0xffffff),
|
||||
)
|
||||
} else {
|
||||
("Online", rgb(0x16a34a), rgb(0xffffff))
|
||||
}
|
||||
} else if device_error.is_some() {
|
||||
("Error", rgb(0xd97706), rgb(0xffffff))
|
||||
} else {
|
||||
("Offline", rgb(0xef4444), rgb(0xffffff))
|
||||
};
|
||||
|
||||
div()
|
||||
.px(px(6.))
|
||||
.h(px(20.))
|
||||
.flex()
|
||||
.items_center()
|
||||
.rounded(px(10.))
|
||||
.bg(color_bg)
|
||||
.child(
|
||||
div()
|
||||
.text_size(px(10.))
|
||||
.font_weight(gpui::FontWeight::BOLD)
|
||||
.text_color(color_text)
|
||||
.child(text),
|
||||
)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("refresh-btn")
|
||||
.outline()
|
||||
.w_full()
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.justify_center()
|
||||
.child(
|
||||
Icon::default()
|
||||
.path("icons/refresh-cw.svg"),
|
||||
)
|
||||
.child("Refresh"),
|
||||
)
|
||||
.on_click(cx.listener(|this, _, _, cx| {
|
||||
this.refresh_device_status(cx);
|
||||
})),
|
||||
)
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.size_full()
|
||||
.child(
|
||||
TitleBar::new().bg(rgba(colors::zinc::ZINC950)).child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.bg(rgba(colors::zinc::ZINC950))
|
||||
.items_center()
|
||||
.cursor(gpui::CursorStyle::OpenHand)
|
||||
.child(
|
||||
Button::new("sidebar_toggle")
|
||||
.ghost()
|
||||
.icon(IconName::PanelLeft)
|
||||
.on_click(cx.listener(|this, _, _, _| {
|
||||
this.collapsed = !this.collapsed;
|
||||
}))
|
||||
.tooltip("Toggle Sidebar"),
|
||||
),
|
||||
.icon(IconName::PanelLeft)
|
||||
.on_click(cx.listener(|this, _, _, _| {
|
||||
this.collapsed = !this.collapsed;
|
||||
}))
|
||||
.tooltip("Toggle Sidebar"),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.min_h(px(0.))
|
||||
.min_w(px(0.))
|
||||
.overflow_y_scrollbar()
|
||||
.flex_grow()
|
||||
.bg(cx.theme().background)
|
||||
.child(match self.active_view {
|
||||
ActiveView::Home => {
|
||||
HomeView::build(cx.theme()).into_any_element()
|
||||
}
|
||||
ActiveView::Passkeys => {
|
||||
PasskeysView::build().into_any_element()
|
||||
}
|
||||
ActiveView::Configuration => {
|
||||
ConfigView::build().into_any_element()
|
||||
}
|
||||
ActiveView::Security => {
|
||||
SecurityView::build().into_any_element()
|
||||
}
|
||||
ActiveView::Logs => LogsView::build().into_any_element(),
|
||||
ActiveView::About => AboutView::build().into_any_element(),
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
v_flex()
|
||||
.min_h(px(0.))
|
||||
.min_w(px(0.))
|
||||
.overflow_y_scrollbar()
|
||||
.flex_grow()
|
||||
.bg(cx.theme().background)
|
||||
.child(match self.active_view {
|
||||
ActiveView::Home => HomeView::build(cx.theme()).into_any_element(),
|
||||
ActiveView::Passkeys => PasskeysView::build().into_any_element(),
|
||||
ActiveView::Configuration => ConfigView::build().into_any_element(),
|
||||
ActiveView::Security => SecurityView::build().into_any_element(),
|
||||
ActiveView::Logs => LogsView::build().into_any_element(),
|
||||
ActiveView::About => AboutView::build().into_any_element(),
|
||||
}),
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user