summaryrefslogtreecommitdiffstats
path: root/src/components/sidebar.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/sidebar.rs')
-rw-r--r--src/components/sidebar.rs176
1 files changed, 176 insertions, 0 deletions
diff --git a/src/components/sidebar.rs b/src/components/sidebar.rs
new file mode 100644
index 0000000..ca753ef
--- /dev/null
+++ b/src/components/sidebar.rs
@@ -0,0 +1,176 @@
+use std::collections::HashSet;
+
+use jid::BareJID;
+use leptos::prelude::*;
+
+use crate::components::{
+ personal_status::PersonalStatus,
+ chats_list::ChatsList,
+ roster_list::RosterList,
+};
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub enum SidebarOpen {
+ Roster,
+ Chats,
+}
+
+pub enum Open {
+ /// Currently on screen
+ Focused,
+ /// Open in background somewhere (e.g. in another chat tab)
+ Open,
+ /// Closed
+ Closed,
+}
+
+impl Open {
+ pub fn is_focused(&self) -> bool {
+ match self {
+ Open::Focused => true,
+ Open::Open => false,
+ Open::Closed => false,
+ }
+ }
+
+ pub fn is_open(&self) -> bool {
+ match self {
+ Open::Focused => true,
+ Open::Open => true,
+ Open::Closed => false,
+ }
+ }
+}
+
+/// returns whether the state was changed to open (true) or closed (false)
+pub fn toggle_open(state: &mut Option<SidebarOpen>, open: SidebarOpen) -> bool {
+ match state {
+ Some(opened) => {
+ if *opened == open {
+ *state = None;
+ false
+ } else {
+ *state = Some(open);
+ true
+ }
+ }
+ None => {
+ *state = Some(open);
+ true
+ },
+ }
+}
+
+#[component]
+pub fn Sidebar() -> impl IntoView {
+ let requests: ReadSignal<HashSet<BareJID>> = use_context().expect("no pending subscriptions in context");
+
+ // for what has been clicked open (in the background)
+ let (open, set_open) = signal(None::<SidebarOpen>);
+ // for what is just in the hovered state (not clicked to be pinned open yet necessarily)
+ let (hovered, set_hovered) = signal(None::<SidebarOpen>);
+ let (just_closed, set_just_closed) = signal(false);
+
+ view! {
+ <div class="sidebar" on:mouseleave=move |_| {
+ set_hovered.set(None);
+ set_just_closed.set(false);
+ }>
+ <div class="dock panel">
+ <div class="shortcuts">
+ <div class="roster-tab dock-item" class:focused=move || *open.read() == Some(SidebarOpen::Roster) class:hovering=move || *hovered.read() == Some(SidebarOpen::Roster)
+ on:mouseenter=move |_| {
+ set_just_closed.set(false);
+ set_hovered.set(Some(SidebarOpen::Roster))
+ }
+ on:click=move |_| {
+ set_open.update(|state| {
+ if !toggle_open(state, SidebarOpen::Roster) {
+ set_just_closed.set(true);
+ }
+ })
+ }>
+ <div class="dock-pill"></div>
+ <div class="dock-icon">
+ <div class="icon-with-badge">
+ <img src="/assets/caw.png" />
+ {move || {
+ let len = requests.read().len();
+ if len > 0 {
+ view! {
+ <div class="badge">{len}</div>
+ }.into_any()
+ } else {
+ view! {}.into_any()
+ }
+ }}
+ </div>
+ </div>
+ </div>
+ <div class="chats-tab dock-item" class:focused=move || *open.read() == Some(SidebarOpen::Chats) class:hovering=move || *hovered.read() == Some(SidebarOpen::Chats)
+ on:mouseenter=move |_| {
+ set_just_closed.set(false);
+ set_hovered.set(Some(SidebarOpen::Chats))
+ }
+ on:click=move |_| {
+ set_open.update(|state| {
+ if !toggle_open(state, SidebarOpen::Chats) {
+ set_just_closed.set(true);
+ }
+ })
+ }>
+ <div class="dock-pill"></div>
+ <img src="/assets/bubble.png" />
+ </div>
+ </div>
+ <div class="pins">
+ </div>
+ <div class="personal">
+ <PersonalStatus />
+ </div>
+ </div>
+ {move || if let Some(hovered) = *hovered.read() {
+ if Some(hovered) != *open.read() {
+ if !just_closed.get() {
+ match hovered {
+ SidebarOpen::Roster => view! {
+ <div class="sidebar-drawer sidebar-hovering-drawer">
+ <RosterList />
+ </div>
+ }.into_any(),
+ SidebarOpen::Chats => view! {
+ <div class="sidebar-drawer sidebar-hovering-drawer">
+ <ChatsList />
+ </div>
+ }.into_any(),
+ }
+ } else {
+
+ view! {}.into_any()
+ }
+ } else {
+ view! {}.into_any()
+ }
+ } else {
+ view! {}.into_any()
+ }}
+ {move || if let Some(opened) = *open.read() {
+ match opened {
+ SidebarOpen::Roster => view! {
+ <div class="sidebar-drawer">
+ <RosterList />
+ </div>
+ }.into_any(),
+ SidebarOpen::Chats => view! {
+ <div class="sidebar-drawer">
+ <ChatsList />
+ </div>
+ }.into_any(),
+ }
+ } else {
+ view! {}.into_any()
+ }}
+ </div>
+ }
+}
+