Merge pull request #4171 from penpot/niwinz-staging-perfix-2

🐛 Bugfixes and  Performance enhancements
This commit is contained in:
Alejandro 2024-02-22 07:09:55 +01:00 committed by GitHub
commit 5883a50520
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 203 additions and 156 deletions

View file

@ -593,20 +593,21 @@
(defn rename-file
[id name]
{:pre [(uuid? id) (string? name)]}
(ptk/reify ::rename-file
IDeref
(-deref [_]
{::ev/origin "workspace" :id id :name name})
(let [name (str/prune name 200)]
(ptk/reify ::rename-file
IDeref
(-deref [_]
{::ev/origin "workspace" :id id :name name})
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-file :name] name))
ptk/UpdateEvent
(update [_ state]
(assoc-in state [:workspace-file :name] name))
ptk/WatchEvent
(watch [_ _ _]
(let [params {:id id :name name}]
(->> (rp/cmd! :rename-file params)
(rx/ignore))))))
ptk/WatchEvent
(watch [_ _ _]
(let [params {:id id :name name}]
(->> (rp/cmd! :rename-file params)
(rx/ignore)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Workspace State Manipulation

View file

@ -27,6 +27,11 @@
(defn add-flow
[starting-frame]
(dm/assert!
"expect uuid"
(uuid? starting-frame))
(ptk/reify ::add-flow
ptk/WatchEvent
(watch [it state _]

View file

@ -144,7 +144,8 @@
(remove nil?))
used (into #{} xfm presence)
avail (set/difference presence-palette used)]
(or (first avail) "var(--app-black)")))
;; If all colores are used we select the default one
(or (first avail) "#dee563")))
(update-color [color presence]
(if (some? color)
@ -158,7 +159,7 @@
(assoc :updated-at (dt/now))
(assoc :version version)
(update :color update-color presence)
(assoc :text-color "#000")))
(assoc :text-color "#000000")))
(update-presence [presence]
(-> presence

View file

@ -9,6 +9,7 @@
(:require
[app.common.colors :as cc]
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.config :as cfg]
[app.main.data.modal :as modal]
[app.main.data.workspace.colors :as dc]
@ -50,6 +51,7 @@
;; --- Color Picker Modal
(mf/defc colorpicker
{::mf/props :obj}
[{:keys [data disable-gradient disable-opacity disable-image on-change on-accept]}]
(let [state (mf/deref refs/colorpicker)
node-ref (mf/use-ref)
@ -90,7 +92,7 @@
(not @drag?)))))
on-fill-image-click
(mf/use-callback #(dom/click (mf/ref-val fill-image-ref)))
(mf/use-fn #(dom/click (mf/ref-val fill-image-ref)))
on-fill-image-selected
(mf/use-fn
@ -107,7 +109,7 @@
(assoc :keep-aspect-ratio keep-aspect-ratio?))}
true)))))
set-tab!
on-change-tab
(mf/use-fn
(fn [event]
(let [tab (-> (dom/get-current-target event)
@ -226,7 +228,7 @@
(dom/set-css-property! node "--saturation-grad-from" (format-hsl hsl-from))
(dom/set-css-property! node "--saturation-grad-to" (format-hsl hsl-to))))
;; Updates color when used el pixel picker
;; Updates color when pixel picker is used
(mf/with-effect [picking-color? picked-color picked-color-select]
(when (and picking-color? picked-color picked-color-select)
(let [[r g b alpha] picked-color
@ -294,7 +296,7 @@
[:*
[:div {:class (stl/css :colorpicker-tabs)}
[:& tab-container
{:on-change-tab set-tab!
{:on-change-tab on-change-tab
:selected @active-color-tab
:collapsable false}
@ -349,7 +351,7 @@
:on-select-color on-select-library-color
:on-add-library-color on-add-library-color}]])
(when on-accept
(when (fn? on-accept)
[:div {:class (stl/css :actions)}
[:button {:class (stl/css-case
:accept-color true
@ -372,59 +374,69 @@
x-pos 400]
(cond
(or (nil? x) (nil? y)) #js {:left "auto" :right "16rem" :top "4rem"}
(or (nil? x) (nil? y))
#js {:left "auto" :right "16rem" :top "4rem"}
(= position :left)
(if (> y max-y)
#js {:left (str (- x x-pos) "px")
#js {:left (dm/str (- x x-pos) "px")
:bottom "1rem"}
#js {:left (str (- x x-pos) "px")
:top (str (- y 70) "px")})
#js {:left (dm/str (- x x-pos) "px")
:top (dm/str (- y 70) "px")})
(= position :right)
(if (> y max-y)
#js {:left (str (+ x 80) "px")
#js {:left (dm/str (+ x 80) "px")
:bottom "1rem"}
#js {:left (str (+ x 80) "px")
:top (str (- y 70) "px")})
:else (if (> y max-y)
#js {:left (str (+ x left-offset) "px")
:bottom "1rem"}
#js {:left (str (+ x left-offset) "px")
:top (str (- y 70) "px")}))))
#js {:left (dm/str (+ x 80) "px")
:top (dm/str (- y 70) "px")})
:else
(if (> y max-y)
#js {:left (dm/str (+ x left-offset) "px")
:bottom "1rem"}
#js {:left (dm/str (+ x left-offset) "px")
:top (dm/str (- y 70) "px")}))))
(mf/defc colorpicker-modal
{::mf/register modal/components
::mf/register-as :colorpicker}
::mf/register-as :colorpicker
::mf/props :obj}
[{:keys [x y data position
disable-gradient
disable-opacity
disable-image
on-change
on-close
on-accept] :as props}]
(let [vport (mf/deref viewport)
dirty? (mf/use-var false)
on-accept]}]
(let [vport (mf/deref viewport)
dirty? (mf/use-var false)
last-change (mf/use-var nil)
position (or position :left)
style (calculate-position vport position x y)
position (d/nilv position :left)
style (calculate-position vport position x y)
handle-change
(fn [new-data]
(reset! dirty? (not= data new-data))
(reset! last-change new-data)
(when on-change
(on-change new-data)))]
on-change'
(mf/use-fn
(mf/deps on-change)
(fn [new-data]
(reset! dirty? (not= data new-data))
(reset! last-change new-data)
(mf/use-effect
(fn []
#(when (and @dirty? @last-change on-close)
(on-close @last-change))))
(if (fn? on-change)
(on-change new-data)
(st/emit! (dc/update-colorpicker new-data)))))]
(mf/with-effect []
#(when (and @dirty? @last-change on-close)
(on-close @last-change)))
[:div {:class (stl/css :colorpicker-tooltip)
:style style}
[:& colorpicker {:data data
:disable-gradient disable-gradient
:disable-opacity disable-opacity
:disable-image disable-image
:on-change handle-change
:on-change on-change'
:on-accept on-accept}]]))

