diff options
| author | 2025-05-24 12:03:57 +0100 | |
|---|---|---|
| committer | 2025-05-24 12:03:57 +0100 | |
| commit | 5f5edccaf327727662db027b9fc4cdf86365e20b (patch) | |
| tree | 31acfd8d32b7e26486e40603e1d721cb13f13167 | |
| parent | eff7045e9f871c0ec6eb0401c77ab4209b36d636 (diff) | |
| download | macaw-web-5f5edccaf327727662db027b9fc4cdf86365e20b.tar.gz macaw-web-5f5edccaf327727662db027b9fc4cdf86365e20b.tar.bz2 macaw-web-5f5edccaf327727662db027b9fc4cdf86365e20b.zip  | |
feat: modal
| -rw-r--r-- | assets/icons/close24.svg | 4 | ||||
| -rw-r--r-- | assets/style.scss | 26 | ||||
| -rw-r--r-- | src/lib.rs | 90 | 
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;  } @@ -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,  | 
