daydream

A small matrix web client written in rust
git clone git://archive.git.mtrnord.blog/daydream-mx/daydream.git
Log | Files | Refs | README | LICENSE

commit 21ba1721c673d73d8bd48e14c01cf41189f69068
parent 80c9da538552e39d62b69cd566f2380f52d0fc7d
Author: Marcel <mtrnord1@gmail.com>
Date:   Fri, 29 May 2020 14:22:45 +0200

Add darkteam

Took 3 hours 19 minutes

Diffstat:
MCargo.toml | 2++
Msrc/app/components/event_list.rs | 19+++++++++++++------
Msrc/app/components/room_list.rs | 47++++++++++++++++++++++++++++++++++++++++++++---
Msrc/app/matrix.rs | 30++++++++++++++----------------
Msrc/app/matrix/types.rs | 6++++--
Msrc/app/views/main_view.rs | 2+-
Astatic/custom-css.scss | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astatic/dark_theme/_globals.scss | 8++++++++
Astatic/dark_theme/_variables.scss | 18++++++++++++++++++
Mstatic/index.html | 2+-
Astatic/light_theme/_globals.scss | 7+++++++
Astatic/light_theme/_variables.scss | 17+++++++++++++++++
Mstatic/style.scss | 99++++++++++++++++++++++++++++++-------------------------------------------------
13 files changed, 223 insertions(+), 90 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -37,6 +37,8 @@ wasm-bindgen-test = "0.3" version = "0.3" features = [ 'KeyboardEvent', + 'HtmlElement', + 'DomStringMap' ] [profile.release] diff --git a/src/app/components/event_list.rs b/src/app/components/event_list.rs @@ -92,9 +92,15 @@ impl Component for EventList { } Response::OldMessages(messages) => { // TODO this doesn't seem smart - // let mut new_events_map = LinkedHashSet::new(); + // let mut new_events_map = LinkedHashSet::new(); info!("{}", self.state.events.len()); - self.state.events = self.state.events.clone().into_iter().chain(messages).collect(); + self.state.events = self + .state + .events + .clone() + .into_iter() + .chain(messages) + .collect(); info!("{}", self.state.events.len()); /*for event in self.state.events.clone().into_iter() { new_events_map.insert(event); @@ -142,7 +148,8 @@ impl Component for EventList { .collect::<LinkedHashSet<&MessageWrapper>>() .is_empty() { - self.matrix_agent.send(Request::GetOldMessages((room_id.clone(), None))); + self.matrix_agent + .send(Request::GetOldMessages((room_id.clone(), None))); } } self.props = props; @@ -160,12 +167,12 @@ impl Component for EventList { { self.state.events.iter().filter(|x| x.room_id.clone().unwrap() == self.props.current_room.clone().unwrap()).map(|event| self.get_event(event.clone())).collect::<Html>() } <div id="anchor"></div> </div> - <form + <form class="uk-margin" onsubmit=self.link.callback(|e: FocusEvent| {e.prevent_default(); Msg::Nope}) onkeypress=self.link.callback(|e: KeyboardEvent| { if e.key() == "Enter" { Msg::SendMessage } else { Msg::Nope } })> - <div class="uk-margin"> + <div> <div class="uk-inline" style="display: block !important;"> <span class="uk-form-icon" uk-icon="icon: pencil"></span> <input class="uk-input" type="text" @@ -184,7 +191,7 @@ impl Component for EventList { impl EventList { fn get_event(&self, event: MessageWrapper) -> Html { html! { - <p>{event.sender_displayname.unwrap_or(event.sender.to_string()).clone()}{": "}{event.content.clone()}</p> + <p>{event.sender_displayname.unwrap_or(event.sender.to_string()).clone()}{": "}{event.content.clone()}</p> } } } diff --git a/src/app/components/room_list.rs b/src/app/components/room_list.rs @@ -6,9 +6,12 @@ use serde::{Deserialize, Serialize}; use yew::prelude::*; use yew::{Bridge, Bridged, Component, ComponentLink, Html}; use yewtil::NeqAssign; +use web_sys::HtmlElement; +use wasm_bindgen::JsCast; use crate::app::matrix::types::SmallRoom; use crate::app::matrix::{MatrixAgent, Request, Response}; +use yew::utils::document; pub struct RoomList { link: ComponentLink<Self>, @@ -21,6 +24,7 @@ pub enum Msg { NewMessage(Response), ChangeRoom(String), SetFilter(String), + ToggleTheme, } #[derive(Serialize, Deserialize, Default)] @@ -29,6 +33,7 @@ pub struct State { current_room: Option<String>, loading: bool, search_query: Option<String>, + dark_theme: bool, } #[derive(Clone, PartialEq, Properties)] @@ -49,6 +54,7 @@ impl Component for RoomList { current_room: None, loading: true, search_query: None, + dark_theme: false, }; RoomList { @@ -96,7 +102,9 @@ impl Component for RoomList { .filter(|(id, _)| **id == room) .map(|(_, room)| room.name.clone()) .collect::<String>(); - self.props.change_room_callback.emit((displayname, room.clone())); + self.props + .change_room_callback + .emit((displayname, room.clone())); self.state.current_room = Some(room); true } @@ -104,6 +112,23 @@ impl Component for RoomList { self.state.search_query = Some(query); true } + Msg::ToggleTheme => { + self.state.dark_theme = !self.state.dark_theme; + let theme = if self.state.dark_theme { + "dark" + } else { + "light" + }; + document() + .document_element() + .unwrap() + .dyn_into::<HtmlElement>() + .unwrap() + .dataset() + .set("theme", theme) + .unwrap(); + true + } } } @@ -123,7 +148,7 @@ impl Component for RoomList { } else { return html! { <div class="container uk-flex uk-flex-column uk-width-1-6" style="height: 100%"> - <div class="uk-padding uk-padding-remove-bottom"> + <div class="uk-padding uk-padding-remove-bottom" style="height: 50px"> <form class="uk-search uk-search-default"> <span uk-search-icon=""></span> <input @@ -134,7 +159,7 @@ impl Component for RoomList { oninput=self.link.callback(|e: InputData| Msg::SetFilter(e.value)) /> </form> </div> - <ul class="scrollable uk-flex uk-flex-column uk-padding uk-nav-default uk-nav-parent-icon" uk-nav="" style="height: 100%"> + <ul class="scrollable uk-flex uk-flex-column uk-padding uk-nav-default uk-nav-parent-icon uk-padding-remove-bottom" uk-nav=""> <li class="uk-nav-header">{"Rooms"}</li> { if self.state.search_query.is_none() || (self.state.search_query.clone().unwrap_or("".to_string()) == "".to_string()) { @@ -144,6 +169,22 @@ impl Component for RoomList { } } </ul> + <div class="toggleWrapper uk-margin uk-flex uk-flex-column uk-flex-center" style="height: 60px;"> + <input type="checkbox" class="dn" id="dn" checked=self.state.dark_theme value=self.state.dark_theme onclick=self.link.callback(|e: MouseEvent| {Msg::ToggleTheme})/> + <label for="dn" class="toggle"> + <span class="toggle__handler"> + <span class="crater crater--1"></span> + <span class="crater crater--2"></span> + <span class="crater crater--3"></span> + </span> + <span class="star star--1"></span> + <span class="star star--2"></span> + <span class="star star--3"></span> + <span class="star star--4"></span> + <span class="star star--5"></span> + //<span class="star star--6"></span> + </label> + </div> </div> }; } diff --git a/src/app/matrix.rs b/src/app/matrix.rs @@ -23,7 +23,7 @@ use yew::worker::*; use crate::app::matrix::types::{MessageWrapper, SmallRoom}; use crate::constants::AUTH_KEY; use crate::errors::MatrixError; -use comrak::{Arena, ComrakOptions, parse_document, format_html}; +use comrak::{format_html, parse_document, Arena, ComrakOptions}; mod sync; pub mod types; @@ -339,29 +339,27 @@ impl Agent for MatrixAgent { spawn_local(async move { let arena = Arena::new(); - let root = parse_document( - &arena, - message.clone().as_str(), - &ComrakOptions::default()); + let root = + parse_document(&arena, message.clone().as_str(), &ComrakOptions::default()); let mut html = vec![]; format_html(root, &ComrakOptions::default(), &mut html).unwrap(); - let mut formatted_message = String::from_utf8(html).unwrap(); - formatted_message = formatted_message.replace("<p>", "").replace("</p>",""); + let mut formatted_message = String::from_utf8(html).unwrap(); + formatted_message = formatted_message.replace("<p>", "").replace("</p>", ""); formatted_message.pop(); let content; if formatted_message == message { - content = - MessageEventContent::Text(TextMessageEventContent::new_plain(message.clone())); + content = MessageEventContent::Text(TextMessageEventContent::new_plain( + message.clone(), + )); } else { - content = - MessageEventContent::Text(TextMessageEventContent { - body: message.into(), - format: Some("org.matrix.custom.html".to_string()), - formatted_body: Some(formatted_message), - relates_to: None, - }); + content = MessageEventContent::Text(TextMessageEventContent { + body: message.into(), + format: Some("org.matrix.custom.html".to_string()), + formatted_body: Some(formatted_message), + relates_to: None, + }); } client.room_send(&room_id, content, None).await; }); diff --git a/src/app/matrix/types.rs b/src/app/matrix/types.rs @@ -37,8 +37,10 @@ impl MessageWrapper { .unwrap(); let room = room.read().await; let member = match room.members.get(&self.sender.clone()) { - None => {return self.sender.clone().to_string();}, - Some(v) => {v}, + None => { + return self.sender.clone().to_string(); + } + Some(v) => v, }; member .display_name diff --git a/src/app/views/main_view.rs b/src/app/views/main_view.rs @@ -76,7 +76,7 @@ impl Component for MainView { fn view(&self) -> Html { if self.state.current_room.is_none() { return html! { - <div class="uk-flex auto-scrollable-container" style="height: 100%"> + <div class="uk-flex auto-scrollable-container uk-background-default" style="height: 100%"> <RoomList change_room_callback=self.link.callback(Msg::ChangeRoom)/> <div class="container uk-flex uk-width-5-6 uk-padding"> diff --git a/static/custom-css.scss b/static/custom-css.scss @@ -0,0 +1,56 @@ +.scrollable { + overflow-y: auto !important; + overflow-x: hidden !important; + height: 100% !important; + scrollbar-width: thin; + scrollbar-color: $scrollbar-color $scrollbar-bg-color; +} + +.scrollable * { + /* don't allow the children of the scrollable element to be selected as an anchor node */ + overflow-anchor: none; +} + +#anchor { + /* allow the final child to be selected as an anchor node */ + overflow-anchor: auto; + + /* anchor nodes are required to have non-zero area */ + height: 1px; +} + +.scrollable::-webkit-scrollbar { + width: 11px; +} + +.non-scrollable-container { + overflow: hidden; +} + + +.auto-scrollable-container { + overflow: auto; +} + +.uk-badge.red { + background: #f0506e; +} + +.h-100 { + height: 100% !important; +} + +html { + overflow: hidden !important; + height: 100% !important; +} + +body { + overflow: hidden !important; + height: 100% !important; +} + +.menu { + width: 20rem; + padding: 1.5rem; +} diff --git a/static/dark_theme/_globals.scss b/static/dark_theme/_globals.scss @@ -0,0 +1,8 @@ +[data-theme="dark"] { + --global-background: #1c1c21; + --global-scrollbar-color: hsla(0,0%,100%,.2); + --global-scrollbar-bg-color: transparent; + --global-emphasis-color: #fff; + --global-color: #fff; + --icon-link-active-color: darken(#fff, 5%); +} diff --git a/static/dark_theme/_variables.scss b/static/dark_theme/_variables.scss @@ -0,0 +1,18 @@ +@at-root {@import "./globals.scss";} + +// Custom component colors +$scrollbar-color: var(--global-scrollbar-color); +$scrollbar-bg-color: var(--global-scrollbar-bg-color); + +// UIKit Colors +$global-background: var(--global-background); +$global-emphasis-color: var(--global-emphasis-color); +$global-color: var(--global-color); +$icon-link-active-color: var(--icon-link-active-color); + +.uk-input, .uk-search-input { + border: 1px solid $global-emphasis-color; +} + + +@import "../../node_modules/uikit/src/scss/variables-theme.scss"; diff --git a/static/index.html b/static/index.html @@ -1,5 +1,5 @@ <!doctype html> -<html lang="en"> +<html lang="en" data-theme="light"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> diff --git a/static/light_theme/_globals.scss b/static/light_theme/_globals.scss @@ -0,0 +1,7 @@ +[data-theme="light"] { + --global-scrollbar-color: hsla(0,0%,100%,.2); + --global-scrollbar-bg-color: transparent; + --global-emphasis-color: #333; + --global-color: #666; + --icon-link-active-color: darken(#666, 5%); +} diff --git a/static/light_theme/_variables.scss b/static/light_theme/_variables.scss @@ -0,0 +1,17 @@ +@at-root {@import "./globals.scss";} + +// Custom component colors +$scrollbar-color: var(--global-scrollbar-color); +$scrollbar-bg-color: var(--global-scrollbar-bg-color); + +// UIKit Colors +$global-background: var(--global-background); +$global-emphasis-color: var(--global-emphasis-color); +$global-color: var(--global-color); +$icon-link-active-color: var(--icon-link-active-color); + +.uk-input { + border: 1px solid $global-emphasis-color; +} + +@import "../../node_modules/uikit/src/scss/variables-theme.scss"; diff --git a/static/style.scss b/static/style.scss @@ -1,63 +1,40 @@ -$scrollbar-color: hsla(0,0%,100%,.2); -$scrollbar-bg-color: #181b21; - -.scrollable { - overflow-y: auto !important; - overflow-x: hidden !important; - height: 100% !important; - scrollbar-width: thin; - scrollbar-color: $scrollbar-bg-color $scrollbar-color; -} - -.scrollable * { - /* don't allow the children of the scrollable element to be selected as an anchor node */ - overflow-anchor: none; -} - -#anchor { - /* allow the final child to be selected as an anchor node */ - overflow-anchor: auto; - - /* anchor nodes are required to have non-zero area */ - height: 1px; -} - -.scrollable::-webkit-scrollbar { - width: 11px; -} - -.non-scrollable-container { - overflow: hidden; -} - - -.auto-scrollable-container { - overflow: auto; -} - -.uk-badge.red { - background: #f0506e; -} - -.h-100 { - height: 100% !important; -} - -html { - overflow: hidden !important; - height: 100% !important; -} - -body { - overflow: hidden !important; - height: 100% !important; -} - -.menu { - width: 20rem; - padding: 1.5rem; +@import "theme_slider.scss"; + +[data-theme="dark"] { + @import "static/dark_theme/variables"; + + [data-theme] { + background-color: var(--global-background); + color: white; + } + + @at-root { + @import "custom-css.scss"; + } + @at-root { + @import "../node_modules/uikit/src/scss/mixins-theme.scss"; + } + @at-root { + @import "../node_modules/uikit/src/scss/uikit-theme.scss"; + } +} + +[data-theme="light"] { + @import "static/light_theme/variables"; + + [data-theme] { + background-color: var(--global-background); + color: black; + } + + @at-root { + @import "custom-css.scss"; + } + @at-root { + @import "../node_modules/uikit/src/scss/mixins-theme.scss"; + } + @at-root { + @import "../node_modules/uikit/src/scss/uikit-theme.scss"; + } } -@import "../node_modules/uikit/src/scss/variables-theme.scss"; -@import "../node_modules/uikit/src/scss/mixins-theme.scss"; -@import "../node_modules/uikit/src/scss/uikit-theme.scss";