diff --git a/Cargo.toml b/Cargo.toml index 9f10741..da622d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" [dependencies] dioxus = "0.4.0" -sir = { version = "0.3.0", features = ["dioxus"] } dioxus-desktop = "0.4.0" # matrix-sdk = { version = "0.6.2", features = ["js"] } matrix-sdk = { git = "https://github.com/matrix-org/matrix-rust-sdk.git", branch = "main" , features = ["js"]} @@ -19,6 +18,7 @@ ctrlc-async = "3.2.2" tracing-subscriber = "0.3.17" dioxus-free-icons = { version = "0.7.0", features = ["material-design-icons-navigation", "ionicons"] } thiserror = "1.0.44" +turf = "0.5.0" [build] target = "x86_64-unknown-linux-gnu" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..30524a9 --- /dev/null +++ b/build.rs @@ -0,0 +1,5 @@ +fn main() { + // Tell Cargo to rerun this build script if any SCSS file + // in the 'src' directory or its subdirectories changes. + println!("cargo:rerun-if-changed=src/**/*.scss"); +} diff --git a/src/_base.scss b/src/_base.scss new file mode 100644 index 0000000..233d29a --- /dev/null +++ b/src/_base.scss @@ -0,0 +1,45 @@ +body { + height: 100vh; + width: 100vw; + margin: 0px; + padding: 0px; + outline: 0px; + font-family: Tahoma, sans-serif; +} + +#main { + height: 100%; + width: 100%; +} + +.aeroButton { + height: 50%; + min-height: 16px; + aspect-ratio: 1; + background-color: transparent; + border: 2px solid transparent; + background-size: contain !important; + margin-right: 1%; +} +.aeroButton:hover { + border-image: url(./images/aerobutton_border.png) 2 round; +} +.aeroButton:active { + border-image: url(./images/aerobutton_border_down.png) 2 round; +} + +.button { + height: 50%; + min-height: 16px; + aspect-ratio: 1; + background-color: transparent; + border: 2px solid transparent; + background-size: contain !important; + margin-right: 1%; +} +.button:hover { + border-image: url(./images/button_border.png) 2 round; +} +.button:active { + border-image: url(./images/button_border_down.png) 2 round; +} diff --git a/src/components/avatar_selector.rs b/src/components/avatar_selector.rs index 0d1d534..6b66c9e 100644 --- a/src/components/avatar_selector.rs +++ b/src/components/avatar_selector.rs @@ -1,30 +1,13 @@ use dioxus::prelude::*; -use sir::css; + +turf::style_sheet!("src/components/avatar_selector.scss"); pub fn AvatarSelector(cx: Scope) -> Element { - let selector = css!( - " - position: relative; - //left: 35%; - height: 100%; - aspect-ratio: 1; - " - ); - - let picture = css!( - " - position: absolute; - height: 75%; - aspect-ratio: 1; - - bottom: 17.5%; - right: 18%; - " - ); - cx.render(rsx! { + style { STYLE_SHEET }, + div { - class: "{selector}", + class: ClassName::SELECTOR, svg { view_box: "0 0 100 100", linearGradient { @@ -69,7 +52,7 @@ pub fn AvatarSelector(cx: Scope) -> Element { // }, }, img { - class: "{picture}", + class: ClassName::PICTURE, src: "./images/default-avatar.png", }, }, diff --git a/src/components/avatar_selector.scss b/src/components/avatar_selector.scss new file mode 100644 index 0000000..cb9fe27 --- /dev/null +++ b/src/components/avatar_selector.scss @@ -0,0 +1,14 @@ +.selector { + position: relative; + height: 100%; + aspect-ratio: 1; + + .picture { + position: absolute; + height: 75%; + aspect-ratio: 1; + + bottom: 17.5%; + right: 18%; + } +} diff --git a/src/components/contacts.rs b/src/components/contacts.rs index 922fcc3..3b8ab36 100644 --- a/src/components/contacts.rs +++ b/src/components/contacts.rs @@ -1,10 +1,13 @@ use dioxus::prelude::*; use dioxus_free_icons::icons::io_icons::IoChevronDown; use dioxus_free_icons::Icon; -use sir::global_css; + +turf::style_sheet!("src/components/contacts.scss"); fn ContactsArrow(cx: Scope) -> Element { cx.render(rsx! { + style { STYLE_SHEET }, + Icon { icon: IoChevronDown, }, @@ -12,86 +15,26 @@ fn ContactsArrow(cx: Scope) -> Element { } pub fn Contacts(cx: Scope) -> Element { - // TODO: Use @extend once implemented (https://github.com/kaj/rsass/issues/65) - global_css!( - " - .contacts { - height: 72%; - width: 100%; - background-color: white; - font-size: 8pt; - - &.active { - ul { - opacity: 0; - } - - svg { - transform: rotate(180deg); - } - - } - - .header { - height: 2%; - width: 98%; - display: flex; - flex-direction: row; - align-items: center; - cursor: pointer; - margin: 0; - margin-left: 1%; - padding-top: 1%; - font-weight: bold; - } - - ul { - height: 100%; - margin: 0; - overflow: hidden; - opacity: 1; - transition: 0.4s ease; - } - - li { - list-style-type: none; - height: 2%; - margin: 0 auto; - cursor: pointer; - display: flex; - flex-direction: row; - align-items: center; - justify-content: flex-start; - - img { - height: 100%; - aspect-ratio: 1; - } - } - - svg { - transition: 0.4s ease; - } - - .contact { - list-style-type: none - margin: 0 auto - text-align: left - cursor: pointer - } - } - " - ); - let show_contacts = use_state(cx, || false); - let contacts_active = if **show_contacts { "active" } else { "" }; + + let classes = vec![ + ClassName::CONTACTS, + if **show_contacts { + ClassName::ACTIVE + } else { + "" + }, + ] + .join(" "); cx.render(rsx! { + style { STYLE_SHEET }, + div { - class: "contacts {contacts_active}", + class: "{classes}", p { - class: "header", + class: ClassName::HEADER, onclick: move |_| show_contacts.set(!show_contacts), ContactsArrow {}, diff --git a/src/components/contacts.scss b/src/components/contacts.scss new file mode 100644 index 0000000..e44094d --- /dev/null +++ b/src/components/contacts.scss @@ -0,0 +1,65 @@ +.contacts { + height: 72%; + width: 100%; + background-color: white; + font-size: 8pt; + + &.active { + ul { + opacity: 0; + } + + svg { + transform: rotate(180deg); + } + + } + + .header { + height: 2%; + width: 98%; + display: flex; + flex-direction: row; + align-items: center; + cursor: pointer; + margin: 0; + margin-left: 1%; + padding-top: 1%; + font-weight: bold; + } + + ul { + height: 100%; + margin: 0; + overflow: hidden; + opacity: 1; + transition: 0.4s ease; + } + + li { + list-style-type: none; + height: 2%; + margin: 0 auto; + cursor: pointer; + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + + img { + height: 100%; + aspect-ratio: 1; + } + } + + svg { + transition: 0.4s ease; + } + + .contact { + list-style-type: none; + margin: 0 auto; + text-align: left; + cursor: pointer + } +} diff --git a/src/components/contacts_window.rs b/src/components/contacts_window.rs index a84a85e..82303c9 100644 --- a/src/components/contacts_window.rs +++ b/src/components/contacts_window.rs @@ -1,151 +1,60 @@ use dioxus::prelude::*; -use sir::css; use crate::app_settings::AppSettings; use crate::components::contacts::Contacts; use crate::components::header::Header; use crate::components::user_infos::UserInfos; +turf::style_sheet!("src/components/contacts_window.scss"); + pub fn ContactWindow(cx: Scope) -> Element { let app_context = use_shared_state::(cx).unwrap(); - let root = css!( - " - width: 100%; - height: 100%; - - background-color: #ECF6F9; - font-family: \"Tahoma\", sans-serif; - - border: thin solid #707070; - border-radius: 8px; - box-shadow: 0 0 5px #00000050; - " - ); - - let header = css!( - " - height: 10%; - width: 100%; - " - ); - - let title_bar = css!( - " - height: 60%; - width: 100%; - background: - linear-gradient(180deg, #7DC5E3, #3883A3); - " - ); - let user_info = css!( - " - height: 40%; - width: 100%; - background: - linear-gradient(180deg, #00658B, #0077A6); - " - ); - let contacts_nav = css!( - " - height: calc(31/1080*100%); - background: - linear-gradient(180deg, #00658B, #0077A6); - " - ); - - let contacts_nav_inner = css!( - " - margin-left: 1%; - margin-right: 1%; - height: 100%; - display: flex; - align-items: center; - " - ); - - let search = css!( - " - height: calc(38/1080*100%); - width: 100%; - - border-bottom: thin solid #e2eaf3; - " - ); - - // TODO: Remove following div - let search_inner = css!( - " - height: 100%; - width: 98%; - padding-left: 1%; - display: flex; - flex-direction: row; - align-items: center; - " - ); - - let search_input = css!( - " - height: calc(23/38*100%); - width: 100%; - margin-right: 1%; - border: thin solid #c7c7c7; - box-shadow: inset 0 0 calc(3/1080*100%) #0000002a; - font-size: 8pt; - - padding-left: 1%; - " - ); - - let footer = css!( - " - height: 10%; - " - ); cx.render(rsx! { + style { STYLE_SHEET }, + div { - class: "{root}", + class: ClassName::CONTACTS_WINDOW, div { - class: "{header}", + class: ClassName::HEADER, div { - class: "{title_bar}", + class: ClassName::TITLE_BAR, }, div { - class: "{user_info}", + class: ClassName::USER_INFO, }, UserInfos {}, }, div { - class: "{contacts_nav}", + class: ClassName::CONTACTS_NAV, div { - class: "{contacts_nav_inner}", + class: ClassName::INNER, button { - class: "aero-button", + class: ClassName::AERO_BUTTON, style: "background: url(./images/letter.png) center no-repeat", }, button { - class: "aero-button", + class: ClassName::AERO_BUTTON, style: "background: url(./images/directory.png) no-repeat center", }, button { - class: "aero-button", + class: ClassName::AERO_BUTTON, style: "background: url(./images/news.png) no-repeat center", }, button { - class: "aero-button flex-right", + class: ClassName::FLEX_RIGHT_AERO_BUTTON, style: "background: url(./images/brush.png) no-repeat center", }, button { - class: "aero-button", + class: ClassName::AERO_BUTTON, style: "background: url(./images/settings.png) no-repeat center", }, @@ -154,24 +63,24 @@ pub fn ContactWindow(cx: Scope) -> Element { }, div { - class: "{search}", + class: ClassName::SEARCH, div { - class: "{search_inner}", + class: ClassName::INNER, input { - class: "{search_input}", + class: ClassName::SEARCH_INPUT, placeholder: "Find a contact...", r#type: "text", }, button { - class: "button", + class: ClassName::BUTTON, style: "background: url(./images/add_user.png) no-repeat center", }, button { - class: "button", + class: ClassName::BUTTON, style: "background: url(./images/tbc_transfert.png) no-repeat center", }, }, @@ -180,7 +89,7 @@ pub fn ContactWindow(cx: Scope) -> Element { Contacts {}, div { - class: "{footer}", + class: ClassName::FOOTER, }, }, }) diff --git a/src/components/contacts_window.scss b/src/components/contacts_window.scss new file mode 100644 index 0000000..51e5322 --- /dev/null +++ b/src/components/contacts_window.scss @@ -0,0 +1,84 @@ +@import "../_base.scss"; + +.contactsWindow { + width: 100%; + height: 100%; + + background-color: #ECF6F9; + font-family: "Tahoma", sans-serif; + + border: thin solid #707070; + border-radius: 8px; + box-shadow: 0 0 5px #00000050; + + + .header { + height: 10%; + width: 100%; + + .titleBar { + height: 60%; + width: 100%; + background: + linear-gradient(180deg, #7DC5E3, #3883A3); + } + + .userInfo { + height: 40%; + width: 100%; + background: + linear-gradient(180deg, #00658B, #0077A6); + } + } + + .contactsNav { + height: calc(31/1080*100%); + background: + linear-gradient(180deg, #00658B, #0077A6); + + .inner { + margin-left: 1%; + margin-right: 1%; + height: 100%; + display: flex; + align-items: center; + + .flexRightAeroButton { + @extend .aeroButton; + + margin-left: auto; + } + } + } + + .search { + height: calc(38/1080*100%); + width: 100%; + + border-bottom: thin solid #e2eaf3; + + .inner { + height: 100%; + width: 98%; + padding-left: 1%; + display: flex; + flex-direction: row; + align-items: center; + + .searchInput { + height: calc(23/38*100%); + width: 100%; + margin-right: 1%; + border: thin solid #c7c7c7; + box-shadow: inset 0 0 calc(3/1080*100%) #0000002a; + font-size: 8pt; + + padding-left: 1%; + } + } + } + + .footer { + height: 10%; + } +} diff --git a/src/components/header.rs b/src/components/header.rs index 3c71131..1b672a0 100644 --- a/src/components/header.rs +++ b/src/components/header.rs @@ -1,25 +1,13 @@ use dioxus::prelude::*; -use sir::css; + +turf::style_sheet!("src/components/header.scss"); pub fn Header(cx: Scope) -> Element { - let header = css!( - " - height: 100%; - width: 100%; - display: flex; - - img { - height: 100%; - } - svg { - fill: white; - } - " - ); - cx.render(rsx! { + style { STYLE_SHEET }, + div { - class: "{header}", + class: ClassName::ROOT, img { // src: "./assets/live-logo2.png" src: "./images/logo-msn.png" diff --git a/src/components/header.scss b/src/components/header.scss new file mode 100644 index 0000000..f087add --- /dev/null +++ b/src/components/header.scss @@ -0,0 +1,13 @@ +.root { + height: 100%; + width: 100%; + display: flex; + + img { + height: 100%; + } + + svg { + fill: white; + } +} diff --git a/src/components/login.rs b/src/components/login.rs index e26e774..4849b01 100644 --- a/src/components/login.rs +++ b/src/components/login.rs @@ -1,5 +1,4 @@ use dioxus::prelude::*; -use sir::css; use std::str::FromStr; use std::sync::Arc; @@ -8,6 +7,8 @@ use crate::components::avatar_selector::AvatarSelector; use crate::components::header::Header; use crate::matrix_client::{LoginStyle, MatrixClient}; +turf::style_sheet!("src/components/login.scss"); + pub fn Login(cx: Scope) -> Element { let app_context = use_shared_state::(cx).unwrap(); @@ -17,68 +18,8 @@ pub fn Login(cx: Scope) -> Element { let empty_placeholder = String::from(""); - let root = css!( - " - width: 90%; - height: 98%; - - display: flex; - flex-direction: column; - align-items: center; - - padding: 5%; - padding-top: 2%; - - background: linear-gradient(rgb(138, 191, 209), rgb(236, 246, 249) 10%); - " - ); - - let header = css!( - " - height: 5%; - width: 100%; - " - ); - - let body = css!( - " - height: 50%; - width: 50%; - max-width: 400px; - - display: flex; - flex-direction: column; - justify-content: center; - - padding-bottom: 3%; - " - ); - - let footer_buttons = css!( - " - width: 100%; - - padding-top: 5%; - - display: flex; - justify-content: center; - " - ); - - let avatar_selector = css!( - " - height: 30%; - width: 100%; - " - ); - - let invalid_input_css = css!( - " - border-color: red; - " - ); let password_class = if **invalid_login { - invalid_input_css + ClassName::INVALID_INPUT } else { "" }; @@ -114,18 +55,20 @@ pub fn Login(cx: Scope) -> Element { }; cx.render(rsx! { + style { STYLE_SHEET }, + div { - class: "{root}", + class: ClassName::ROOT, div { - class: "{header}", + class: ClassName::HEADER, Header {}, }, div { - class: "{body}", + class: ClassName::BODY, div { - class: "{avatar_selector}", + class: ClassName::AVATAR_SELECTOR, AvatarSelector {}, }, @@ -166,9 +109,9 @@ pub fn Login(cx: Scope) -> Element { }, div { - class: "{footer_buttons}", + class: ClassName::FOOTER_BUTTONS, input { - class: "button", + class: ClassName::BUTTON, onclick: run_matrix_client, r#type: "submit", value: "sign in", diff --git a/src/components/login.scss b/src/components/login.scss new file mode 100644 index 0000000..8c39f89 --- /dev/null +++ b/src/components/login.scss @@ -0,0 +1,51 @@ +@import "../_base.scss"; + +.root { + width: 90%; + height: 98%; + + display: flex; + flex-direction: column; + align-items: center; + + padding: 5%; + padding-top: 2%; + + background: linear-gradient(rgb(138, 191, 209), rgb(236, 246, 249) 10%); + + .header { + height: 5%; + width: 100%; + } + + .body { + height: 50%; + width: 50%; + max-width: 400px; + + display: flex; + flex-direction: column; + justify-content: center; + + padding-bottom: 3%; + + .invalidInput { + border-color: red; + } + + .avatarSelector { + height: 30%; + width: 100%; + } + + + .footerButtons { + width: 100%; + + padding-top: 5%; + + display: flex; + justify-content: center; + } + } +} diff --git a/src/components/user_infos.rs b/src/components/user_infos.rs index db1fa3e..d98cd39 100644 --- a/src/components/user_infos.rs +++ b/src/components/user_infos.rs @@ -1,123 +1,52 @@ use dioxus::prelude::*; use dioxus_free_icons::icons::md_navigation_icons::MdArrowDropDown; use dioxus_free_icons::Icon; -use sir::{css, global_css}; use crate::components::avatar_selector::AvatarSelector; -fn DownArrowIcon(cx: Scope) -> Element { - let style = css!( - " - color: transparent; - path:last-child { - fill: white; - } - " - ); +turf::style_sheet!("src/components/user_infos.scss"); +fn DownArrowIcon(cx: Scope) -> Element { cx.render(rsx! { + style { STYLE_SHEET }, + Icon { - class: "{style}", + class: ClassName::DOWN_ARROW_ICON, icon: MdArrowDropDown, } }) } pub fn UserInfos(cx: Scope) -> Element { - global_css!( - " - .flex-right { - margin-left: auto; - } - - .user-info { - position: relative; - height: 75%; - width: 99%; - top: -75%; - left: 1%; - aspect-ratio: 1; - z-index: 1; - display: flex; - flex-direction: row; - align-items: center; - - .avatar-selector { - height: 100%; - aspect-ratio: 1; - } - - .info-container { - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: center; - height: 100%; - width: 100%; - // font-size: 8pt; - - .user-id { - height: 30%; - width: fit-content; - display: flex; - text-align: begin; - align-items: center; - - .user-name { - display: inline-block; - width: fit-content; - color: white; - margin: 0; - // font-size: 10pt; - } - - .user-status { - display: inline-block; - width: fit-content; - color: #B9DDE7; - } - } - - .user-message { - width: fit-content; - height: 30%; - display: flex; - text-align: begin; - align-items: center; - margin: 0; - color: white; - } - } - }" - ); - cx.render(rsx! { + style { STYLE_SHEET }, + div { - class: "user-info", + class: ClassName::USER_INFO, div { - class: "avatar-selector", + class: ClassName::AVATAR_SELECTOR, AvatarSelector {}, }, div { - class: "info-container", + class: ClassName::INFO_CONTAINER, div { - class: "aero-button user-id", + class: ClassName::USER_ID, p { - class: "user-name", + class: ClassName::USER_NAME, "SUPER USER" }, p { - class: "user-status", + class: ClassName::USER_STATUS, "(Busy)", }, DownArrowIcon {}, }, div { - class: "aero-button user-message", + class: ClassName::USER_MESSAGE, p { "My message", } diff --git a/src/components/user_infos.scss b/src/components/user_infos.scss new file mode 100644 index 0000000..0829d0e --- /dev/null +++ b/src/components/user_infos.scss @@ -0,0 +1,71 @@ +@import "../_base.scss" + +.userInfo { + position: relative; + height: 75%; + width: 99%; + top: -75%; + left: 1%; + aspect-ratio: 1; + z-index: 1; + display: flex; + flex-direction: row; + align-items: center; + + .avatarSelector { + height: 100%; + aspect-ratio: 1; + } + + .infoContainer { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + height: 100%; + width: 100%; + + .userId { + @extend .aeroButton; + + height: 30%; + width: fit-content; + display: flex; + text-align: begin; + align-items: center; + + .userName { + display: inline-block; + width: fit-content; + color: white; + margin: 0; + } + + .userStatus { + display: inline-block; + width: fit-content; + color: #B9DDE7; + } + } + + .userMessage { + @extend .aeroButton; + + width: fit-content; + height: 30%; + display: flex; + text-align: begin; + align-items: center; + margin: 0; + color: white; + } + } +} + +.downArrowIcon { + color: transparent; + + path:last-child { + fill: white; + } +} diff --git a/src/main.rs b/src/main.rs index 7937ed1..778a61f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,8 +2,6 @@ use dioxus::prelude::*; use dioxus_desktop::Config; -use sir::{global_css, AppStyle}; - pub mod app_settings; pub mod components; pub mod matrix_client; @@ -19,70 +17,18 @@ fn App(cx: Scope) -> Element { let app_context = use_shared_state::(cx).unwrap(); - global_css!( - " - body { - height: 100vh; - width: 100vw; - margin: 0px; - padding: 0px; - outline: 0px; - font-family: Tahoma, sans-serif; - } - #main { - height: 100%; - width: 100%; - } - - .aero-button { - height: 50%; - min-height: 16px; - aspect-ratio: 1; - background-color: transparent; - border: 2px solid transparent; - background-size: contain !important; - margin-right: 1%; - } - .aero-button:hover { - border-image: url(./images/aerobutton_border.png) 2 round; - } - .aero-button:active { - border-image: url(./images/aerobutton_border_down.png) 2 round; - } - - .button { - height: 50%; - min-height: 16px; - aspect-ratio: 1; - background-color: transparent; - border: 2px solid transparent; - background-size: contain !important; - margin-right: 1%; - } - .button:hover { - border-image: url(./images/button_border.png) 2 round; - } - .button:active { - border-image: url(./images/button_border_down.png) 2 round; - } - " - ); - // let window = dioxus_desktop::use_window(cx); // let dom = VirtualDom::new(ControlWindow); // window.new_window(dom, cx.props.clone()); - if app_context.read().store.is_logged { - cx.render(rsx! { - AppStyle {}, - ContactWindow {}, - }) - } else { - cx.render(rsx! { - AppStyle {}, - Login {} - }) - } + cx.render(rsx! { + if app_context.read().store.is_logged { + rsx!(ContactWindow {}) + } + else { + rsx!(Login {}) + } + }) } #[tokio::main]