summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@bunny.garden>2025-05-24 12:03:57 +0100
committerLibravatar cel 🌸 <cel@bunny.garden>2025-05-24 12:03:57 +0100
commit5f5edccaf327727662db027b9fc4cdf86365e20b (patch)
tree31acfd8d32b7e26486e40603e1d721cb13f13167
parenteff7045e9f871c0ec6eb0401c77ab4209b36d636 (diff)
downloadmacaw-web-5f5edccaf327727662db027b9fc4cdf86365e20b.tar.gz
macaw-web-5f5edccaf327727662db027b9fc4cdf86365e20b.tar.bz2
macaw-web-5f5edccaf327727662db027b9fc4cdf86365e20b.zip
feat: modal
Diffstat (limited to '')
-rw-r--r--assets/icons/close24.svg4
-rw-r--r--assets/style.scss26
-rw-r--r--src/lib.rs90
3 files changed, 99 insertions, 21 deletions
diff --git a/assets/icons/close24.svg b/assets/icons/close24.svg
new file mode 100644
index 0000000..d7e82ba
--- /dev/null
+++ b/assets/icons/close24.svg
@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M3 3L21 21" stroke="black" stroke-width="2"/>
+<path d="M3 21L21 3" stroke="black" stroke-width="2"/>
+</svg>
diff --git a/assets/style.scss b/assets/style.scss
index 245e5c7..f781976 100644
--- a/assets/style.scss
+++ b/assets/style.scss
@@ -155,11 +155,11 @@ p {
flex-direction: column;
}
-.chats-list>*, .roster-list>* {
+.chats-list>*, .roster-list>*, .settings .header {
padding: 8px 16px;
}
-.chats-list .header, .roster-list .header {
+.chats-list .header, .roster-list .header, .settings .header {
margin-top: 0.4rem;
border-bottom: 2px solid black;
display: flex;
@@ -589,20 +589,21 @@ p {
}
.modal {
- position: relative;
- z-index: 150;
-}
-
-.modal-background {
- background-color: rgba(0, 0, 0, 0.1);
-}
-
-.modal-content {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
+ z-index: 150;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: rgba(0, 0, 0, 0.4);
+}
+
+.settings {
+ width: 75vw;
+ height: 75vh;
}
.modal .overlay {
@@ -672,7 +673,8 @@ hr {
}
.new-chat:hover, .new-chat.open,
-.add-contact:hover, .add-contact.open {
+.add-contact:hover, .add-contact.open,
+.close:hover {
background: #00000060;
}
diff --git a/src/lib.rs b/src/lib.rs
index 570d2f6..92c764d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,7 +20,7 @@ use futures::stream::StreamExt;
use indexmap::IndexMap;
use jid::JID;
use leptos::{
- ev::{Event, KeyboardEvent, SubmitEvent},
+ ev::{Event, KeyboardEvent, MouseEvent, SubmitEvent},
html::{self, Div, Input, Pre, Textarea},
prelude::*,
tachys::{dom::document, reactive_graph::bind::GetValue},
@@ -633,6 +633,8 @@ fn Macaw(
let open_chats = Store::new(OpenChatsPanel::default());
provide_context(open_chats);
+ let show_settings = RwSignal::new(None::<SettingsPage>);
+ provide_context(show_settings);
let user_presences = Store::new(UserPresences::new());
provide_context(user_presences);
@@ -740,6 +742,11 @@ fn Macaw(
<Sidebar />
// <ChatsList />
<OpenChatsPanelView />
+ {move || if let Some(_) = *show_settings.read() {
+ view! { <Settings /> }.into_any()
+ } else {
+ view! {}.into_any()
+ }}
}
}
@@ -902,7 +909,7 @@ pub fn PersonalStatus() -> impl IntoView {
if open {
view! {
<Overlay set_open>
- <PersonalStatusMenu user />
+ <PersonalStatusMenu user set_open/>
</Overlay>
}.into_any()
} else {
@@ -915,7 +922,8 @@ pub fn PersonalStatus() -> impl IntoView {
}
#[component]
-pub fn PersonalStatusMenu(user: Store<User>) -> impl IntoView {
+pub fn PersonalStatusMenu(user: Store<User>, set_open: WriteSignal<bool>) -> impl IntoView {
+ let show_settings: RwSignal<Option<SettingsPage>> = use_context().unwrap();
let user_presences: Store<UserPresences> = use_context().expect("no user presence store");
let client = use_context::<Client>().expect("client not in context");
@@ -1019,10 +1027,16 @@ pub fn PersonalStatusMenu(user: Store<User>) -> impl IntoView {
</select>
</div>
<hr />
- <div class="menu-item">
+ <div class="menu-item" on:click=move |_| {
+ show_settings.set(Some(SettingsPage::Profile));
+ set_open.set(false);
+ }>
Profile
</div>
- <div class="menu-item">
+ <div class="menu-item" on:click=move |_| {
+ show_settings.set(Some(SettingsPage::Account));
+ set_open.set(false);
+ }>
Settings
</div>
<hr />
@@ -1047,15 +1061,69 @@ pub fn Overlay(set_open: WriteSignal<bool>, children: Children) -> impl IntoView
}
#[component]
-pub fn Modal(set_open: WriteSignal<bool>, children: Children) -> impl IntoView {
+pub fn Modal(on_background_click: impl Fn(MouseEvent) + 'static, children: Children) -> impl IntoView {
view! {
- <div class="modal">
- <div class="modal-background" on:click=move |_| set_open.update(|state| *state = false)></div>
- <div class="modal-content">{children()}</div>
+ <div class="modal" on:click=move |e| {
+ if e.current_target() == e.target() {
+ on_background_click(e)
+ }
+ }>
+ {children()}
</div>
}
}
+#[derive(Clone, Copy, Debug)]
+pub enum SettingsPage {
+ Account,
+ Chat,
+ Profile,
+ Privacy,
+}
+
+#[component]
+pub fn Settings() -> impl IntoView {
+ let show_settings: RwSignal<Option<SettingsPage>> = use_context().unwrap();
+
+ view! {
+ <Modal on_background_click=move |_| { show_settings.set(None); }>
+ <div class="settings panel">
+ <div class="header">
+ <h2>Settings</h2>
+ <div class="header-icon close">
+ <IconComponent icon=Icon::Close24 on:click=move |_| show_settings.set(None)/>
+ </div>
+ </div>
+ <div class="settings-main">
+ <div class="settings-sidebar">
+ <div on:click=move |_| show_settings.set(Some(SettingsPage::Account))>Account</div>
+ <div on:click=move |_| show_settings.set(Some(SettingsPage::Chat))>Chat</div>
+ <div on:click=move |_| show_settings.set(Some(SettingsPage::Privacy))>Privacy</div>
+ <div on:click=move |_| show_settings.set(Some(SettingsPage::Profile))>Profile</div>
+ </div>
+ <div class="settings-main">
+ {move || if let Some(page) = show_settings.get() {
+ match page {
+ SettingsPage::Account => view! { <div>"account"</div> }.into_any(),
+ SettingsPage::Chat => view! { <div>"chat"</div> }.into_any(),
+ SettingsPage::Profile => view! { <div>"profile"</div> }.into_any(),
+ SettingsPage::Privacy => view! { <div>"privacy"</div> }.into_any(),
+ }
+ } else {
+ view! {}.into_any()
+ }}
+ </div>
+ </div>
+ </div>
+ </Modal>
+ }
+}
+
+#[component]
+pub fn ProfileSettings() -> impl IntoView {
+ view! {}
+}
+
#[component]
pub fn OpenChatsPanelView() -> impl IntoView {
let open_chats: Store<OpenChatsPanel> = use_context().expect("no open chats panel in context");
@@ -1340,6 +1408,7 @@ pub enum Icon {
Bubble16,
Bubble16Color,
Bubble24,
+ Close24,
Contact24,
Delivered16,
Dnd16,
@@ -1368,6 +1437,7 @@ impl Icon {
Icon::Bubble16 => format!("{}bubble16.svg", ICONS_SRC),
Icon::Bubble16Color => format!("{}bubble16color.svg", ICONS_SRC),
Icon::Bubble24 => format!("{}bubble24.svg", ICONS_SRC),
+ Icon::Close24 => format!("{}close24.svg", ICONS_SRC),
Icon::Contact24 => format!("{}contact24.svg", ICONS_SRC),
Icon::Delivered16 => format!("{}delivered16.svg", ICONS_SRC),
Icon::Dnd16 => format!("{}dnd16.svg", ICONS_SRC),
@@ -1394,6 +1464,7 @@ impl Icon {
Icon::Bubble16 => 16,
Icon::Bubble16Color => 16,
Icon::Bubble24 => 24,
+ Icon::Close24 => 24,
Icon::Contact24 => 24,
Icon::Delivered16 => 16,
Icon::Dnd16 => 16,
@@ -1420,6 +1491,7 @@ impl Icon {
Icon::Bubble16 => true,
Icon::Bubble16Color => false,
Icon::Bubble24 => true,
+ Icon::Close24 => true,
Icon::Contact24 => true,
Icon::Delivered16 => true,
Icon::Dnd16 => true,