From 8aa7ba43ccc5171ccb8b4f1ee5ee55774f3a67c6 Mon Sep 17 00:00:00 2001
From: Midhun Suresh <midhunr@element.io>
Date: Wed, 19 Jan 2022 13:40:06 +0530
Subject: [PATCH] Implement UI

---
 src/style.css                         | 63 ++++++++++++++++++++++-----
 src/ui/res/chevron-down.svg           | 36 +++++++++++++++
 src/ui/res/matrix-logo.svg            |  5 +++
 src/ui/views/ChatterboxView.ts        | 18 +++++++-
 src/viewmodels/ChatterboxViewModel.ts | 21 ++++++---
 src/viewmodels/RootViewModel.ts       | 26 ++++++-----
 6 files changed, 137 insertions(+), 32 deletions(-)
 create mode 100644 src/ui/res/chevron-down.svg
 create mode 100644 src/ui/res/matrix-logo.svg

diff --git a/src/style.css b/src/style.css
index ffaf7aa..a8d8a4c 100644
--- a/src/style.css
+++ b/src/style.css
@@ -3,14 +3,11 @@
     bottom: 10px;
     right: 10px;
     max-width: 375px;
+    border-radius: 5px;
 }
 
 #chatterbox .Timeline {
-    height: 500px;
-}
-
-#chatterbox>div {
-    border-radius: 5px;
+    height: 450px;
 }
 
 /*
@@ -26,7 +23,6 @@ todo: this style should actually be in hydrogen-web
     width: 32px;
     height: 32px;
     border: none;
-    margin: 5px;
     background: no-repeat center url('./ui/res/chat-bubbles.svg'), #295dbd;
     border-radius: 2px;
     cursor: pointer;
@@ -40,8 +36,8 @@ todo: this style should actually be in hydrogen-web
     justify-content: space-evenly;
     height: 80px;
     width: 320px;
-    border-radius: 5px;
 }
+
 .PolicyAgreementView-text {
     padding-bottom: 10px;
 }
@@ -67,15 +63,58 @@ todo: this style should actually be in hydrogen-web
 
 .ChatterboxView {
     width: 375px;
-    height: 570px;
+    height: 595px;
+}
+
+.RoomHeaderView {
+    display: grid;
+    grid-template-columns: 1fr 6fr 1fr;
+    align-items: center;
+    padding: 10px 15px;
+    height: 35px;
+    background-color: #295dbd;
+    border-radius: 5px 5px  0 0;
+    color: white;
+    font-weight: 600;
+    font-size: 1.5rem;
+}
+
+.RoomHeaderView_menu {
+    display: flex;
+    justify-content: end;
 }
 
-.hydrogen {
-    background-color: transparent !important;
+.RoomHeaderView_menu_minimize {
+    background: url("./ui/res/chevron-down.svg") no-repeat;
+    height: 20px;
+    width: 20px;
+    border: none;
+    cursor: pointer;
+}
+
+.RoomHeaderView .avatar {
+    border-radius: 2px;
+}
+
+.ChatterboxView_footer {
+    display: flex;
+    align-items: center;
+    justify-content: end;
+    font-size: 1.0rem;
+    font-weight: 600;
+    box-sizing: border-box;
+    padding-right: 53px;
+    color: #9b9797;
 }
 
-.hydrogen :not(.StartChat) {
-    background-color: rgba(245, 245, 245, 0.90);
+.ChatterboxView_footer>img {
+    width: 35px;
+    padding-left: 4px;
+}
+
+.ChatterboxView .MessageComposer_input>textarea {
+    border-radius: 5px;
+    border: #c2bebe 1.5px solid;
 }
 
 body {
diff --git a/src/ui/res/chevron-down.svg b/src/ui/res/chevron-down.svg
new file mode 100644
index 0000000..12c9e04
--- /dev/null
+++ b/src/ui/res/chevron-down.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   width="17"
+   height="9"
+   viewBox="0 0 17 9"
+   fill="none"
+   version="1.1"
+   id="svg839"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <g
+     clip-path="url(#clip0)"
+     id="g832"
+     transform="rotate(-90,4.3001277,4.8826258)">
+    <path
+       fill-rule="evenodd"
+       clip-rule="evenodd"
+       d="M 8.20723,2.70711 C 8.59775,3.09763 8.59878,3.73182 8.20952,4.1236 L 3.27581,9.08934 8.22556,14.0391 c 0.39052,0.3905 0.39155,1.0247 0.00229,1.4165 -0.38926,0.3918 -1.0214,0.3928 -1.41192,0.0023 L 1.15907,9.80101 C 0.768549,9.41049 0.767523,8.7763 1.15678,8.38452 L 6.79531,2.70939 C 7.18457,2.31761 7.8167,2.31658 8.20723,2.70711 Z"
+       fill="#fff"
+       id="path830" />
+  </g>
+  <defs
+     id="defs837">
+    <clipPath
+       id="clip0">
+      <rect
+         width="8"
+         height="17"
+         fill="#ffffff"
+         transform="rotate(180,4.25,8.5)"
+         id="rect834"
+         x="0"
+         y="0" />
+    </clipPath>
+  </defs>
+</svg>
diff --git a/src/ui/res/matrix-logo.svg b/src/ui/res/matrix-logo.svg
new file mode 100644
index 0000000..d24a428
--- /dev/null
+++ b/src/ui/res/matrix-logo.svg
@@ -0,0 +1,5 @@
+<svg width="75" height="32" xmlns="http://www.w3.org/2000/svg">
+  <g fill="#9b9797" fill-rule="nonzero">
+    <path d="M.936.732V31.25H3.13v.732H.095V0h3.034v.732zM9.386 10.407v1.544h.044a4.461 4.461 0 0 1 1.487-1.368c.58-.323 1.245-.485 1.993-.485.72 0 1.377.14 1.972.42.595.279 1.047.771 1.355 1.477.338-.5.796-.941 1.377-1.323.58-.383 1.266-.574 2.06-.574.602 0 1.16.074 1.674.22.514.148.954.383 1.322.707.366.323.653.746.859 1.268.205.522.308 1.15.308 1.887v7.633H20.71v-6.464c0-.383-.015-.743-.044-1.082a2.305 2.305 0 0 0-.242-.882 1.473 1.473 0 0 0-.584-.596c-.257-.146-.606-.22-1.047-.22-.44 0-.796.085-1.068.253-.272.17-.485.39-.639.662a2.654 2.654 0 0 0-.308.927 7.074 7.074 0 0 0-.078 1.048v6.354h-3.128v-6.398c0-.338-.007-.673-.021-1.004a2.825 2.825 0 0 0-.188-.916 1.411 1.411 0 0 0-.55-.673c-.258-.168-.636-.253-1.135-.253a2.33 2.33 0 0 0-.584.1 1.94 1.94 0 0 0-.705.374c-.228.184-.422.449-.584.794-.161.346-.242.798-.242 1.357v6.619H6.434V10.407h2.952zM25.842 12.084a3.751 3.751 0 0 1 1.233-1.17 5.37 5.37 0 0 1 1.685-.629 9.579 9.579 0 0 1 1.884-.187c.573 0 1.153.04 1.74.121.588.081 1.124.24 1.609.475.484.235.88.562 1.19.981.308.42.462.975.462 1.666v5.934c0 .516.03 1.008.088 1.478.058.471.161.824.308 1.06H32.87a4.435 4.435 0 0 1-.22-1.104c-.5.515-1.087.876-1.762 1.081a7.084 7.084 0 0 1-2.071.31c-.544 0-1.05-.067-1.52-.2a3.472 3.472 0 0 1-1.234-.617 2.87 2.87 0 0 1-.826-1.059c-.199-.426-.298-.934-.298-1.522 0-.647.114-1.18.342-1.6.227-.419.52-.753.881-1.004.36-.25.771-.437 1.234-.562.462-.125.929-.224 1.399-.298.47-.073.932-.132 1.387-.176.456-.044.86-.11 1.212-.199.353-.088.631-.217.837-.386.206-.169.301-.415.287-.74 0-.337-.055-.606-.166-.804a1.217 1.217 0 0 0-.44-.464 1.737 1.737 0 0 0-.639-.22 5.292 5.292 0 0 0-.782-.055c-.617 0-1.101.132-1.454.397-.352.264-.558.706-.617 1.323h-3.128c.044-.735.227-1.345.55-1.83zm6.179 4.423a5.095 5.095 0 0 1-.639.165 9.68 9.68 0 0 1-.716.11c-.25.03-.5.067-.749.11a5.616 5.616 0 0 0-.694.177 2.057 2.057 0 0 0-.594.298c-.17.125-.305.284-.408.474-.103.192-.154.434-.154.728 0 .28.051.515.154.706.103.192.242.342.419.453.176.11.381.187.617.231.234.044.477.066.726.066.617 0 1.094-.102 1.432-.309.338-.205.587-.452.75-.739.16-.286.26-.576.297-.87.036-.295.055-.53.055-.707v-1.17a1.4 1.4 0 0 1-.496.277zM43.884 10.407v2.096h-2.291v5.647c0 .53.088.883.264 1.059.176.177.529.265 1.057.265.177 0 .345-.007.507-.022.161-.015.316-.037.463-.066v2.426a7.49 7.49 0 0 1-.882.089 21.67 21.67 0 0 1-.947.022c-.484 0-.944-.034-1.377-.1a3.233 3.233 0 0 1-1.145-.386 2.04 2.04 0 0 1-.782-.816c-.191-.353-.287-.816-.287-1.39v-6.728H36.57v-2.096h1.894v-3.42h3.129v3.42h2.29zM48.355 10.407v2.118h.044a3.907 3.907 0 0 1 1.454-1.754 4.213 4.213 0 0 1 1.036-.497 3.734 3.734 0 0 1 1.145-.176c.206 0 .433.037.683.11v2.912a5.862 5.862 0 0 0-.528-.077 5.566 5.566 0 0 0-.595-.033c-.573 0-1.058.096-1.454.287a2.52 2.52 0 0 0-.958.783 3.143 3.143 0 0 0-.518 1.158 6.32 6.32 0 0 0-.154 1.434v5.14h-3.128V10.407h2.973zM54.039 8.642V6.06h3.128v2.582H54.04zm3.128 1.765v11.405H54.04V10.407h3.128zM58.797 10.407h3.569l2.005 2.978 1.982-2.978h3.459l-3.745 5.339 4.208 6.067h-3.57l-2.378-3.596-2.38 3.596h-3.502l4.097-6.001zM74.094 31.25V.732H71.9V0h3.035v31.982H71.9v-.732z"/>
+  </g>
+</svg>
diff --git a/src/ui/views/ChatterboxView.ts b/src/ui/views/ChatterboxView.ts
index 632bd0b..9d40096 100644
--- a/src/ui/views/ChatterboxView.ts
+++ b/src/ui/views/ChatterboxView.ts
@@ -1,4 +1,4 @@
-import { TemplateView, TimelineView, LoadingView } from "hydrogen-view-sdk";
+import { TemplateView, TimelineView, LoadingView, AvatarView, RoomViewModel } from "hydrogen-view-sdk";
 import { Builder } from "hydrogen-view-sdk/types/platform/web/ui/general/TemplateView";
 import { MessageComposer } from "hydrogen-view-sdk";
 import { ChatterboxViewModel } from "../../viewmodels/ChatterboxViewModel";
@@ -6,8 +6,22 @@ import { ChatterboxViewModel } from "../../viewmodels/ChatterboxViewModel";
 export class ChatterboxView extends TemplateView<ChatterboxViewModel> {
     render(t: Builder<ChatterboxViewModel>) {
         return t.div({className: "ChatterboxView"}, [
+            t.mapView(vm => vm.roomViewModel? vm: null, vm => vm ? new RoomHeaderView(vm) : null),
             t.mapView(vm => vm.timelineViewModel, vm => vm ? new TimelineView(vm) : new LoadingView()),
-            t.mapView(vm => vm.messageComposerViewModel, vm => vm ? new MessageComposer(vm) : null)
+            t.mapView(vm => vm.messageComposerViewModel, vm => vm ? new MessageComposer(vm) : null),
+            t.div({className: "ChatterboxView_footer"}, ["Powered by", t.img({src:"./src/ui/res/matrix-logo.svg"})]),
+        ]);
+    }
+}
+
+class RoomHeaderView extends TemplateView<ChatterboxViewModel> {
+    render(t: Builder<ChatterboxViewModel>, vm) {
+        return t.div({ className: "RoomHeaderView" }, [
+            t.view(new AvatarView(vm.roomViewModel, 30)),
+            t.div({ className: "RoomHeaderView_name" }, vm => vm.roomViewModel.name),
+            t.div({ className: "RoomHeaderView_menu" }, [
+                t.button({ className: "RoomHeaderView_menu_minimize", onClick: () => vm.minimize() })
+            ]),
         ]);
     }
 }
diff --git a/src/viewmodels/ChatterboxViewModel.ts b/src/viewmodels/ChatterboxViewModel.ts
index b3c3d36..342b4b7 100644
--- a/src/viewmodels/ChatterboxViewModel.ts
+++ b/src/viewmodels/ChatterboxViewModel.ts
@@ -1,14 +1,16 @@
 import { RoomViewModel, ViewModel, TimelineViewModel, ComposerViewModel} from "hydrogen-view-sdk";
 
 export class ChatterboxViewModel extends ViewModel {
-    private _timelineViewModel?: TimelineViewModel;
     private _messageComposerViewModel?: ComposerViewModel;
+    private _roomViewModel?: RoomViewModel;
     private _loginPromise: Promise<void>;
+    private _applySegment: (segment) => void;
 
     constructor(options) {
         super(options);
         this._client = options.client;
         this._loginPromise = options.loginPromise;
+        this._applySegment = options.applySegment;
     }
 
     async loadRoom() {
@@ -16,16 +18,15 @@ export class ChatterboxViewModel extends ViewModel {
         await this._loginPromise;
         const roomId = this._options.config["auto_join_room"];
         const room = this._session.rooms.get(roomId) ?? await this._joinRoom(roomId);
-        const roomVm = new RoomViewModel({
+        this._roomViewModel = new RoomViewModel({
             room,
             ownUserId: this._session.userId,
             platform: this.platform,
             urlCreator: this.urlCreator,
             navigation: this.navigation,
         });
-        await roomVm.load();
-        this._timelineViewModel = roomVm.timelineViewModel;
-        this._messageComposerViewModel = new ComposerViewModel(roomVm);
+        await this._roomViewModel.load();
+        this._messageComposerViewModel = new ComposerViewModel(this._roomViewModel);
         this.emitChange("timelineViewModel");
     }
 
@@ -52,13 +53,21 @@ export class ChatterboxViewModel extends ViewModel {
         return promise;
     }
 
+    minimize() {
+        this._applySegment("start");
+    }
+
     get timelineViewModel() {
-        return this._timelineViewModel;
+        return this._roomViewModel?.timelineViewModel;
     }
 
     get messageComposerViewModel() {
         return this._messageComposerViewModel;
     }
+    
+    get roomViewModel() {
+        return this._roomViewModel;
+    }
 
     private get _session() {
         return this._client.session;
diff --git a/src/viewmodels/RootViewModel.ts b/src/viewmodels/RootViewModel.ts
index 7957949..fa7a999 100644
--- a/src/viewmodels/RootViewModel.ts
+++ b/src/viewmodels/RootViewModel.ts
@@ -39,29 +39,31 @@ export class RootViewModel extends ViewModel {
 
     private async _showTimeline(loginPromise: Promise<void>) {
         this._activeSection = "timeline";
-        this._chatterBoxViewModel = new ChatterboxViewModel(
-            this.childOptions({
-                client: this._client,
-                config: this._config,
-                state: this._state,
-                applySegment: this._applySegment,
-                loginPromise,
-            })
-        );
-        this._chatterBoxViewModel.loadRoom();
+        if (!this._chatterBoxViewModel) {
+            this._chatterBoxViewModel = this.track(new ChatterboxViewModel(
+                this.childOptions({
+                    client: this._client,
+                    config: this._config,
+                    state: this._state,
+                    applySegment: this._applySegment,
+                    loginPromise,
+                })
+            ));
+            this._chatterBoxViewModel.loadRoom();
+        }
         this.emitChange("activeSection");
     }
 
     private _showAccountSetup() {
         this._activeSection = "account-setup";
-        this._accountSetupViewModel = new AccountSetupViewModel(
+        this._accountSetupViewModel = this.track(new AccountSetupViewModel(
             this.childOptions({
                 client: this._client,
                 config: this._config,
                 state: this._state,
                 applySegment: this._applySegment,
             })
-        );
+        ));
         this.emitChange("activeSection");
     }
 
-- 
GitLab