mirror of
https://github.com/penpot/penpot.git
synced 2025-06-06 23:51:37 +02:00
🎉 Update master component
This commit is contained in:
parent
917643489f
commit
f837bad894
10 changed files with 337 additions and 166 deletions
|
@ -48,10 +48,6 @@
|
|||
(s/def ::set-of-string
|
||||
(s/every string? :kind set?))
|
||||
|
||||
;; --- Expose inner functions
|
||||
|
||||
(defn interrupt? [e] (= e :interrupt))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Workspace Initialization
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -956,7 +952,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> stream
|
||||
(rx/filter interrupt?)
|
||||
(rx/filter dwc/interrupt?)
|
||||
(rx/take 1)
|
||||
(rx/map (constantly clear-edition-mode))))))
|
||||
|
||||
|
@ -985,7 +981,7 @@
|
|||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [cancel-event? (fn [event]
|
||||
(interrupt? event))
|
||||
(dwc/interrupt? event))
|
||||
stoper (rx/filter (ptk/type? ::clear-drawing) stream)]
|
||||
(->> (rx/filter cancel-event? stream)
|
||||
(rx/take 1)
|
||||
|
|
|
@ -44,6 +44,11 @@
|
|||
([state page-id]
|
||||
(get-in state [:workspace-data :pages-index page-id :options])))
|
||||
|
||||
(defn interrupt? [e] (= e :interrupt))
|
||||
|
||||
(defn lookup-component-objects
|
||||
([state component-id]
|
||||
(get-in state [:workspace-data :components component-id :objects])))
|
||||
|
||||
|
||||
;; --- Changes Handling
|
||||
|
@ -454,3 +459,4 @@
|
|||
objects (lookup-page-objects state page-id)
|
||||
[rchanges uchanges] (impl-gen-changes objects page-id (seq ids))]
|
||||
(rx/of (commit-changes rchanges uchanges {:commit-local? true})))))))
|
||||
|
||||
|
|
|
@ -12,11 +12,15 @@
|
|||
[app.common.data :as d]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.common.pages-helpers :as cph]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as geom]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.common.pages :as cp]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
[app.main.streams :as ms]
|
||||
[app.util.color :as color]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[beicon.core :as rx]
|
||||
|
@ -107,7 +111,7 @@
|
|||
:object prev}]
|
||||
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true}))))))
|
||||
|
||||
(declare clone-shape)
|
||||
(declare make-component-shape)
|
||||
|
||||
(def add-component
|
||||
(ptk/reify ::add-component
|
||||
|
@ -127,7 +131,7 @@
|
|||
(dws/prepare-create-group page-id shapes "Component-" true))
|
||||
|
||||
[new-shape new-shapes updated-shapes]
|
||||
(clone-shape group nil objects)
|
||||
(make-component-shape group nil objects)
|
||||
|
||||
rchanges (conj rchanges
|
||||
{:type :add-component
|
||||
|
@ -168,59 +172,23 @@
|
|||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||
(dws/select-shapes (d/ordered-set (:id group))))))))))
|
||||
|
||||
(defn- clone-shape
|
||||
(defn- make-component-shape
|
||||
"Clone the shape and all children. Generate new ids and detach
|
||||
from parent and frame. Update the original shapes to have links
|
||||
to the new ones."
|
||||
[shape parent-id objects]
|
||||
(let [new-id (uuid/next)]
|
||||
(if (nil? (:shapes shape))
|
||||
(let [xf-new-shape (fn [new-shape original-shape]
|
||||
(assoc new-shape :frame-id nil))
|
||||
|
||||
; TODO: unify this case with the empty child-ids case.
|
||||
(let [new-shape (assoc shape
|
||||
:id new-id
|
||||
:parent-id parent-id
|
||||
:frame-id nil)
|
||||
xf-original-shape (fn [original-shape new-shape]
|
||||
(cond-> original-shape
|
||||
true
|
||||
(assoc :shape-ref (:id new-shape))
|
||||
|
||||
new-shapes [new-shape]
|
||||
(nil? (:parent-id new-shape))
|
||||
(assoc :component-id (:id new-shape))))]
|
||||
|
||||
updated-shapes [(cond-> shape
|
||||
true (assoc :shape-ref (:id new-shape))
|
||||
(nil? parent-id) (assoc :component-id (:id new-shape)))]]
|
||||
|
||||
[new-shape new-shapes updated-shapes])
|
||||
|
||||
(loop [child-ids (seq (:shapes shape))
|
||||
new-children []
|
||||
updated-children []]
|
||||
|
||||
(if (empty? child-ids)
|
||||
(let [new-shape (assoc shape
|
||||
:id new-id
|
||||
:parent-id parent-id
|
||||
:frame-id nil
|
||||
:shapes (map :id new-children))
|
||||
|
||||
new-shapes (conj new-children new-shape)
|
||||
|
||||
updated-shapes
|
||||
(conj updated-children
|
||||
(cond-> shape
|
||||
true (assoc :shape-ref (:id new-shape))
|
||||
(nil? parent-id) (assoc :component-id (:id new-shape))))]
|
||||
|
||||
[new-shape new-shapes updated-shapes])
|
||||
|
||||
(let [child-id (first child-ids)
|
||||
child (get objects child-id)
|
||||
|
||||
[new-child new-child-shapes updated-child-shapes]
|
||||
(clone-shape child new-id objects)]
|
||||
|
||||
(recur
|
||||
(next child-ids)
|
||||
(into new-children new-child-shapes)
|
||||
(into updated-children updated-child-shapes))))))))
|
||||
(cph/clone-object shape parent-id objects xf-new-shape xf-original-shape)))
|
||||
|
||||
(defn delete-component
|
||||
[{:keys [id] :as params}]
|
||||
|
@ -241,3 +209,145 @@
|
|||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))
|
||||
|
||||
(defn instantiate-component
|
||||
[id]
|
||||
(us/assert ::us/uuid id)
|
||||
(ptk/reify ::instantiate-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [component (get-in state [:workspace-data :components id])
|
||||
component-shape (get-in component [:objects (:id component)])
|
||||
|
||||
orig-pos (gpt/point (:x component-shape) (:y component-shape))
|
||||
mouse-pos @ms/mouse-position
|
||||
delta (gpt/subtract mouse-pos orig-pos)
|
||||
|
||||
_ (js/console.log "orig-pos" (clj->js orig-pos))
|
||||
_ (js/console.log "mouse-pos" (clj->js mouse-pos))
|
||||
_ (js/console.log "delta" (clj->js delta))
|
||||
|
||||
page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
unames (dwc/retrieve-used-names objects)
|
||||
|
||||
all-frames (cph/select-frames objects)
|
||||
|
||||
xf-new-shape
|
||||
(fn [new-shape original-shape]
|
||||
(let [new-name ;; TODO: ojoooooooooo
|
||||
(dwc/generate-unique-name unames (:name new-shape))]
|
||||
|
||||
(cond-> new-shape
|
||||
true
|
||||
(as-> $
|
||||
(assoc $ :name new-name)
|
||||
(geom/move $ delta)
|
||||
(assoc $ :frame-id
|
||||
(dwc/calculate-frame-overlap all-frames $))
|
||||
(assoc $ :parent-id
|
||||
(or (:parent-id $) (:frame-id $)))
|
||||
(assoc $ :shape-ref (:id original-shape)))
|
||||
|
||||
(nil? (:parent-id original-shape))
|
||||
(assoc :component-id (:id original-shape)))))
|
||||
|
||||
[new-shape new-shapes _]
|
||||
(cph/clone-object component-shape
|
||||
nil
|
||||
(get component :objects)
|
||||
xf-new-shape)
|
||||
|
||||
rchanges (map (fn [obj]
|
||||
{:type :add-obj
|
||||
:id (:id obj)
|
||||
:page-id page-id
|
||||
:frame-id (:frame-id obj)
|
||||
:parent-id (:parent-id obj)
|
||||
:obj obj})
|
||||
new-shapes)
|
||||
|
||||
uchanges (map (fn [obj]
|
||||
{:type :del-obj
|
||||
:id (:id obj)
|
||||
:page-id page-id})
|
||||
new-shapes)]
|
||||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||
(dws/select-shapes (d/ordered-set (:id new-shape))))))))
|
||||
|
||||
(defn detach-component
|
||||
[id]
|
||||
(us/assert ::us/uuid id)
|
||||
(ptk/reify ::detach-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
root-id (cph/get-root-component id objects)
|
||||
|
||||
shapes (cph/get-object-with-children root-id objects)
|
||||
|
||||
rchanges (map (fn [obj]
|
||||
{:type :mod-obj
|
||||
:page-id page-id
|
||||
:id (:id obj)
|
||||
:operations [{:type :set
|
||||
:attr :component-id
|
||||
:val nil}
|
||||
{:type :set
|
||||
:attr :shape-ref
|
||||
:val nil}]})
|
||||
shapes)
|
||||
|
||||
uchanges (map (fn [obj]
|
||||
{:type :mod-obj
|
||||
:page-id page-id
|
||||
:id (:id obj)
|
||||
:operations [{:type :set
|
||||
:attr :component-id
|
||||
:val (:component-id obj)}
|
||||
{:type :set
|
||||
:attr :shape-ref
|
||||
:val (:shape-ref obj)}]})
|
||||
shapes)]
|
||||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))
|
||||
|
||||
(defn reset-component
|
||||
[id]
|
||||
[id]
|
||||
(us/assert ::us/uuid id)
|
||||
(ptk/reify ::reset-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
)))
|
||||
|
||||
(defn update-component
|
||||
[id]
|
||||
[id]
|
||||
(us/assert ::us/uuid id)
|
||||
(ptk/reify ::update-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
root-id (cph/get-root-component id objects)
|
||||
root-shape (get objects id)
|
||||
component-id (get root-shape :component-id)
|
||||
component-objs (dwc/lookup-component-objects state component-id)
|
||||
|
||||
shapes (cph/get-object-with-children root-id objects)
|
||||
|
||||
rchanges [{:type :update-component
|
||||
:id component-id
|
||||
:shapes shapes}
|
||||
{:type :sync-library
|
||||
:id (get-in state [:workspace-file :id])}]
|
||||
|
||||
|
||||
uchanges [{:type :update-component
|
||||
:id component-id
|
||||
:shapes (vals component-objs)}]]
|
||||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))
|
||||
|
||||
|
|
|
@ -33,33 +33,6 @@
|
|||
(s/def ::set-of-string
|
||||
(s/every string? :kind set?))
|
||||
|
||||
;; Duplicate from workspace.
|
||||
;; FIXME: Move these functions to a common place
|
||||
|
||||
(defn interrupt? [e] (= e :interrupt))
|
||||
|
||||
(defn- retrieve-used-names
|
||||
[objects]
|
||||
(into #{} (map :name) (vals objects)))
|
||||
|
||||
(defn- extract-numeric-suffix
|
||||
[basename]
|
||||
(if-let [[match p1 p2] (re-find #"(.*)-([0-9]+)$" basename)]
|
||||
[p1 (+ 1 (d/parse-integer p2))]
|
||||
[basename 1]))
|
||||
|
||||
(defn- generate-unique-name
|
||||
"A unique name generator"
|
||||
[used basename]
|
||||
(s/assert ::set-of-string used)
|
||||
(s/assert ::us/string basename)
|
||||
(let [[prefix initial] (extract-numeric-suffix basename)]
|
||||
(loop [counter initial]
|
||||
(let [candidate (str prefix "-" counter)]
|
||||
(if (contains? used candidate)
|
||||
(recur (inc counter))
|
||||
candidate)))))
|
||||
|
||||
;; --- Selection Rect
|
||||
|
||||
(declare select-shapes-by-current-selrect)
|
||||
|
@ -88,7 +61,7 @@
|
|||
(ptk/reify ::handle-selection
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [stoper (rx/filter #(or (interrupt? %)
|
||||
(let [stoper (rx/filter #(or (dwc/interrupt? %)
|
||||
(ms/mouse-up? %))
|
||||
stream)]
|
||||
(rx/concat
|
||||
|
@ -198,7 +171,9 @@
|
|||
(let [selrect (geom/selection-rect shapes)
|
||||
frame-id (-> shapes first :frame-id)
|
||||
parent-id (-> shapes first :parent-id)
|
||||
group-name (if (and keep-name (= (count shapes) 1))
|
||||
group-name (if (and keep-name
|
||||
(= (count shapes) 1)
|
||||
(= (:type (first shapes)) :group))
|
||||
(:name (first shapes))
|
||||
(name (gensym prefix)))]
|
||||
(-> (cp/make-minimal-group frame-id selrect group-name)
|
||||
|
@ -298,7 +273,7 @@
|
|||
(defn- prepare-duplicate-shape-change
|
||||
[objects page-id names obj delta frame-id parent-id]
|
||||
(let [id (uuid/next)
|
||||
name (generate-unique-name names (:name obj))
|
||||
name (dwc/generate-unique-name names (:name obj))
|
||||
renamed-obj (assoc obj :id id :name name)
|
||||
moved-obj (geom/move renamed-obj delta)
|
||||
frames (cph/select-frames objects)
|
||||
|
@ -338,7 +313,7 @@
|
|||
(defn- prepare-duplicate-frame-change
|
||||
[objects page-id names obj delta]
|
||||
(let [frame-id (uuid/next)
|
||||
frame-name (generate-unique-name names (:name obj))
|
||||
frame-name (dwc/generate-unique-name names (:name obj))
|
||||
sch (->> (map #(get objects %) (:shapes obj))
|
||||
(mapcat #(prepare-duplicate-shape-change objects page-id names % delta frame-id frame-id)))
|
||||
|
||||
|
@ -367,7 +342,7 @@
|
|||
|
||||
selected (get-in state [:workspace-local :selected])
|
||||
delta (gpt/point 0 0)
|
||||
unames (retrieve-used-names objects)
|
||||
unames (dwc/retrieve-used-names objects)
|
||||
|
||||
rchanges (prepare-duplicate-changes objects page-id unames selected delta)
|
||||
uchanges (mapv #(array-map :type :del-obj :page-id page-id :id (:id %))
|
||||
|
|
|
@ -61,7 +61,10 @@
|
|||
do-unlock-shape #(st/emit! (dw/update-shape-flags id {:blocked false}))
|
||||
do-create-group #(st/emit! dw/group-selected)
|
||||
do-remove-group #(st/emit! dw/ungroup-selected)
|
||||
do-add-component #(st/emit! dwl/add-component)]
|
||||
do-add-component #(st/emit! dwl/add-component)
|
||||
do-detach-component #(st/emit! (dwl/detach-component id))
|
||||
do-reset-component #(st/emit! (dwl/reset-component id))
|
||||
do-update-component #(st/emit! (dwl/update-component id))]
|
||||
[:*
|
||||
[:& menu-entry {:title "Copy"
|
||||
:shortcut "Ctrl + c"
|
||||
|
@ -110,9 +113,18 @@
|
|||
:on-click do-lock-shape}])
|
||||
|
||||
[:& menu-separator]
|
||||
[:& menu-entry {:title "Create component"
|
||||
:shortcut "Ctrl + K"
|
||||
:on-click do-add-component}]
|
||||
|
||||
(if (nil? (:shape-ref shape))
|
||||
[:& menu-entry {:title "Create component"
|
||||
:shortcut "Ctrl + K"
|
||||
:on-click do-add-component}]
|
||||
[:*
|
||||
[:& menu-entry {:title "Detach instance"
|
||||
:on-click do-detach-component}]
|
||||
[:& menu-entry {:title "Reset overrides"
|
||||
:on-click do-reset-component}]
|
||||
[:& menu-entry {:title "Update master component"
|
||||
:on-click do-update-component}]])
|
||||
|
||||
[:& menu-separator]
|
||||
[:& menu-entry {:title "Delete"
|
||||
|
|
|
@ -69,8 +69,8 @@
|
|||
|
||||
on-drag-start
|
||||
(mf/use-callback
|
||||
(fn [path event]
|
||||
(dnd/set-data! event "text/uri-list" (cfg/resolve-media-path path))
|
||||
(fn [component-id event]
|
||||
(dnd/set-data! event "app/component" component-id)
|
||||
(dnd/set-allowed-effect! event "move")))]
|
||||
|
||||
[:div.asset-group
|
||||
|
@ -82,7 +82,7 @@
|
|||
[:div.grid-cell {:key (:id component)
|
||||
:draggable true
|
||||
:on-context-menu (on-context-menu (:id component))
|
||||
:on-drag-start (partial on-drag-start (:path component))}
|
||||
:on-drag-start (partial on-drag-start (:id component))}
|
||||
[:& exports/component-svg {:group (get-in component [:objects (:id component)])
|
||||
:objects (:objects component)}]
|
||||
[:div.cell-name (:name component)]])
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
[app.common.data :as d]
|
||||
[app.main.constants :as c]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.drawing :as dd]
|
||||
[app.main.data.colors :as dwc]
|
||||
[app.main.data.fetch :as mdf]
|
||||
|
@ -454,6 +455,7 @@
|
|||
on-drag-enter
|
||||
(fn [e]
|
||||
(when (or (dnd/has-type? e "app/shape")
|
||||
(dnd/has-type? e "app/component")
|
||||
(dnd/has-type? e "Files")
|
||||
(dnd/has-type? e "text/uri-list"))
|
||||
(dom/prevent-default e)))
|
||||
|
@ -461,6 +463,7 @@
|
|||
on-drag-over
|
||||
(fn [e]
|
||||
(when (or (dnd/has-type? e "app/shape")
|
||||
(dnd/has-type? e "app/component")
|
||||
(dnd/has-type? e "Files")
|
||||
(dnd/has-type? e "text/uri-list"))
|
||||
(dom/prevent-default e)))
|
||||
|
@ -491,6 +494,10 @@
|
|||
(assoc :x final-x)
|
||||
(assoc :y final-y)))))
|
||||
|
||||
(dnd/has-type? event "app/component")
|
||||
(let [component-id (dnd/get-data event "app/component")]
|
||||
(st/emit! (dwl/instantiate-component component-id)))
|
||||
|
||||
(dnd/has-type? event "text/uri-list")
|
||||
(let [data (dnd/get-data event "text/uri-list")
|
||||
lines (str/lines data)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue