diff --git a/frontend/src/uxbox/main/data/users.cljs b/frontend/src/uxbox/main/data/users.cljs index cc104fd9f..32b0a509e 100644 --- a/frontend/src/uxbox/main/data/users.cljs +++ b/frontend/src/uxbox/main/data/users.cljs @@ -44,15 +44,21 @@ ;; --- Profile Fetched (defn profile-fetched - [data] + [{:keys [fullname] :as data}] (us/verify ::profile data) (ptk/reify ::profile-fetched ptk/UpdateEvent (update [_ state] - (let [profile (avatars/assign data)] - (assoc state :profile (cond-> profile - (nil? (:lang data)) (assoc :lang cfg/default-language) - (nil? (:theme data)) (assoc :theme cfg/default-theme))))) + (assoc state :profile + (cond-> data + (nil? (:photo-uri data)) + (assoc :photo-uri (avatars/generate {:name fullname})) + + (nil? (:lang data)) + (assoc :lang cfg/default-language) + + (nil? (:theme data)) + (assoc :theme cfg/default-theme)))) ptk/EffectEvent (effect [_ state stream] diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index d622567bd..3326f591d 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -295,26 +295,52 @@ (ws/-close (get-in state [:ws file-id])) (rx/of ::finalize-ws)))) -;; --- Handle: Who +;; --- Handle: Presence + +(def ^:private presence-palette + #{"#2e8b57" ; seagreen + "#808000" ; olive + "#b22222" ; firebrick + "#ff8c00" ; darkorage + "#ffd700" ; gold + "#ba55d3" ; mediumorchid + "#00fa9a" ; mediumspringgreen + "#00bfff" ; deepskyblue + "#dda0dd" ; plum + "#ff1493" ; deeppink + "#ffa07a" ; lightsalmon + }) (defn handle-presence [{:keys [sessions] :as msg}] - (ptk/reify ::handle-presence - ptk/UpdateEvent - (update [_ state] - (let [users (:workspace-users state)] - (update state :workspace-presence - (fn [prev-sessions] - (reduce (fn [acc [sid pid]] - (if-let [prev (get prev-sessions sid)] - (assoc acc sid prev) - (let [profile (get users pid) - session {:id sid - :fullname (:fullname profile) - :photo-uri (:photo-uri profile)}] - (assoc acc sid (avatars/assign session))))) - {} - sessions))))))) + (letfn [(assign-color [sessions session] + (if (string? (:color session)) + session + (let [used (into #{} + (comp (map second) + (map :color) + (remove nil?)) + sessions) + avail (set/difference presence-palette used) + color (or (first avail) "#000000")] + (assoc session :color color)))) + (update-sessions [previous profiles] + (reduce (fn [current [session-id profile-id]] + (let [profile (get profiles profile-id) + session {:id session-id + :fullname (:fullname profile) + :photo-uri (or (:photo-uri profile) + (avatars/generate {:name (:fullname profile)}))} + session (assign-color current session)] + (assoc current session-id session))) + (select-keys previous (map first sessions)) + (filter (fn [[sid]] (not (contains? previous sid))) sessions)))] + + (ptk/reify ::handle-presence + ptk/UpdateEvent + (update [_ state] + (let [profiles (:workspace-users state)] + (update state :workspace-presence update-sessions profiles)))))) (defn handle-pointer-update [{:keys [page-id profile-id session-id x y] :as msg}] diff --git a/frontend/src/uxbox/main/data/workspace/texts.cljs b/frontend/src/uxbox/main/data/workspace/texts.cljs index 6dda7bf12..7254adf47 100644 --- a/frontend/src/uxbox/main/data/workspace/texts.cljs +++ b/frontend/src/uxbox/main/data/workspace/texts.cljs @@ -45,7 +45,7 @@ ([editor props options] (when (and (nil? (obj/get editor "selection")) (nil? (obj/get options "at"))) - (obj/assoc! options "at" (calculate-full-selection editor))) + (obj/set! options "at" (calculate-full-selection editor))) (.setNodes Transforms editor props options) editor)) @@ -106,10 +106,10 @@ (let [options #js {:match pred :universal universal?}] (cond (object? at) - (obj/assoc! options "at" at) + (obj/set! options "at" at) (nil? (obj/get editor "selection")) - (obj/assoc! options "at" (calculate-full-selection editor))) + (obj/set! options "at" (calculate-full-selection editor))) (let [result (.nodes Editor editor options) match (ffirst (es6-iterator-seq result))] diff --git a/frontend/src/uxbox/main/ui/shapes/text.cljs b/frontend/src/uxbox/main/ui/shapes/text.cljs index 6a5206c42..ea5ce8596 100644 --- a/frontend/src/uxbox/main/ui/shapes/text.cljs +++ b/frontend/src/uxbox/main/ui/shapes/text.cljs @@ -80,9 +80,9 @@ :width "100%" :display "flex"}] (cond-> base - (= valign "top") (obj/assoc! "alignItems" "flex-start") - (= valign "center") (obj/assoc! "alignItems" "center") - (= valign "bottom") (obj/assoc! "alignItems" "flex-end")))) + (= valign "top") (obj/set! "alignItems" "flex-start") + (= valign "center") (obj/set! "alignItems" "center") + (= valign "bottom") (obj/set! "alignItems" "flex-end")))) (mf/defc rt-text-box {::mf/wrap-props false @@ -93,8 +93,8 @@ data (obj/get props "element") type (obj/get data "type") style (generate-text-box-styles data) - attrs (obj/assoc! attrs "style" style) - attrs (obj/assoc! attrs "className" type)] + attrs (obj/set! attrs "style" style) + attrs (obj/set! attrs "className" type)] [:> :div attrs childs])) (defn- generate-text-styles @@ -113,8 +113,8 @@ data (obj/get props "element") type (obj/get data "type") style (generate-text-styles data) - attrs (obj/assoc! attrs "style" style) - attrs (obj/assoc! attrs "className" type)] + attrs (obj/set! attrs "style" style) + attrs (obj/set! attrs "className" type)] [:> :div attrs childs])) (defn- generate-paragraph-styles @@ -125,8 +125,8 @@ lh (obj/get data "lineHeight") ta (obj/get data "textAlign")] (cond-> base - ta (obj/assoc! "textAlign" ta) - lh (obj/assoc! "lineHeight" lh)))) + ta (obj/set! "textAlign" ta) + lh (obj/set! "lineHeight" lh)))) (mf/defc rt-pharagraph {::mf/wrap-props false @@ -136,7 +136,7 @@ childs (obj/get props "children") data (obj/get props "element") style (generate-paragraph-styles data) - attrs (obj/assoc! attrs "style" style)] + attrs (obj/set! attrs "style" style)] [:> :p attrs childs])) (defn- generate-leaf-styles @@ -162,11 +162,11 @@ (when (and (string? letter-spacing) (pos? (alength letter-spacing))) - (obj/assoc! base "letterSpacing" (str letter-spacing "px"))) + (obj/set! base "letterSpacing" (str letter-spacing "px"))) (when (and (string? font-size) (pos? (alength font-size))) - (obj/assoc! base "fontSize" (str font-size "px"))) + (obj/set! base "fontSize" (str font-size "px"))) (when (and (string? font-id) (pos? (alength font-id))) @@ -180,9 +180,9 @@ (obj/get data "fontStyle")) font-weight (or (:weight font-variant) (obj/get data "fontWeight"))] - (obj/assoc! base "fontFamily" font-family) - (obj/assoc! base "fontStyle" font-style) - (obj/assoc! base "fontWeight" font-weight)))) + (obj/set! base "fontFamily" font-family) + (obj/set! base "fontStyle" font-style) + (obj/set! base "fontWeight" font-weight)))) base)) @@ -194,7 +194,7 @@ childs (obj/get props "children") data (obj/get props "leaf") style (generate-leaf-styles data) - attrs (obj/assoc! attrs "style" style)] + attrs (obj/set! attrs "style" style)] [:> :span attrs childs])) (defn- render-element @@ -298,7 +298,7 @@ (dom/prevent-default event) (dom/stop-propagation event) ;; WARN: monky patch - (obj/assoc! slate/Transforms "deselect" (constantly nil))) + (obj/set! slate/Transforms "deselect" (constantly nil))) :placeholder "Type some text here..."}]]])) ;; --- Text Shape Wrapper diff --git a/frontend/src/uxbox/util/avatars.cljs b/frontend/src/uxbox/util/avatars.cljs index d9122ae9f..dab27164a 100644 --- a/frontend/src/uxbox/util/avatars.cljs +++ b/frontend/src/uxbox/util/avatars.cljs @@ -13,7 +13,7 @@ [uxbox.util.object :as obj] ["randomcolor" :as rdcolor])) -(defn- impl-generate-image +(defn generate [{:keys [name color size] :or {color "#303236" size 128}}] (let [parts (str/words (str/upper name)) @@ -23,19 +23,15 @@ canvas (.createElement js/document "canvas") context (.getContext canvas "2d")] - (set! (.-width canvas) size) - (set! (.-height canvas) size) - (set! (.-fillStyle context) "#303236") + (obj/set! canvas "width" size) + (obj/set! canvas "height" size) + + (obj/set! context "fillStyle" color) (.fillRect context 0 0 size size) - (set! (.-font context) (str (/ size 2) "px Arial")) - (set! (.-textAlign context) "center") - (set! (.-fillStyle context) "#FFFFFF") + (obj/set! context "font" (str (/ size 2) "px Arial")) + (obj/set! context "textAlign" "center") + (obj/set! context "fillStyle" "#FFFFFF") (.fillText context letters (/ size 2) (/ size 1.5)) - (.toDataURL canvas))) -(defn assign - [{:keys [id photo-uri fullname color] :as profile}] - (cond-> profile - (not photo-uri) (assoc :photo-uri (impl-generate-image {:name fullname})) - (not color) (assoc :color (rdcolor)))) + (.toDataURL canvas))) diff --git a/frontend/src/uxbox/util/color.cljs b/frontend/src/uxbox/util/color.cljs index b03f61ea0..f4a7c3f61 100644 --- a/frontend/src/uxbox/util/color.cljs +++ b/frontend/src/uxbox/util/color.cljs @@ -2,14 +2,17 @@ ;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; -;; Copyright (c) 2015-2016 Andrey Antukh -;; Copyright (c) 2015-2016 Juan de la Cruz +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL (ns uxbox.util.color "Color conversion utils." - (:require [cuerdas.core :as str] - [uxbox.util.math :as math] - [goog.color :as gcolor])) + (:require + [cuerdas.core :as str] + [uxbox.util.math :as math] + [goog.color :as gcolor])) (defn rgb->str [color] diff --git a/frontend/src/uxbox/util/object.cljs b/frontend/src/uxbox/util/object.cljs index dabc12f65..53b229f22 100644 --- a/frontend/src/uxbox/util/object.cljs +++ b/frontend/src/uxbox/util/object.cljs @@ -34,14 +34,13 @@ (rest keys) (unchecked-get res key)))))) -(defn assign! +(defn merge! ([a b] (js/Object.assign a b)) ([a b & more] - (reduce assign! (assign! a b) more))) + (reduce merge! (merge! a b) more))) -(defn assoc! - [obj attr value] - (when (object? obj) - (unchecked-set obj attr value) - obj)) +(defn set! + [obj key value] + (unchecked-set obj key value) + obj)