From 9a5f7ae50476fa5546b02bc2fe1384a389cae201 Mon Sep 17 00:00:00 2001 From: Adrien Date: Wed, 21 Aug 2024 22:57:34 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20=20Use=20of=20Dioxus=20mai?= =?UTF-8?q?n=20branch=20instead=20of=200.5=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 17 +- src/infrastructure/messaging/matrix/client.rs | 57 ++++--- src/ui/components/conversations.rs | 157 +++++++++++------- src/ui/components/conversations.scss | 60 ++++++- src/ui/components/modal.rs | 24 +-- src/ui/components/text_input.rs | 14 +- src/ui/components/text_input.scss | 2 +- src/ui/hooks/use_long_press.rs | 8 +- src/ui/layouts/conversations.rs | 121 +++++++------- src/ui/layouts/conversations.scss | 45 +++-- 10 files changed, 318 insertions(+), 187 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0050bd0..93f6817 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,30 +43,35 @@ tracing-forest = "0.1.6" turf = "0.8.0" # Dioxus -dioxus = { version = "0.5", default-features = false } -dioxus-free-icons = { version = "0.8", features = ["ionicons", "font-awesome-solid"] } +# dioxus-free-icons = { version = "0.8", features = ["ionicons", "font-awesome-solid"] } +dioxus-free-icons = { git = "https://github.com/ASR-ASU/dioxus-free-icons.git", branch = "asr/dioxus-0.6", features = ["ionicons", "font-awesome-solid"] } modx = "0.1.2" -[patch.crates-io] -dioxus = { git = "https://github.com/DioxusLabs/dioxus.git" } +# Matrix rich text editor +wysiwyg = { path = "../matrix.org/matrix-rich-text-editor/crates/wysiwyg/" } [target.'cfg(target_family = "wasm")'.dependencies] # Logging/tracing tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } tracing-web = "0.1.3" + # Dioxus -dioxus = { features = ["web"] } +dioxus = { git = "https://github.com/DioxusLabs/dioxus.git", branch = "main", features = ["web"] } web-sys = "0.3.69" + # Matrix matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", default-features = false, features = ["rustls-tls", "js"] } [target.'cfg(not(target_family = "wasm"))'.dependencies] # Utils time = "0.3.36" + # Logging/tracing tracing-subscriber = { version = "0.3.18", features = ["env-filter", "time"] } + # Dioxus -dioxus = { features = ["desktop"] } +dioxus = { git = "https://github.com/DioxusLabs/dioxus.git", branch = "main", features = ["desktop"] } + # Matrix matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", default-features = false, features = ["rustls-tls"] } diff --git a/src/infrastructure/messaging/matrix/client.rs b/src/infrastructure/messaging/matrix/client.rs index 008ce76..7942580 100644 --- a/src/infrastructure/messaging/matrix/client.rs +++ b/src/infrastructure/messaging/matrix/client.rs @@ -9,7 +9,7 @@ use dioxus::prelude::Task; use matrix_sdk::{ config::SyncSettings, event_handler::Ctx, - media::{MediaFormat, MediaRequest, MediaThumbnailSize}, + media::{MediaFormat, MediaRequest, MediaThumbnailSettings, MediaThumbnailSize}, room::{ParentSpace, Room}, ruma::{ api::client::media::get_content_thumbnail::v3::Method, @@ -448,10 +448,13 @@ impl Client { async fn on_room_avatar_event(room: &Room, senders: &Ctx) { let room_id = room.room_id(); let avatar = match room - .avatar(MediaFormat::Thumbnail(MediaThumbnailSize { - method: Method::Scale, - width: uint!(256), - height: uint!(256), + .avatar(MediaFormat::Thumbnail(MediaThumbnailSettings { + size: MediaThumbnailSize { + method: Method::Scale, + width: uint!(256), + height: uint!(256), + }, + animated: false, })) .await { @@ -668,10 +671,13 @@ impl Client { match client .account() - .get_avatar(MediaFormat::Thumbnail(MediaThumbnailSize { - method: Method::Scale, - width: uint!(256), - height: uint!(256), + .get_avatar(MediaFormat::Thumbnail(MediaThumbnailSettings { + size: MediaThumbnailSize { + method: Method::Scale, + width: uint!(256), + height: uint!(256), + }, + animated: false, })) .await { @@ -685,10 +691,13 @@ impl Client { if let Some(room) = client.get_room(room_id) { match room - .avatar(MediaFormat::Thumbnail(MediaThumbnailSize { - method: Method::Scale, - width: uint!(256), - height: uint!(256), + .avatar(MediaFormat::Thumbnail(MediaThumbnailSettings { + size: MediaThumbnailSize { + method: Method::Scale, + width: uint!(256), + height: uint!(256), + }, + animated: false, })) .await { @@ -709,10 +718,13 @@ impl Client { let request = MediaRequest { source: MediaSource::Plain(media_url), - format: MediaFormat::Thumbnail(MediaThumbnailSize { - method: Method::Scale, - width: uint!(256), - height: uint!(256), + format: MediaFormat::Thumbnail(MediaThumbnailSettings { + size: MediaThumbnailSize { + method: Method::Scale, + width: uint!(256), + height: uint!(256), + }, + animated: false, }), }; @@ -739,10 +751,13 @@ impl Client { Ok(room_member) => { if let Some(room_member) = room_member { let res = match room_member - .avatar(MediaFormat::Thumbnail(MediaThumbnailSize { - method: Method::Scale, - width: uint!(256), - height: uint!(256), + .avatar(MediaFormat::Thumbnail(MediaThumbnailSettings { + size: MediaThumbnailSize { + method: Method::Scale, + width: uint!(256), + height: uint!(256), + }, + animated: false, })) .await { diff --git a/src/ui/components/conversations.rs b/src/ui/components/conversations.rs index a0e4ad1..2ea9917 100644 --- a/src/ui/components/conversations.rs +++ b/src/ui/components/conversations.rs @@ -21,18 +21,13 @@ turf::style_sheet!("src/ui/components/conversations.scss"); #[component] fn AccountAvatar(content: Option>, class_name: Option) -> Element { - match content { - Some(content) => { - let encoded = general_purpose::STANDARD.encode(content); - rsx! { - div { - class: class_name, - background_image: format!("url(data:image/jpeg;base64,{encoded})") - } + rsx! { + if let Some(content) = content { + div { + class: class_name, + background_image: format!("url(data:image/jpeg;base64,{})", general_purpose::STANDARD.encode(content)) } } - // TODO: Manage acount without avatar - None => None, } } @@ -54,11 +49,11 @@ fn PresenceState(state: Option, class_name: Option) rsx! { div { class: classes, - LogoIcon {}, + LogoIcon {} } } } - None => None, + None => VNode::empty(), } } @@ -70,12 +65,12 @@ fn DisplayName(display_name: Option, class_name: Option) -> Elem div { class: class_name, p { - {display_name}, + {display_name} } } } } - None => None, + None => VNode::empty(), } } @@ -137,37 +132,35 @@ pub fn Account() -> Element { }); rsx! { - style { {STYLE_SHEET} }, - div { class: ClassName::ACCOUNT, - {avatar}, - {presence_state}, - {display_name}, + {avatar} + {presence_state} + {display_name} - {status}, + {status} div { class: ClassName::ACCOUNT_SPACES, Button { - SpacesIcon {}, + SpacesIcon {} } - }, + } div { class: ClassName::ACCOUNT_CHAT, Button { - ChatsIcon {}, + ChatsIcon {} } - }, + } div { class: ClassName::ACCOUNT_ROOM, Button { - RoomsIcon {}, + RoomsIcon {} } - }, + } } } } @@ -175,8 +168,8 @@ pub fn Account() -> Element { #[component] pub fn ConversationAvatar( room_id: RoomId, - on_selected: EventHandler, - on_pressed: EventHandler, + on_selected: Option>, + on_pressed: Option>, ) -> Element { let long_press_duration = Duration::from_millis(500); @@ -185,7 +178,7 @@ pub fn ConversationAvatar( let room_id = Rc::new(room_id); let room_name = room.name(); - let selected_room_id = use_context::>>(); + let selected_room_id = use_signal(|| None::); let invited_badge = if room.is_invited() { rsx! { @@ -193,12 +186,12 @@ pub fn ConversationAvatar( class: ClassName::CONVERSATION_AVATAR_INVITED_BADGE, p { - "Invited", + "Invited" } } } } else { - None + VNode::empty() }; let is_selected = match selected_room_id.read().as_ref() { @@ -206,7 +199,6 @@ pub fn ConversationAvatar( None => false, }; - // let avatar = if let Some(Some(content)) = &*avatar.read() { let avatar = if let Some(content) = room.avatar() { let encoded = general_purpose::STANDARD.encode(content); rsx! { @@ -230,7 +222,7 @@ pub fn ConversationAvatar( div { class: ClassName::CONVERSATION_AVATAR_IMAGE, - {placeholder}, + {placeholder} } } }; @@ -244,12 +236,12 @@ pub fn ConversationAvatar( let on_press = { let room_id = room_id.clone(); move || { - on_selected.call(room_id.as_ref().clone()); + on_selected.map(|c| c.call(room_id.as_ref().clone())); } }; let on_long_press = move || { - on_pressed.call(room_id.as_ref().clone()); + on_pressed.map(|c| c.call(room_id.as_ref().clone())); }; let long_press_hook = use_long_press(long_press_duration, on_press, on_long_press); @@ -302,7 +294,7 @@ pub fn ConversationsCarousel( onscroll: move |_| { // Catch scrolling events. }, - {rendered_avatars}, + {rendered_avatars} } } } @@ -367,8 +359,6 @@ pub fn Space(id: Option, on_pressed_conversation: EventHandler) let classes_str = space_classes.join(" "); rsx! { - style { {STYLE_SHEET} }, - div { class: "{classes_str}", @@ -382,17 +372,17 @@ pub fn Space(id: Option, on_pressed_conversation: EventHandler) p { {name} } - }, + } ConversationsCarousel { on_selected_conversation, on_pressed_conversation, - }, + } div { class: ClassName::SPACE_CONVERSATION_NAME, p { - {selected_room_name}, + {selected_room_name} } - }, + } } } } @@ -412,19 +402,24 @@ pub fn Spaces(on_pressed_conversation: EventHandler) -> Element { div { class: ClassName::SPACES, - {rendered_spaces}, + {rendered_spaces} - Space { on_pressed_conversation }, + Space { on_pressed_conversation } } } } +#[component] pub fn Search() -> Element { rsx! { div { class: ClassName::SEARCH, - TextInput {} + div { + class: ClassName::SEARCH_TEXT, + + TextInput {} + } div { class: ClassName::SEARCH_BUTTON, @@ -437,7 +432,15 @@ pub fn Search() -> Element { } #[component] -fn ConversationOptionsMenu(room_id: RoomId, on_close: EventHandler) -> Element { +fn ConversationOptionsMenu( + room_id: RoomId, + on_close: EventHandler, + on_join: EventHandler, +) -> Element { + let room = STORE.read().rooms().get(&room_id).unwrap().signal(); + + let topic = room.topic().unwrap_or("".to_string()); + rsx! { div { class: ClassName::CONVERSATION_OPTIONS_MENU, @@ -447,31 +450,44 @@ fn ConversationOptionsMenu(room_id: RoomId, on_close: EventHandler) -> Element { div { class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_AVATAR, + ConversationAvatar { room_id } } div { class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_NAME, + p { + {room.name()} + } } div { class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_TOPIC, + p { + {topic} + } } div { class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_CONFIG, + p { + "Coming soon..." + } } div { class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_CLOSE_BUTTON, RejectButton { - onclick: move |_| on_close(()), + onclick: move |_| on_close(()) } } div { class: ClassName::CONVERSATION_OPTIONS_MENU_INNER_JOIN_BUTTON, JoinButton { - onclick: move |_| on_close(()), + onclick: move |_| { + on_join(()); + on_close(()); + } } } } @@ -480,37 +496,54 @@ fn ConversationOptionsMenu(room_id: RoomId, on_close: EventHandler) -> Element { } pub fn Conversations() -> Element { - let mut conversation_options_menu = use_signal(|| None::); + let mut room_id = use_signal(|| None::); - let on_conversation_options_menu_close = move |_| { - conversation_options_menu.set(None); + let on_menu_close = move |_| { + room_id.set(None); }; - let on_pressed_conversation = move |room_id: RoomId| { - conversation_options_menu.set(Some(rsx! { ConversationOptionsMenu { room_id, on_close: on_conversation_options_menu_close } })); + let on_menu_join = move |_| async move { + let rooms = STORE.read().rooms(); + if let Some(room_id) = room_id.read().to_owned() { + if let Some(room) = rooms.get(&room_id) {} + } + }; + + let on_pressed_conversation = move |id: RoomId| { + room_id.set(Some(id)); + }; + + let menu = match room_id.read().as_ref() { + Some(room_id) => { + let room_id = room_id.clone(); + rsx! { + ConversationOptionsMenu { room_id, on_close: on_menu_close, on_join: on_menu_join } + } + } + None => VNode::empty(), }; rsx! { - style { {STYLE_SHEET} }, + style { {STYLE_SHEET} } div { class: ClassName::CONVERSATIONS, div { class: ClassName::CONVERSATIONS_ACCOUNT, - Account {}, - }, + Account {} + } div { class: ClassName::CONVERSATIONS_SPACES, - Spaces { on_pressed_conversation }, - }, + Spaces { on_pressed_conversation } + } div { class: ClassName::CONVERSATIONS_SEARCH, - Search {}, - }, - }, - {conversation_options_menu} + Search {} + } + } + {menu} } } diff --git a/src/ui/components/conversations.scss b/src/ui/components/conversations.scss index 81621cc..847b0ff 100644 --- a/src/ui/components/conversations.scss +++ b/src/ui/components/conversations.scss @@ -268,6 +268,11 @@ display: flex; gap: 5%; + &__text { + height: 100%; + width: 100%; + } + &__button { @include button-class(); @@ -313,6 +318,24 @@ } } +%base-helper-text { + margin: 0; + margin-top: 0.3vh; + + font-size: 1.2vh; + + // TODO: Set color used for text in _base.scss file + color: get-color(greyscale, 90); + + p { + margin: 0; + + &.invalid { + color: get-color(critical, 100); + } + } +} + .conversation-options-menu { width: 100%; height: 100%; @@ -355,23 +378,50 @@ width: 100%; aspect-ratio: 1; - - background-color: green; } &__name { grid-area: name; - background-color: orange; + + // TODO: Merge with &__display-name + display: flex; + align-items: center; + justify-content: center; + + p { + font-size: 2.5vh; + margin: 0; + text-align: center; + } } &__topic { grid-area: topic; - background-color: aqua; + + // TODO: Merge with &__display-name + display: flex; + align-items: center; + justify-content: center; + + @extend %base-helper-text; + p { + font-size: 2vh; + margin: 0; + text-align: center; + } } &__config { grid-area: config; - background-color: purple; + + // TODO: Merge with &__display-name + display: flex; + align-items: center; + justify-content: center; + + border: $border-thin; + border-color: get-color(ternary, 90); + border-radius: $border-radius; } button { diff --git a/src/ui/components/modal.rs b/src/ui/components/modal.rs index 1b5b764..7200f66 100644 --- a/src/ui/components/modal.rs +++ b/src/ui/components/modal.rs @@ -76,10 +76,10 @@ pub fn Modal(props: ModalProps) -> Element { Severity::Critical => ErrorButton, }; - icon.as_ref()?; + icon.as_ref().ok_or(VNode::empty()); rsx! { - style { {STYLE_SHEET} }, + style { {STYLE_SHEET} } div { class: ClassName::MODAL, @@ -90,17 +90,17 @@ pub fn Modal(props: ModalProps) -> Element { div { class: ClassName::MODAL_CONTENT_ICON, {icon} - }, + } div { class: ClassName::MODAL_CONTENT_TITLE, - {props.title}, - }, + {props.title} + } div { class: ClassName::MODAL_CONTENT_MSG, - {props.children}, - }, + {props.children} + } div { class: ClassName::MODAL_CONTENT_BUTTONS, @@ -109,10 +109,10 @@ pub fn Modal(props: ModalProps) -> Element { if let Some(cb) = &props.on_confirm { cb.call(evt); } - }, - }, - }, - }, - }, + } + } + } + } + } } } diff --git a/src/ui/components/text_input.rs b/src/ui/components/text_input.rs index 07e4fcb..8f34dd8 100644 --- a/src/ui/components/text_input.rs +++ b/src/ui/components/text_input.rs @@ -67,7 +67,7 @@ pub fn TextInput(props: InputProps) -> Element { let input_classes_str = [ClassName::TEXT_INPUT_INPUT, criticity_class].join(" "); rsx! { - style { {STYLE_SHEET} }, + style { {STYLE_SHEET} } div { class: ClassName::TEXT_INPUT, @@ -83,7 +83,7 @@ pub fn TextInput(props: InputProps) -> Element { cb.call(evt); } }, - }, + } div { class: ClassName::TEXT_INPUT_HELPER_TEXT, @@ -159,7 +159,7 @@ pub fn PasswordTextInput(props: InputProps) -> Element { let input_classes = [ClassName::PASSWORD_TEXT_INPUT_INPUT, criticity_class].join(" "); rsx! { - style { {STYLE_SHEET} }, + style { {STYLE_SHEET} } div { class: "{text_input_classes}", @@ -175,7 +175,7 @@ pub fn PasswordTextInput(props: InputProps) -> Element { cb.call(evt); } }, - }, + } if let Some(score) = score { div { @@ -184,7 +184,7 @@ pub fn PasswordTextInput(props: InputProps) -> Element { ratio: score, } } - }, + } div { class: ClassName::PASSWORD_TEXT_INPUT_SHOW_TOGGLE, @@ -203,7 +203,7 @@ pub fn PasswordTextInput(props: InputProps) -> Element { icon: IoEye, } } - }, + } div { class: ClassName::PASSWORD_TEXT_INPUT_HELPER_TEXT, @@ -212,7 +212,7 @@ pub fn PasswordTextInput(props: InputProps) -> Element { class: criticity_class, {helper_text} } - }, + } } } } diff --git a/src/ui/components/text_input.scss b/src/ui/components/text_input.scss index ce09044..7c3dae8 100644 --- a/src/ui/components/text_input.scss +++ b/src/ui/components/text_input.scss @@ -1,4 +1,4 @@ -@import "../_base.scss" +@import "../_base.scss"; %base-text-input { $horizontal-padding: 1vw; diff --git a/src/ui/hooks/use_long_press.rs b/src/ui/hooks/use_long_press.rs index 2044bdd..a507747 100644 --- a/src/ui/hooks/use_long_press.rs +++ b/src/ui/hooks/use_long_press.rs @@ -14,20 +14,20 @@ pub fn use_long_press( on_long_press: impl FnMut() + 'static, ) -> UseLongPress { let on_press = std::rc::Rc::new(RefCell::new(on_press)); - let on_press_cb = use_callback(move || { + let on_press_cb = use_callback(move |_| { let mut on_press = on_press.as_ref().borrow_mut(); on_press(); }); let on_long_press = std::rc::Rc::new(RefCell::new(on_long_press)); - let on_long_press_cb = use_callback(move || { + let on_long_press_cb = use_callback(move |_| { let mut on_long_press = on_long_press.as_ref().borrow_mut(); on_long_press(); }); let mut timer = use_future(move || async move { task::sleep(duration).await; - on_long_press_cb.call(); + on_long_press_cb.call(()); }); timer.cancel(); @@ -39,7 +39,7 @@ pub fn use_long_press( let selection_end_cb = move |_: Event| { if !timer.finished() { timer.cancel(); - on_press_cb.call(); + on_press_cb.call(()); } }; diff --git a/src/ui/layouts/conversations.rs b/src/ui/layouts/conversations.rs index 8bb742e..bd475c7 100644 --- a/src/ui/layouts/conversations.rs +++ b/src/ui/layouts/conversations.rs @@ -1,15 +1,19 @@ -use std::rc::Rc; +use std::{collections::HashSet, rc::Rc}; +use base64::{engine::general_purpose, Engine as _}; use dioxus::prelude::*; use futures::join; use tracing::warn; -use crate::ui::{ - components::{ - chat_panel::ChatPanel, conversations::Conversations as ConversationsComponent, - wallpaper::Wallpaper, +use crate::{ + domain::model::room::RoomId, + ui::{ + components::{ + chat_panel::ChatPanel, conversations::Conversations as ConversationsComponent, + wallpaper::Wallpaper, + }, + STORE, }, - STORE, }; turf::style_sheet!("src/ui/layouts/conversations.scss"); @@ -66,7 +70,7 @@ fn LayoutSmall() -> Element { let inner = rsx! { div { class: ClassName::CONVERSATIONS_VIEW_SMALL_PANEL_INNER, - ChatPanel { name: format!("CHAT {room_name_repr}") }, + ChatPanel { name: format!("CHAT {room_name_repr}") } } }; @@ -88,7 +92,7 @@ fn LayoutSmall() -> Element { } }; - if let Some(panel) = panel { + if let Ok(panel) = panel { conversation_panels.push(panel); } } else { @@ -97,7 +101,7 @@ fn LayoutSmall() -> Element { } rsx! { - style { {STYLE_SHEET} }, + style { {STYLE_SHEET} } div { class: ClassName::CONVERSATIONS_VIEW_SMALL, @@ -133,9 +137,9 @@ fn LayoutSmall() -> Element { div { class: ClassName::CONVERSATIONS_VIEW_SMALL_CONVERSATIONS_PANEL_INNER, - ConversationsComponent {}, - }, - }, + ConversationsComponent {} + } + } {conversation_panels.iter()} @@ -164,33 +168,33 @@ fn LayoutBig() -> Element { is_first = false; rsx! { div { - class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATION_PANELS_PANEL, + class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANELS_PANEL, onmounted: move |cx| async move { let data = cx.data(); let _ = data.as_ref().scroll_to(ScrollBehavior::Smooth).await; first_div.set(Some(data)); }, - ChatPanel { name: room_name_repr }, + ChatPanel { name: room_name_repr } } } } else if displayed_room_ids_it.peek().is_none() { rsx! { div { - class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATION_PANELS_PANEL, + class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANELS_PANEL, onmounted: move |cx: Event| last_div.set(Some(cx.data())), - ChatPanel { name: room_name_repr }, + ChatPanel { name: room_name_repr } } } } else { rsx! { div { - class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATION_PANELS_PANEL, - ChatPanel { name: room_name_repr }, + class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANELS_PANEL, + ChatPanel { name: room_name_repr } } } }; - if let Some(panel) = panel { + if let Ok(panel) = panel { conversation_panels.push(panel); } } else { @@ -199,7 +203,7 @@ fn LayoutBig() -> Element { } rsx! { - style { {STYLE_SHEET} }, + style { {STYLE_SHEET} } div { class: ClassName::CONVERSATIONS_VIEW_BIG, @@ -207,40 +211,45 @@ fn LayoutBig() -> Element { div { class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANEL, - ConversationsComponent {}, - }, + ConversationsComponent {} + } div { - class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATION_PANELS, + class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS, - onmounted: move |cx| async move { - let data = cx.data(); - carousel_div.set(Some(data)); - }, - onscroll: move |_| { - async move { - if let (Some(carousel_div), Some(first_div), Some(last_div)) = ( - carousel_div.read().as_ref(), - first_div.read().as_ref(), - last_div.read().as_ref(), - ) { - on_carousel_scroll(carousel_div, first_div, last_div).await; + + div { + class: ClassName::CONVERSATIONS_VIEW_BIG_CONVERSATIONS_PANELS, + + onmounted: move |cx| async move { + let data = cx.data(); + carousel_div.set(Some(data)); + }, + + onscroll: move |_| { + async move { + if let (Some(carousel_div), Some(first_div), Some(last_div)) = ( + carousel_div.read().as_ref(), + first_div.read().as_ref(), + last_div.read().as_ref(), + ) { + on_carousel_scroll(carousel_div, first_div, last_div).await; + } } + }, + + div { + class: ClassName::CONVERSATIONS_VIEW_HEAD, } - }, - div { - class: ClassName::CONVERSATIONS_VIEW_HEAD, + {conversation_panels.iter()} + + div { + class: ClassName::CONVERSATIONS_VIEW_TAIL, + } } - - {conversation_panels.iter()} - - div { - class: ClassName::CONVERSATIONS_VIEW_TAIL, - } - - }, + } } } } @@ -249,29 +258,29 @@ pub fn Conversations() -> Element { let mut layout = use_signal(|| None::); rsx! { - style { {STYLE_SHEET} }, + style { {STYLE_SHEET} } Wallpaper { display_version: true - }, + } div { class: ClassName::CONVERSATIONS_VIEW, - onresized: move |cx| { + onresize: move |cx| { let data = cx.data(); let mut use_big_layout = false; if let Ok(size) = data.get_border_box_size() { - if let Some(size) = size.first() { - // Use LayoutBig if the layout can contain 2 panels side by side - let component_width = size.height * INNER_PANEL_HEIGHT_RATIO * ASPECT_RATIO; - let breakpoint_width = component_width * 2_f64; - use_big_layout = size.width > breakpoint_width; - } + // Use LayoutBig if the layout can contain 2 panels side by side + let component_width = size.height * INNER_PANEL_HEIGHT_RATIO * ASPECT_RATIO; + let breakpoint_width = component_width * 2_f64; + use_big_layout = size.width > breakpoint_width; } - layout.set(rsx! { if use_big_layout { LayoutBig {} } else { LayoutSmall {} }}); + // let layout_result = rsx! { if use_big_layout { LayoutBig {} } else { LayoutSmall {} }}; + let layout_result = rsx! { LayoutBig {} }; + layout.set(Some(layout_result.unwrap())); }, {layout} diff --git a/src/ui/layouts/conversations.scss b/src/ui/layouts/conversations.scss index 146f19c..c0ad69d 100644 --- a/src/ui/layouts/conversations.scss +++ b/src/ui/layouts/conversations.scss @@ -110,28 +110,47 @@ $inner-panel-height-ratio: 0.95; aspect-ratio: $aspect-ratio; } - &__conversation-panels { + &__conversations { height: $content-height; + min-width: 64px; flex-grow: 1; display: flex; - flex-direction: row; - overflow-x: scroll; - - justify-content: safe center; - align-items: safe center; - scroll-snap-type: x mandatory; - + flex-direction: column; gap: $gap; - &__panel { - flex-shrink: 0; - - height: 100%; + &__tabs-bar { + height: 5%; width: 100%; - scroll-snap-align: center; + flex-grow: 0; + + // overflow: scroll; + // scrollbar-width: none; + } + + &__panels { + flex-grow: 1; + + display: flex; + flex-direction: row; + overflow-x: scroll; + + justify-content: safe center; + align-items: safe center; + scroll-snap-type: x mandatory; + + gap: $gap; + + &__panel { + flex-shrink: 0; + + height: 100%; + width: 100%; + + scroll-snap-align: center; + } } } }