View file

@ -15,61 +15,64 @@
[app.util.timers :as tm]
[rumext.v2 :as mf]))
;; --- SESSION WIDGET
(mf/defc session-widget
[{:keys [session profile index] :as props}]
(let [profile (assoc profile :color (:color session))]
{::mf/props :obj
::mf/memo true}
[{:keys [color profile index]}]
(let [profile (assoc profile :color color)
full-name (:fullname profile)]
[:li {:class (stl/css :session-icon)
:style {:z-index (str (or (+ 1 (* -1 index)) 0))
:background-color (:color session)}
:title (:fullname profile)}
[:img {:alt (:fullname profile)
:style {:background-color (:color session)}
:style {:z-index (dm/str (+ 1 (* -1 index)))
:background-color color}
:title full-name}
[:img {:alt full-name
:style {:background-color color}
:src (cfg/resolve-profile-photo-url profile)}]]))
(mf/defc active-sessions
{::mf/wrap [mf/memo]}
{::mf/memo true}
[]
(let [users (mf/deref refs/users)
presence (mf/deref refs/workspace-presence)
user-ids (vals presence)
num-users (count user-ids)
first-users (take 2 user-ids)
sessions (vals presence)
num-sessions (count sessions)
open* (mf/use-state false)
open? (deref open*)
open-users-widget
open? (and ^boolean (deref open*) (> num-sessions 2))
on-open
(mf/use-fn
(fn []
(reset! open* true)
(tm/schedule-on-idle
#(dom/focus! (dom/get-element "users-close")))))
close-users-widget (mf/use-fn #(reset! open* false))]
on-close
(mf/use-fn #(reset! open* false))]
[:*
(when (and (> num-users 2) open?)
(when ^boolean open?
[:button {:id "users-close"
:class (stl/css :active-users-opened)
:on-click close-users-widget
:on-blur close-users-widget}
:on-click on-close
:on-blur on-close}
[:ul {:class (stl/css :active-users-list)}
(for [session user-ids]
(for [session sessions]
[:& session-widget
{:session session
{:color (:color session)
:index 0
:profile (get users (:profile-id session))
:key (:id session)}])]])
:key (dm/str (:id session))}])]])
[:button {:class (stl/css-case :active-users true)
:on-click open-users-widget}
:on-click on-open}
[:ul {:class (stl/css :active-users-list)}
(when (> num-users 2) [:span {:class (stl/css :users-num)} (dm/str "+" (- num-users 2))])
(for [[index session] (d/enumerate first-users)]
(when (> num-sessions 2)
[:span {:class (stl/css :users-num)} (dm/str "+" (- num-sessions 2))])
(for [[index session] (d/enumerate (take 2 sessions))]
[:& session-widget
{:session session
{:color (:color session)
:index index
:profile (get users (:profile-id session))
:key (:id session)}])]]]))
:key (dm/str (:id session))}])]]]))

