mirror of
https://github.com/penpot/penpot.git
synced 2025-05-19 23:46:11 +02:00
Merge pull request #4171 from penpot/niwinz-staging-perfix-2
🐛 Bugfixes and ⚡ Performance enhancements
This commit is contained in:
commit
5883a50520
8 changed files with 203 additions and 156 deletions
|
@ -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
|
||||
|
|
|
@ -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 _]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}]]))
|
||||
|
||||
|
|
|
@ -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))}])]]]))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))))]
|
||||
|
||||
|
|
|
@ -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))}])))
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue