From 26c9aaebfdf21e090ce2337ad62ca7ad19c5236f Mon Sep 17 00:00:00 2001 From: Sofiane Date: Sat, 5 Jun 2021 01:44:41 -0400 Subject: [PATCH] finished styling v1 --- package-lock.json | 11 ++ package.json | 1 + resources/public/css/styles.css | 118 ++++++++++++------ resources/public/html/chat.html | 20 ++- src/buddylistclient/main/core.cljs | 27 ++-- src/buddylistclient/main/user.cljs | 25 ++-- .../renderer/buddies/core.cljs | 89 ++++++------- src/buddylistclient/renderer/chat/core.cljs | 93 +++++++++++--- yarn.lock | 5 + 9 files changed, 266 insertions(+), 123 deletions(-) diff --git a/package-lock.json b/package-lock.json index 01846e5..1f46410 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "react-phone-number-input": "^3.1.22", "request": "^2.51.0", "request-promise": "^4.2.6", + "s-ago": "^2.2.0", "schema-utils": "2.6.6", "sound-play": "^1.1.0", "tailwindcss": "^2.1.2", @@ -6782,6 +6783,11 @@ } ] }, + "node_modules/s-ago": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/s-ago/-/s-ago-2.2.0.tgz", + "integrity": "sha512-t6Q/aFCCJSBf5UUkR/WH0mDHX8EGm2IBQ7nQLobVLsdxOlkryYMbOlwu2D4Cf7jPUp0v1LhfPgvIZNoi9k8lUA==" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -13213,6 +13219,11 @@ "integrity": "sha512-Arc4hUN896vjkqCYrUXquBFtRZdv1PfLbTYP71efP6butxyQ0kWpiNJyAgsxscmQg1cqvHY32/UCBzXedTpU2g==", "dev": true }, + "s-ago": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/s-ago/-/s-ago-2.2.0.tgz", + "integrity": "sha512-t6Q/aFCCJSBf5UUkR/WH0mDHX8EGm2IBQ7nQLobVLsdxOlkryYMbOlwu2D4Cf7jPUp0v1LhfPgvIZNoi9k8lUA==" + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", diff --git a/package.json b/package.json index 940948f..1ceefff 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "react-phone-number-input": "^3.1.22", "request": "^2.51.0", "request-promise": "^4.2.6", + "s-ago": "^2.2.0", "schema-utils": "2.6.6", "sound-play": "^1.1.0", "tailwindcss": "^2.1.2", diff --git a/resources/public/css/styles.css b/resources/public/css/styles.css index fc7424d..0617202 100644 --- a/resources/public/css/styles.css +++ b/resources/public/css/styles.css @@ -782,6 +782,14 @@ select { margin-top: 10px; margin-bottom: 10px; } +.my-\[15px\] { + margin-top: 15px; + margin-bottom: 15px; +} +.my-\[5px\] { + margin-top: 5px; + margin-bottom: 5px; +} .mt-\[10px\] { margin-top: 10px; } @@ -797,24 +805,24 @@ select { .mt-\[15px\] { margin-top: 15px; } -.mr-\[30px\] { - margin-right: 30px; -} -.mr-\[20px\] { - margin-right: 20px; -} .mr-\[10px\] { margin-right: 10px; } -.ml-\[20px\] { - margin-left: 20px; -} .mt-\[5px\] { margin-top: 5px; } .mb-\[30px\] { margin-bottom: 30px; } +.mr-\[20px\] { + margin-right: 20px; +} +.ml-\[20px\] { + margin-left: 20px; +} +.ml-\[5px\] { + margin-left: 5px; +} .block { display: block; } @@ -833,11 +841,8 @@ select { .h-\[100px\] { height: 100px; } -.h-\[30px\] { - height: 30px; -} -.h-\[20px\] { - height: 20px; +.h-\[65px\] { + height: 65px; } .min-h-\[50px\] { min-height: 50px; @@ -857,15 +862,12 @@ select { .w-\[100px\] { width: 100px; } -.w-\[30px\] { - width: 30px; -} -.max-w-\[150px\] { - max-width: 150px; -} .max-w-\[140px\] { max-width: 140px; } +.flex-1 { + flex: 1 1 0%; +} .cursor-pointer { cursor: pointer; } @@ -896,11 +898,14 @@ select { .justify-between { justify-content: space-between; } +.justify-start { + justify-content: flex-start; +} .justify-evenly { justify-content: space-evenly; } -.justify-start { - justify-content: flex-start; +.justify-end { + justify-content: flex-end; } .overflow-hidden { overflow: hidden; @@ -908,11 +913,31 @@ select { .overflow-x-hidden { overflow-x: hidden; } +.overflow-y-scroll { + overflow-y: scroll; +} +.overflow-y-hidden { + overflow-y: hidden; +} .rounded-full { border-radius: 9999px; } -.rounded { - border-radius: 0.25rem; +.border-0 { + border-width: 0px; +} +.border-b-2 { + border-bottom-width: 2px; +} +.border-b-\[1px\] { + border-bottom-width: 1px; +} +.border-gray-300 { + --tw-border-opacity: 1; + border-color: rgba(209, 213, 219, var(--tw-border-opacity)); +} +.border-gray-500 { + --tw-border-opacity: 1; + border-color: rgba(107, 114, 128, var(--tw-border-opacity)); } .bg-\[\#FFFAFF\] { --tw-bg-opacity: 1; @@ -926,6 +951,18 @@ select { --tw-bg-opacity: 1; background-color: rgba(48, 48, 54, var(--tw-bg-opacity)); } +.bg-\[\#3A3A41\] { + --tw-bg-opacity: 1; + background-color: rgba(58, 58, 65, var(--tw-bg-opacity)); +} +.bg-\[\#43434C\] { + --tw-bg-opacity: 1; + background-color: rgba(67, 67, 76, var(--tw-bg-opacity)); +} +.bg-\[\#30BCED\] { + --tw-bg-opacity: 1; + background-color: rgba(48, 188, 237, var(--tw-bg-opacity)); +} .bg-contain { background-size: contain; } @@ -935,21 +972,10 @@ select { .bg-no-repeat { background-repeat: no-repeat; } -.p-\[20px\] { - padding: 20px; -} .px-\[100px\] { padding-left: 100px; padding-right: 100px; } -.py-\[50px\] { - padding-top: 50px; - padding-bottom: 50px; -} -.py-\[30px\] { - padding-top: 30px; - padding-bottom: 30px; -} .px-\[20px\] { padding-left: 20px; padding-right: 20px; @@ -962,6 +988,14 @@ select { padding-top: 5px; padding-bottom: 5px; } +.px-\[50px\] { + padding-left: 50px; + padding-right: 50px; +} +.px-\[75px\] { + padding-left: 75px; + padding-right: 75px; +} .pt-\[10px\] { padding-top: 10px; } @@ -994,6 +1028,12 @@ select { .font-normal { font-weight: 400; } +.font-thin { + font-weight: 100; +} +.font-light { + font-weight: 300; +} .uppercase { text-transform: uppercase; } @@ -1020,10 +1060,18 @@ select { --tw-text-opacity: 1; color: rgba(9, 188, 138, var(--tw-text-opacity)); } +.text-gray-500 { + --tw-text-opacity: 1; + color: rgba(107, 114, 128, var(--tw-text-opacity)); +} .shadow-2xl { --tw-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.shadow-md { + --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} .focus\:border-\[\#30BCED\]:focus { --tw-border-opacity: 1; border-color: rgba(48, 188, 237, var(--tw-border-opacity)); diff --git a/resources/public/html/chat.html b/resources/public/html/chat.html index d71c82a..ed7381c 100644 --- a/resources/public/html/chat.html +++ b/resources/public/html/chat.html @@ -1,14 +1,26 @@ - + BuddyList + + - -
-
+ diff --git a/src/buddylistclient/main/core.cljs b/src/buddylistclient/main/core.cljs index d760c90..65f9ab5 100644 --- a/src/buddylistclient/main/core.cljs +++ b/src/buddylistclient/main/core.cljs @@ -127,7 +127,7 @@ (defn notify-new-message [with-user message] (let [notification-params (clj->js {:title (str "New message from " with-user) :body message - :sound (.resolve path (js* "__dirname") "../assets/imrcv.wav")}) + :sound (.resolve path (js* "__dirname") "../resources/public/sounds/imrcv.wav")}) notification (Notification. notification-params)] (.show notification))) @@ -150,9 +150,9 @@ (println new-max old-max)) (println "new max null" old-max)))) -(defn launch-chat [with-user] - (swap! *win* assoc-in [:chats with-user] (BrowserWindow. (clj->js {:width 500 :height 400 :webPreferences {:nodeIntegration true :contextIsolation false}}))) - (.loadFile (-> @*win* :chats (get with-user)) (.resolve path (js* "__dirname") "../resources/public/html/chat.html") (clj->js {:query {:with-user with-user :user (:username @*user*)}})) +(defn launch-chat [with-user data] + (swap! *win* assoc-in [:chats with-user] (BrowserWindow. (clj->js {:width 500 :minWidth 350 :height 400 :titleBarStyle "hidden" :webPreferences {:nodeIntegration true :contextIsolation false}}))) + (.loadFile (-> @*win* :chats (get with-user)) (.resolve path (js* "__dirname") "../resources/public/html/chat.html") (clj->js {:query {:with-user data :user (->> @*user* clj->js (.stringify js/JSON))}})) (.on (-> @*win* :chats (get with-user) .-webContents) "did-finish-load" (fn [] (println "chat did-finish-load " with-user) @@ -165,15 +165,16 @@ (.on (-> @*win* :chats (get with-user)) "closed" #(swap! *win* dissoc-in [:chats with-user]))) (.on ipcMain "buddies:selected" - (fn [_ username] - (if-not (contains? (:chats @*win*) username) - (launch-chat username) - (.show (-> @*win* :chats (get username)))))) + (fn [_ buddy data] + (println "data:" data) + (if-not (contains? (:chats @*win*) buddy) + (launch-chat buddy data) + (.show (-> @*win* :chats (get buddy)))))) (.on ipcMain "addbuddy" (fn [_ buddy-username] (.then (user/add-buddy (:username @*user*) (:auth-token @*user*) buddy-username) - (fn [m] + (fn [_] (.reload (-> @*win* :buddylist)) (.close (-> @*win* :add-buddy)))))) @@ -197,6 +198,14 @@ (.catch (fn [err] (println "File error:" err)))))) +(.on ipcMain "new-buddies-order" + (fn [_ new-buddies-order] + (-> (user/set-new-buddies-order (:username @*user*) (:auth-token @*user*) (js->clj new-buddies-order)) + (.then (fn [m] + (reset! *user* (js->clj m :keywordize-keys true)))) + (.catch (fn [err] + (println "new-buddies-order.err:" err)))))) + (defn open-addbuddy-win [] (swap! *win* assoc :add-buddy (BrowserWindow. (clj->js {:width 300 :height 300 :webPreferences {:nodeIntegration true :contextIsolation false}}))) (.loadURL (:add-buddy @*win*) (str "file://" (.resolve path (js* "__dirname") "../resources/public/html/addbuddy.html"))) diff --git a/src/buddylistclient/main/user.cljs b/src/buddylistclient/main/user.cljs index ba29111..d242598 100644 --- a/src/buddylistclient/main/user.cljs +++ b/src/buddylistclient/main/user.cljs @@ -101,19 +101,6 @@ (.then #(.-data %)) (.catch #(println %))))) -(defn upload-pfp- [username auth-token f] - (let [form {:image {:value (.createReadStream fs (-> f - .-filePaths - (aget 0) - .toString)) - :options {:contentType nil}}} - headers {:authorization auth-token :request-user username} - options (clj->js {:method "POST" :url "https://buddylist.app/set-pfp" :formData form :headers headers}) - request (rp options)] - (-> request - (.then #(-> % (js->clj :keywordize-keys true))) - (.catch #(println "user.upload-pfp error:" %))))) - (defn upload-pfp [username auth-token f] (let [form (FormData.) _ (.append form "image" (.createReadStream fs (-> f @@ -125,4 +112,14 @@ request (axios options)] (-> request (.then #(-> % (js->clj :keywordize-keys true) :data)) - (.catch #(println "user.upload-pfp error:" %))))) \ No newline at end of file + (.catch #(println "user.upload-pfp error:" %))))) + +(defn set-new-buddies-order [username auth-token new-buddies-order] + (println new-buddies-order) + (let [headers {:authorization auth-token :request-user username "Content-Type" "application/json"} + params {:new-buddies-order new-buddies-order} + options (clj->js {:method "POST" :url "https://buddylist.app/rearrange-buddies" :headers headers :data params}) + request (axios options)] + (-> request + (.then #(.-data %)) + (.catch #(println (-> % .-response .-data)))))) \ No newline at end of file diff --git a/src/buddylistclient/renderer/buddies/core.cljs b/src/buddylistclient/renderer/buddies/core.cljs index 5015a4f..760c071 100644 --- a/src/buddylistclient/renderer/buddies/core.cljs +++ b/src/buddylistclient/renderer/buddies/core.cljs @@ -18,8 +18,8 @@ (def EVENTCHANNEL (chan)) (def EVENTS - {:buddy-clicked (fn [username] - (.send ipc-renderer "buddies:selected" username)) + {:buddy-clicked (fn [buddy] + (.send ipc-renderer "buddies:selected" (:username buddy) (->> buddy clj->js (.stringify js/JSON)))) :status-updated (fn [new-status] (println "sending new-status" new-status) (.send ipc-renderer "buddies:new-status" new-status))}) @@ -42,41 +42,39 @@ (println "parsed" @*user* (:username @*user*) (get @*user* "username")))) (defn buddies-list [event-channel buddies] - [:ul (merge {:class "buddies-list"}) - (for [buddy buddies] - ^{:key (:username buddy)} - [:> Droppable {:droppable-id (str "droppable-" (:username buddy)) - :direction "vertical"} - (fn [provided snapshot] - (let [inner-ref (.-innerRef provided) - droppable-props (-> (.-droppableProps provided) - (js->clj :keywordize-keys true)) - placeholder (.-placeholder provided) - is-dragging-over (.-isDraggingOver snapshot)] - - (as-element - [:div (merge droppable-props - {:ref inner-ref - :isdraggingover (str is-dragging-over)}) - [:> Draggable {:draggableId (str key) - :index (if (= (:username buddy) "liam") 0 1)} - (fn [provided snapshot] - (let [inner-ref (.-innerRef provided) - draggable-props (-> (.-draggableProps provided) - (js->clj :keywordize-keys true)) - drag-handler-props (-> (.-dragHandleProps provided) - (js->clj :keywordize-keys true)) - is-dragging (.-isDragging snapshot)] - (as-element - [:li (merge {:ref inner-ref :isdragging is-dragging} - draggable-props - {:class "flex flex-row justify-start px-[20px] my-[10px] cursor-pointer" :on-click #(put! event-channel [:buddy-clicked (:username buddy)])} - drag-handler-props) - [:img {:class "w-[50px] h-[50px] m-w-[50px] m-h-[50px] rounded-full overflow-hidden mr-[10px]" :src "../img/smiley.svg"}] - [:div {:class "flex flex-col justify-evenly"} - [:h4 {:class "font-semibold"} (:username buddy)] - [:h6 {:class "font-normal text-xs"} (:status buddy)]] - placeholder])))]])))])]) + [:> Droppable {:droppable-id "droppable" + :direction "vertical"} + (fn [provided snapshot] + (let [inner-ref (.-innerRef provided) + droppable-props (-> (.-droppableProps provided) + (js->clj :keywordize-keys true)) + placeholder (.-placeholder provided) + is-dragging-over (.-isDraggingOver snapshot)] + (as-element [:ul (merge droppable-props + {:style {"-webkit-app-region" "no-drag"}} + {:ref inner-ref + :isdraggingover (str is-dragging-over)}) + (map-indexed (fn [idx buddy] + [:> Draggable {:draggableId (:username buddy) + :key (:username buddy) + :index idx} + (fn [provided snapshot] + (let [inner-ref (.-innerRef provided) + draggable-props (-> (.-draggableProps provided) + (js->clj :keywordize-keys true)) + drag-handler-props (-> (.-dragHandleProps provided) + (js->clj :keywordize-keys true)) + is-dragging (.-isDragging snapshot)] + (as-element + [:li (merge {:ref inner-ref :isdragging is-dragging} + draggable-props + {:class "flex flex-row justify-start px-[20px] my-[10px] cursor-pointer" :on-click #(put! event-channel [:buddy-clicked buddy])} + drag-handler-props) + [:img {:class "w-[50px] h-[50px] m-w-[50px] m-h-[50px] rounded-full overflow-hidden mr-[10px]" :src (if (nil? (:profile-picture buddy)) "../img/smiley.svg" (:profile-picture buddy))}] + [:div {:class "flex flex-col justify-evenly"} + [:h4 {:class "font-semibold"} (:username buddy)] + [:h6 {:class "font-normal text-xs"} (:status buddy)]]])))]) buddies) + placeholder])))]) (defn on-new-status-submit [e _] (.preventDefault e) @@ -88,7 +86,7 @@ [:form {:on-submit #(on-new-status-submit % event-channel) :class "flex flex-col justify-start" :style {"-webkit-app-region" "no-drag"}} [:textarea {:class "text-[#050401] focus:border-[#30BCED] resize-y text-xs h-[50px] min-h-[50px]" :type "text" :id "new-status-input" :placeholder "New status"}] - [:input {:type "submit" :value "Change" :class "bg-[#09BC8A] focus:outline-none mt-[5px] py-[10px] font-semibold"}]]]) + [:input {:type "submit" :value "Change" :class "bg-[#09BC8A] cursor-pointer focus:outline-none mt-[5px] py-[10px] font-semibold"}]]]) (defn on-add-buddy [event] (.preventDefault event) @@ -97,12 +95,19 @@ (defn open-add-buddy [] [:div {:class "flex flex-row justify-center mt-[15px]"} [:button {:on-click #(on-add-buddy %) - :class "cursor-pointer font-semibold text-[#09BC8A]"} + :class "cursor-pointer font-semibold text-[#30BCED]"} "Add buddy!"]]) +(defn on-drag-end [result] + (let [{:keys [destination source]} (js->clj result :keywordize-keys true) + src-index (:index source) + dest-index (:index destination)] + (when (not= src-index dest-index) + (swap! state assoc src-index (@state dest-index) dest-index (@state src-index)) + (.send ipc-renderer "new-buddies-order" (clj->js (map :username @state)))))) + (defn root-component [] - [:div {:class "relative h-screen w-screen font-sans bg-[#303036] py-[5px] select-none text-[#FFFAFF] overflow-x-hidden" - :style {"-webkit-app-region" "no-drag"}} + [:div {:class "relative h-screen w-screen font-sans bg-[#303036] py-[5px] select-none text-[#FFFAFF] overflow-x-hidden"} [:h4 {:class "mb-[30px] text-center"} "BuddyList"] [:div {:class "flex flex-row justify-start px-[20px]"} [:div {:class "cursor-pointer container w-[100px] h-[100px] m-w-[100px] m-h-[100px] rounded-full overflow-hidden mr-[20px]" @@ -118,7 +123,7 @@ (if @state [:> DragDropContext {:on-drag-start #() :on-drag-update #() - :on-drag-end #(println %)} + :on-drag-end on-drag-end} [buddies-list EVENTCHANNEL @state]] [:p "Loading buddies..."]) [open-add-buddy]]) diff --git a/src/buddylistclient/renderer/chat/core.cljs b/src/buddylistclient/renderer/chat/core.cljs index 8263e26..8832b81 100644 --- a/src/buddylistclient/renderer/chat/core.cljs +++ b/src/buddylistclient/renderer/chat/core.cljs @@ -3,10 +3,11 @@ [cljs.core.async.macros :refer (go)]) (:require [clojure.string :refer [split]] - [reagent.core :refer [atom]] + [reagent.core :refer [atom create-class]] [reagent.dom :as rd] [cljs.core.async :refer (chan put! js/global .-location .-search))) +(def user (js->clj (.parse js/JSON (js/decodeURIComponent (:user data))) :keywordize-keys true)) + +(def with-user (js->clj (.parse js/JSON (js/decodeURIComponent (:with-user data))) :keywordize-keys true)) + (def ipc-renderer (.-ipcRenderer Electron)) (defonce state (atom [])) @@ -27,7 +32,7 @@ (def EVENTS {:message-sent (fn [message] - (.send ipc-renderer "chat:sent" (:with-user data) message))}) + (.send ipc-renderer "chat:sent" (:username with-user) message))}) (go (while true @@ -40,40 +45,90 @@ (let [parsed (.parse js/JSON message) message (js->clj parsed :keywordize-keys true)] (swap! state conj message) - (if (= (-> message :from) (:user data)) - (.play (js/Audio. "../../sounds/imsend.wav")))))) + (if (= (-> message :from) (:username user)) + (.play (js/Audio. "../sounds/imsend.wav")))) + (if-let [element (js/document.getElementById "message-list")] + (do + (set! (.-scrollTop element) (.-scrollHeight element)) + (println "done!")) + (println "not rendered message-list yet")))) (.on ipc-renderer "chat:loaded-history" (fn [_ parsed] (let [messages (js->clj parsed :keywordize-keys true)] - (swap! state (comp vec flatten conj) messages)))) + (swap! state (comp vec flatten conj) messages)) + (if-let [element (js/document.getElementById "message-list")] + (do + (set! (.-scrollTop element) (.-scrollHeight element)) + (println "done!")) + (println "not rendered message-list yet")))) + +(defn conglomerate-messages [messages] + (partition-by :from messages)) (defn message-list [messages] - [:ul {:class "message-list"} - (for [message messages] - ^{:key (:id message)} - [:li {:class "message-holder"} - [:p (str (:from message) ": " (:message message))]])]) + (create-class + {:component-did-update (fn [_ _] (if-let [element (js/document.getElementById "message-list")] + (do + (set! (.-scrollTop element) (.-scrollHeight element)) + (println "done!")) + (println "not rendered message-list yet"))) + :reagent-render + (fn [messages] [:ul {:class "overflow-y-scroll" + :id "message-list" + :style {:height "calc(100vh - 120px)" + :scrollbar-color "gray #3A3A41"}} + (map + (fn [message-group] + [:li {:class "flex flex-row justify-start my-[5px] ml-[5px]" + :key (str (first message-group) "-group")} + (let [my-message? (= (:username user) (-> message-group first :from)) + img-url (if my-message? (:profile-pic user) (:profile-pic with-user))] + [:img {:class "w-[50px] h-[50px] m-w-[50px] m-h-[50px] rounded-full overflow-hidden mr-[10px]" :src (if (nil? img-url) "../img/smiley.svg" img-url)}]) + [:div + [:h5 {:class "font-semibold"} + (-> message-group first :from) + [:span {:class "ml-[5px] text-xs font-light text-gray-500"} + (ago (let [date (js/Date. (-> message-group last :time)) + date-minutes (.getMinutes date) + offset (.getTimezoneOffset date)] + (.setMinutes date (- date-minutes offset)) + date))]] + [:ul {:class ""} + (map (fn [message] + [:li {:key (:id message)} (:message message)]) message-group)]]]) messages)])})) (defn submit-chat [event] (.preventDefault event) (let [message (-> js/document (.getElementById "chat-input") .-value)] (js/console.log message) - (.send ipc-renderer "chat:sent" (:with-user data) message) + (.send ipc-renderer "chat:sent" (:username with-user) message) (set! (-> js/document (.getElementById "chat-input") .-value) ""))) (defn chat-input [] - [:form {:on-submit #(submit-chat %)} - [:input {:id "chat-input" :type "text"}] - [:input {:type "submit"}]]) + [:form {:class "flex flex-row shadow-2xl overflow-hidden absolute inset-x-0 bottom-0 bg-[#303036] h-[50px] mx-[10px] mb-[10px] rounded-full" :on-submit #(submit-chat %) :style {"-webkit-app-region" "no-drag"}} + [:input {:class "text-sm bg-[#43434C] border-0" :style {:flex "4"} :id "chat-input" :type "text" :placeholder (str "Message @" (:username with-user))}] + [:input {:class "bg-[#30BCED] text-[#FFFAFF] border-0 cursor-pointer" :style {:flex "1"} :type "submit" :value "Send"}]]) + +(defn chat-header [with-user] + [:div {:class "flex flex-row justify-start px-[75px] py-[5px] bg-[#303036] cursor-pointer"} + [:img {:class "w-[50px] h-[50px] m-w-[50px] m-h-[50px] rounded-full overflow-hidden mr-[10px]" :src (if (nil? (:profile-picture with-user)) "../img/smiley.svg" (:profile-picture with-user))}] + [:div {:class "flex flex-col justify-evenly"} + [:h4 {:class "font-semibold"} (:username with-user)] + [:h6 {:class "font-normal text-xs"} (:status with-user)]]]) (defn root-component [] - [:div - [:h4 (str "Conversation with " (:with-user data))] - [message-list @state] + [:div {:class "relative h-screen w-screen font-sans bg-[#3A3A41] select-none text-[#FFFAFF] overflow-x-hidden"} + [chat-header with-user] + [message-list (conglomerate-messages @state)] [chat-input]]) (defn ^:dev/after-load start! [] (rd/render [root-component] - (js/document.getElementById "app-container"))) + (js/document.getElementById "app-container") + (fn [_] (if-let [element (js/document.getElementById "message-list")] + (do + (set! (.-scrollTop element) (.-scrollHeight element)) + (println "done!")) + (println "not rendered message-list yet"))))) diff --git a/yarn.lock b/yarn.lock index cc40059..a4e8989 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3922,6 +3922,11 @@ "resolved" "https://registry.npmjs.org/run-series/-/run-series-1.1.9.tgz" "version" "1.1.9" +"s-ago@^2.2.0": + "integrity" "sha512-t6Q/aFCCJSBf5UUkR/WH0mDHX8EGm2IBQ7nQLobVLsdxOlkryYMbOlwu2D4Cf7jPUp0v1LhfPgvIZNoi9k8lUA==" + "resolved" "https://registry.npmjs.org/s-ago/-/s-ago-2.2.0.tgz" + "version" "2.2.0" + "safe-buffer@^5.0.1", "safe-buffer@^5.1.0", "safe-buffer@^5.1.1", "safe-buffer@^5.1.2", "safe-buffer@^5.2.0", "safe-buffer@>=5.1.0", "safe-buffer@~5.2.0": "integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"