View file

@ -377,6 +377,7 @@
(grp/group-assets colors reverse-sort?))
read-only? (mf/use-ctx ctx/workspace-read-only?)
add-color
(mf/use-fn
(fn [value _]
@ -386,23 +387,22 @@
(mf/use-fn
(mf/deps file-id)
(fn [event]
(let [bounding-rect (-> event
(dom/get-current-target)
(dom/get-bounding-rect))
x-position (:right bounding-rect)
y-position (:top bounding-rect)]
(let [bounds (-> event
(dom/get-current-target)
(dom/get-bounding-rect))
x-position (:right bounds)
y-position (:top bounds)]
(st/emit! (dw/set-assets-section-open file-id :colors true)
(ptk/event ::ev/event {::ev/name "add-asset-to-library"
:asset-type "color"}))
;; FIXME: replace interop with dom helpers
(modal/show! :colorpicker
{:x x-position
:y y-position
:on-accept add-color
:data {:color "#406280"
:opacity 1}
:position :right}))))
:asset-type "color"})
(modal/show :colorpicker
{:x x-position
:y y-position
:on-accept add-color
:data {:color "#406280"
:opacity 1}
:position :right})))))
create-group
(mf/use-fn

View file

@ -61,7 +61,7 @@
:layout-grid-rows])
(defn get-layout-flex-icon
[type val is-col?]
[type val ^boolean is-col?]
(case type
:align-items
(if is-col?
@ -115,7 +115,6 @@
:space-between i/align-content-row-between-refactor
:stretch nil))
:align-self
(if is-col?
(case val
@ -134,7 +133,7 @@
:baseline i/align-self-column-baseline))))
(defn get-layout-grid-icon-refactor
[type val is-col?]
[type val ^boolean is-col?]
(case type
:align-items
(if is-col?
@ -171,7 +170,8 @@
:stretch i/align-content-row-stretch-refactor))))
(mf/defc direction-row-flex
[{:keys [saved-dir on-change] :as props}]
{::mf/props :obj}
[{:keys [saved-dir on-change]}]
[:& radio-buttons {:selected (d/name saved-dir)
:on-change on-change
:name "flex-direction"}
@ -193,7 +193,8 @@
:icon (dir-icons-refactor :column-reverse)}]])
(mf/defc wrap-row
[{:keys [wrap-type on-click] :as props}]
{::mf/props :obj}
[{:keys [wrap-type on-click]}]
[:button {:class (stl/css-case :wrap-button true
:selected (= wrap-type :wrap))
:title (if (= :wrap wrap-type)
@ -203,7 +204,8 @@
i/wrap-refactor])
(mf/defc align-row
[{:keys [is-col? align-items on-change] :as props}]
{::mf/props :obj}
[{:keys [is-col? align-items on-change]}]
[:& radio-buttons {:selected (d/name align-items)
:on-change on-change
:name "flex-align-items"}
@ -221,7 +223,8 @@
:id "align-items-end"}]])
(mf/defc align-content-row
[{:keys [is-col? align-content on-change] :as props}]
{::mf/props :obj}
[{:keys [is-col? align-content on-change]}]
[:& radio-buttons {:selected (d/name align-content)
:on-change on-change
:name "flex-align-content"}
@ -251,7 +254,8 @@
:id "align-content-space-evenly"}]])
(mf/defc justify-content-row
[{:keys [is-col? justify-content on-change] :as props}]
{::mf/props :obj}
[{:keys [is-col? justify-content on-change]}]
[:& radio-buttons {:selected (d/name justify-content)
:on-change on-change
:name "flex-justify"}
@ -281,8 +285,8 @@
:id "justify-content-space-evenly"}]])
(mf/defc padding-section
[{:keys [values on-change-style on-change] :as props}]
{::mf/props :obj}
[{:keys [values on-change-style on-change]}]
(let [padding-type (:layout-padding-type values)
toggle-padding-mode
@ -418,6 +422,7 @@
i/padding-extended-refactor]]))
(mf/defc gap-section
{::mf/props :obj}
[{:keys [is-col? wrap-type gap-selected? on-change gap-value]}]
(let [select-gap
(fn [gap]
@ -474,7 +479,7 @@
;; GRID COMPONENTS
(defn get-layout-grid-icon
[type val is-col?]
[type val ^boolean is-col?]
(case type
:justify-items
(if is-col?
@ -497,6 +502,7 @@
:space-evenly i/grid-justify-content-row-between))))
(mf/defc direction-row-grid
{::mf/props :obj}
[{:keys [saved-dir on-change] :as props}]
[:& radio-buttons {:selected (d/name saved-dir)
:on-change on-change
@ -511,7 +517,8 @@
:icon (dir-icons-refactor :column)}]])
(mf/defc grid-edit-mode
[{:keys [id] :as props}]
{::mf/props :obj}
[{:keys [id]}]
(let [edition (mf/deref refs/selected-edition)
active? (= id edition)
@ -529,7 +536,8 @@
(tr "workspace.layout_grid.editor.options.edit-grid")]))
(mf/defc align-grid-row
[{:keys [is-col? align-items set-align] :as props}]
{::mf/props :obj}
[{:keys [is-col? align-items set-align]}]
(let [type (if is-col? :column :row)]
[:& radio-buttons {:selected (d/name align-items)
:on-change #(set-align % type)
@ -548,7 +556,8 @@
:id (dm/str "align-items-end-" (d/name type))}]]))
(mf/defc justify-grid-row
[{:keys [is-col? justify-items set-justify] :as props}]
{::mf/props :obj}
[{:keys [is-col? justify-items set-justify]}]
(let [type (if is-col? :column :row)]
[:& radio-buttons {:selected (d/name justify-items)
@ -561,7 +570,8 @@
:title (dm/str "Justify items " (d/name justify))
:id (dm/str "justify-items-" (d/name justify) "-" (d/name type))}])]))
(defn manage-values [{:keys [value type]}]
(defn- manage-values
[{:keys [type value]}]
(case type
:auto "auto"
:percent (fmt/format-percent value)
@ -570,6 +580,7 @@
value))
(mf/defc grid-track-info
{::mf/props :obj}
[{:keys [is-col?
type
index
@ -650,12 +661,13 @@
i/remove-refactor]]))
(mf/defc grid-columns-row
{::mf/props :obj}
[{:keys [is-col? expanded? column-values toggle add-new-element set-column-value set-column-type
remove-element reorder-track hover-track on-select-track] :as props}]
remove-element reorder-track hover-track on-select-track]}]
(let [column-num (count column-values)
direction (if (> column-num 1)
(if is-col? "Columns " "Rows ")
(if is-col? "Column " "Row "))
(if ^boolean is-col? "Columns " "Rows ")
(if ^boolean is-col? "Column " "Row "))
track-name (dm/str direction (if (= column-num 0) " - empty" column-num))
track-detail (str/join ", " (map manage-values column-values))
@ -694,8 +706,9 @@
;; LAYOUT COMPONENT
(mf/defc layout-container-menu
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "multiple"]))]}
[{:keys [ids values multiple] :as props}]
{::mf/memo #{:ids :values :multiple}
::mf/props :obj}
[{:keys [ids values multiple]}]
(let [;; Display
layout-type (:layout values)
has-layout? (some? layout-type)
@ -711,7 +724,7 @@
toggle-content (mf/use-fn #(swap! state* not))
on-add-layout
(mf/use-callback
(mf/use-fn
(fn [type]
(st/emit! (dwsl/create-layout type))
(reset! state* true)))
@ -730,13 +743,13 @@
(reset! state* false))
set-flex
(mf/use-callback
(mf/use-fn
(mf/deps on-add-layout)
(fn []
(on-add-layout :flex)))
set-grid
(mf/use-callback
(mf/use-fn
(mf/deps on-add-layout)
(fn []
(on-add-layout :grid)))
@ -875,22 +888,22 @@
(st/emit! (dwsl/update-layout ids {:layout-align-content value}))))))
handle-show-layout-dropdown
(mf/use-callback
(mf/use-fn
(fn []
(swap! show-layout-dropdown* not)))
handle-close-layout-options
(mf/use-callback
(mf/use-fn
(fn []
(reset! show-layout-dropdown* false)))
handle-open-flex-help
(mf/use-callback
(mf/use-fn
(fn []
(st/emit! (dom/open-new-window cf/flex-help-uri))))
handle-open-grid-help
(mf/use-callback
(mf/use-fn
(fn []
(st/emit! (dom/open-new-window cf/grid-help-uri))))]
@ -1011,8 +1024,9 @@
nil)))]))
(mf/defc grid-layout-edition
{::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values"]))]}
[{:keys [ids values] :as props}]
{::mf/memo #{:ids :values}
::mf/props :obj}
[{:keys [ids values]}]
(let [;; Gap
gap-selected? (mf/use-state :none)
saved-grid-dir (:layout-grid-dir values)
@ -1135,12 +1149,12 @@
(st/emit! (dwsl/change-layout-track ids type index {:value value
:type track-type})))))
handle-open-grid-help
(mf/use-callback
(mf/use-fn
(fn []
(st/emit! (dom/open-new-window cf/grid-help-uri))))
handle-locate-grid
(mf/use-callback
(mf/use-fn
(fn []
(st/emit! (dwge/locate-board (first ids)))))]

View file

@ -6,6 +6,7 @@
(ns app.main.ui.workspace.viewport.presence
(:require
[app.common.data.macros :as dm]
[app.main.refs :as refs]
[app.util.time :as dt]
[app.util.timers :as ts]
@ -13,56 +14,66 @@
[cuerdas.core :as str]
[rumext.v2 :as mf]))
(def pointer-icon-path
(str "M11.58,-0.47L11.47,-0.35L0.34,10.77L0.30,10.96L-0.46,"
"15.52L4.29,14.72L15.53,3.47L11.58,-0.47ZL11.58,"
"-0.47ZL11.58,-0.47ZM11.58,1.3C12.31,2.05,13.02,"
"2.742,13.76,3.47L4.0053,13.23C3.27,12.50,2.55,"
"11.78,1.82,11.05L11.58,1.30ZL11.58,1.30ZM1.37,12.15L2.90,"
"13.68L1.67,13.89L1.165,13.39L1.37,12.15ZL1.37,12.15Z"))
(def pointer-path
(dm/str "M11.58,-0.47L11.47,-0.35L0.34,10.77L0.30,10.96L-0.46,"
"15.52L4.29,14.72L15.53,3.47L11.58,-0.47ZL11.58,"
"-0.47ZL11.58,-0.47ZM11.58,1.3C12.31,2.05,13.02,"
"2.742,13.76,3.47L4.0053,13.23C3.27,12.50,2.55,"
"11.78,1.82,11.05L11.58,1.30ZL11.58,1.30ZM1.37,12.15L2.90,"
"13.68L1.67,13.89L1.165,13.39L1.37,12.15ZL1.37,12.15Z"))
(mf/defc session-cursor
[{:keys [session profile] :as props}]
(let [zoom (mf/deref refs/selected-zoom)
point (:point session)
background-color (:color session "var(--app-black)")
text-color (:text-color session "var(--app-white)")
transform (str/fmt "translate(%s, %s) scale(%s)" (:x point) (:y point) (/ 1 zoom))
shown-name (if (> (count (:fullname profile)) 16)
(str (str/slice (:fullname profile) 0 12) "...")
(:fullname profile))]
{::mf/props :obj
::mf/memo true}
[{:keys [session profile zoom]}]
(let [point (:point session)
bg-color (:color session)
fg-color "var(--app-white)"
transform (str/ffmt "translate(%, %) scale(%)"
(dm/get-prop point :x)
(dm/get-prop point :y)
(/ 1 zoom))
fullname (:fullname profile)
fullname (if (> (count fullname) 16)
(dm/str (str/slice fullname 0 12) "...")
fullname)]
[:g.multiuser-cursor {:transform transform}
[:path {:fill background-color
:d pointer-icon-path}]
[:path {:fill bg-color :d pointer-path}]
[:g {:transform "translate(17 -10)"}
[:foreignObject {:x -0.3
:y -12.5
:width 300
:height 120}
[:div.profile-name {:style {:background-color background-color
:color text-color}}
shown-name]]]]))
[:div.profile-name {:style {:background-color bg-color
:color fg-color}}
fullname]]]]))
(mf/defc active-cursors
{::mf/wrap [mf/memo]}
[{:keys [page-id] :as props}]
{::mf/props :obj}
[{:keys [page-id]}]
(let [counter (mf/use-state 0)
users (mf/deref refs/users)
sessions (mf/deref refs/workspace-presence)
zoom (mf/deref refs/selected-zoom)
sessions (->> (vals sessions)
(filter :point)
(filter #(= page-id (:page-id %)))
(filter #(>= 5000 (- (inst-ms (dt/now)) (inst-ms (:updated-at %))))))]
(mf/use-effect
nil
(fn []
(let [sem (ts/schedule 1000 #(swap! counter inc))]
(fn [] (rx/dispose! sem)))))
(filter #(>= 5000 (- (inst-ms (dt/now))
(inst-ms (:updated-at %))))))]
(mf/with-effect nil
(let [sem (ts/schedule 1000 #(swap! counter inc))]
(fn [] (rx/dispose! sem))))
(for [session sessions]
(when (:point session)
[:& session-cursor {:session session
:profile (get users (:profile-id session))
:key (:id session)}]))))
[:& session-cursor
{:session session
:zoom zoom
:profile (get users (:profile-id session))
:key (dm/str (:id session))}])))