mirror of
https://github.com/penpot/penpot.git
synced 2026-05-02 22:58:35 +00:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
cb6e3a2e3c
@ -728,10 +728,11 @@
|
||||
|
||||
|
||||
(defmethod read-section :v1/files
|
||||
[{:keys [::db/conn ::input ::project-id ::enabled-features ::timestamp ::overwrite?] :as system}]
|
||||
[{:keys [::db/conn ::input ::project-id ::enabled-features ::timestamp ::overwrite? ::name] :as system}]
|
||||
|
||||
(doseq [expected-file-id (-> *state* deref :files)]
|
||||
(doseq [[idx expected-file-id] (d/enumerate (-> *state* deref :files))]
|
||||
(let [file (read-obj! input)
|
||||
|
||||
media (read-obj! input)
|
||||
|
||||
file-id (:id file)
|
||||
@ -770,6 +771,8 @@
|
||||
|
||||
(let [file (-> file
|
||||
(assoc :id file-id')
|
||||
(cond-> (and (= idx 0) (some? name))
|
||||
(assoc :name name))
|
||||
(process-file))
|
||||
|
||||
;; All features that are enabled and requires explicit migration are
|
||||
@ -1105,6 +1108,7 @@
|
||||
schema:import-binfile
|
||||
(sm/define
|
||||
[:map {:title "import-binfile"}
|
||||
[:name :string]
|
||||
[:project-id ::sm/uuid]
|
||||
[:file ::media/upload]]))
|
||||
|
||||
@ -1116,12 +1120,13 @@
|
||||
::webhooks/event? true
|
||||
::sse/stream? true
|
||||
::sm/params schema:import-binfile}
|
||||
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id project-id file] :as params}]
|
||||
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id name project-id file] :as params}]
|
||||
(projects/check-read-permissions! pool profile-id project-id)
|
||||
(let [params (-> cfg
|
||||
(assoc ::input (:path file))
|
||||
(assoc ::project-id project-id)
|
||||
(assoc ::profile-id profile-id)
|
||||
(assoc ::name name)
|
||||
(assoc ::ignore-index-errors? true))]
|
||||
(with-meta
|
||||
(sse/response #(import-binfile params))
|
||||
|
||||
@ -210,7 +210,8 @@
|
||||
[:restore-component
|
||||
[:map {:title "RestoreComponentChange"}
|
||||
[:type [:= :restore-component]]
|
||||
[:id ::sm/uuid]]]
|
||||
[:id ::sm/uuid]
|
||||
[:page-id ::sm/uuid]]]
|
||||
|
||||
[:purge-component
|
||||
[:map {:title "PurgeComponentChange"}
|
||||
|
||||
@ -742,13 +742,14 @@
|
||||
changes)))
|
||||
|
||||
(defn delete-component
|
||||
[changes id]
|
||||
[changes id page-id]
|
||||
(assert-library! changes)
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :del-component
|
||||
:id id})
|
||||
(update :undo-changes conj {:type :restore-component
|
||||
:id id})))
|
||||
:id id
|
||||
:page-id page-id})))
|
||||
|
||||
(defn restore-component
|
||||
([changes id]
|
||||
|
||||
@ -44,6 +44,17 @@
|
||||
(mth/to-fixed (.-e this) precision)
|
||||
(mth/to-fixed (.-f this) precision))))
|
||||
|
||||
(defn format-precision
|
||||
[mtx precision]
|
||||
(when mtx
|
||||
(dm/fmt "matrix(%, %, %, %, %, %)"
|
||||
(mth/to-fixed (.-a mtx) precision)
|
||||
(mth/to-fixed (.-b mtx) precision)
|
||||
(mth/to-fixed (.-c mtx) precision)
|
||||
(mth/to-fixed (.-d mtx) precision)
|
||||
(mth/to-fixed (.-e mtx) precision)
|
||||
(mth/to-fixed (.-f mtx) precision))))
|
||||
|
||||
(defn matrix?
|
||||
"Return true if `v` is Matrix instance."
|
||||
[v]
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.tree-seq :as gsts]
|
||||
[app.common.logging :as l]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.text :as ct]
|
||||
@ -176,6 +177,13 @@
|
||||
(when (:shape-ref shape)
|
||||
(get-component-shape file-data component (:shape-ref shape))))
|
||||
|
||||
(defn get-shape-in-copy
|
||||
"Given a shape in the main component and the root of the copy component returns the equivalent
|
||||
shape inside the root copy that matches the main-shape"
|
||||
[file-data main-shape root-copy]
|
||||
(->> (gsts/get-children-seq (:id root-copy) (:objects file-data))
|
||||
(d/seek #(= (:shape-ref %) (:id main-shape)))))
|
||||
|
||||
(defn find-ref-shape
|
||||
"Locate the near component in the local file or libraries, and retrieve the shape
|
||||
referenced by the instance shape."
|
||||
@ -351,10 +359,10 @@
|
||||
(mapcat used-assets-container (containers-seq file-data))))
|
||||
|
||||
(defn get-or-add-library-page
|
||||
"If exists a page named 'Library backup', get the id and calculate the position to start
|
||||
"If exists a page named 'Main components', get the id and calculate the position to start
|
||||
adding new components. If not, create it and start at (0, 0)."
|
||||
[file-data grid-gap]
|
||||
(let [library-page (d/seek #(= (:name %) "Library backup") (ctpl/pages-seq file-data))]
|
||||
(let [library-page (d/seek #(= (:name %) "Main components") (ctpl/pages-seq file-data))]
|
||||
(if (some? library-page)
|
||||
(let [compare-pos (fn [pos shape]
|
||||
(let [bounds (gsh/bounding-box shape)]
|
||||
@ -366,7 +374,7 @@
|
||||
(gpt/point 0 0)
|
||||
(ctn/shapes-seq library-page))]
|
||||
[file-data (:id library-page) position])
|
||||
(let [library-page (ctp/make-empty-page (uuid/next) "Library backup")]
|
||||
(let [library-page (ctp/make-empty-page (uuid/next) "Main components")]
|
||||
[(ctpl/add-page file-data library-page) (:id library-page) (gpt/point 0 0)]))))
|
||||
|
||||
(defn- absorb-components
|
||||
|
||||
@ -102,7 +102,7 @@
|
||||
|
||||
(t/is (= (count pages) 2))
|
||||
(t/is (= (:name (first pages)) "Page 1"))
|
||||
(t/is (= (:name (second pages)) "Library backup"))
|
||||
(t/is (= (:name (second pages)) "Main components"))
|
||||
|
||||
(t/is (= (count components) 1))
|
||||
|
||||
|
||||
@ -10,6 +10,5 @@
|
||||
// debugging.
|
||||
|
||||
body {
|
||||
background-color: red;
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
;; --- Auxiliar Functions
|
||||
|
||||
(def valid-browsers
|
||||
#{:chrome :firefox :safari :edge :other})
|
||||
#{:chrome :firefox :safari :safari-16 :safari-17 :edge :other})
|
||||
|
||||
(def valid-platforms
|
||||
#{:windows :linux :macos :other})
|
||||
@ -33,13 +33,17 @@
|
||||
check-chrome? (fn [] (str/includes? user-agent "chrom"))
|
||||
check-firefox? (fn [] (str/includes? user-agent "firefox"))
|
||||
check-edge? (fn [] (str/includes? user-agent "edg"))
|
||||
check-safari? (fn [] (str/includes? user-agent "safari"))]
|
||||
check-safari? (fn [] (str/includes? user-agent "safari"))
|
||||
check-safari-16? (fn [] (and (check-safari?) (str/includes? user-agent "version/16")))
|
||||
check-safari-17? (fn [] (and (check-safari?) (str/includes? user-agent "version/17")))]
|
||||
(cond
|
||||
(check-edge?) :edge
|
||||
(check-chrome?) :chrome
|
||||
(check-firefox?) :firefox
|
||||
(check-safari?) :safari
|
||||
:else :other)))
|
||||
(check-edge?) :edge
|
||||
(check-chrome?) :chrome
|
||||
(check-firefox?) :firefox
|
||||
(check-safari-16?) :safari-16
|
||||
(check-safari-17?) :safari-17
|
||||
(check-safari?) :safari
|
||||
:else :other)))
|
||||
|
||||
(defn- parse-platform
|
||||
[]
|
||||
@ -130,7 +134,9 @@
|
||||
|
||||
(defn ^boolean check-browser? [candidate]
|
||||
(dm/assert! (contains? valid-browsers candidate))
|
||||
(= candidate browser))
|
||||
(if (= candidate :safari)
|
||||
(contains? #{:safari :safari-16 :safari-17} browser)
|
||||
(= candidate browser)))
|
||||
|
||||
(defn ^boolean check-platform? [candidate]
|
||||
(dm/assert! (contains? valid-platforms candidate))
|
||||
|
||||
@ -551,7 +551,7 @@
|
||||
(map :component-id))
|
||||
|
||||
changes (reduce (fn [changes component-id]
|
||||
(pcb/delete-component changes component-id))
|
||||
(pcb/delete-component changes component-id (:id page)))
|
||||
changes
|
||||
components-to-delete)]
|
||||
changes))
|
||||
|
||||
@ -129,6 +129,9 @@
|
||||
|
||||
(->> ms/mouse-position
|
||||
(rx/filter #(> (gpt/distance % initial) (/ 2 zoom)))
|
||||
;; Take until before the snap calculation otherwise we could cancel the snap in the worker
|
||||
;; and its a problem for fast moving drawing
|
||||
(rx/take-until stoper)
|
||||
(rx/with-latest-from ms/mouse-position-shift ms/mouse-position-mod)
|
||||
(rx/switch-map
|
||||
(fn [[point :as current]]
|
||||
@ -136,8 +139,7 @@
|
||||
(rx/map (partial array/conj current)))))
|
||||
(rx/map
|
||||
(fn [[_ shift? mod? point]]
|
||||
#(update-drawing % initial (cond-> point snap-pixel? (gpt/round-step snap-prec)) shift? mod?)))))
|
||||
(rx/take-until stoper))
|
||||
#(update-drawing % initial (cond-> point snap-pixel? (gpt/round-step snap-prec)) shift? mod?))))))
|
||||
|
||||
(->> (rx/of (common/handle-finish-drawing))
|
||||
(rx/delay 100)))))))
|
||||
|
||||
@ -483,9 +483,10 @@
|
||||
(rx/of
|
||||
(dwt/clear-thumbnail (:current-file-id state) page-id root-id "component")
|
||||
(dwsh/delete-shapes page-id #{root-id}))) ;; Deleting main root triggers component delete
|
||||
(let [changes (-> (pcb/empty-changes it)
|
||||
(let [page-id (:current-page-id state)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(pcb/delete-component id))]
|
||||
(pcb/delete-component id page-id))]
|
||||
(rx/of (dch/commit-changes changes))))))))
|
||||
|
||||
|
||||
|
||||
@ -51,6 +51,8 @@
|
||||
(declare change-touched)
|
||||
(declare change-remote-synced)
|
||||
(declare update-attrs)
|
||||
(declare update-grid-main-attrs)
|
||||
(declare update-grid-copy-attrs)
|
||||
(declare reposition-shape)
|
||||
(declare make-change)
|
||||
|
||||
@ -665,6 +667,13 @@
|
||||
container
|
||||
omit-touched?)
|
||||
|
||||
(ctl/grid-layout? shape-main)
|
||||
(update-grid-copy-attrs shape-main
|
||||
shape-inst
|
||||
library
|
||||
component
|
||||
container)
|
||||
|
||||
reset?
|
||||
(change-touched shape-inst
|
||||
shape-main
|
||||
@ -836,6 +845,12 @@
|
||||
component-container
|
||||
{:copy-touched? true}))
|
||||
|
||||
(ctl/grid-layout? shape-main)
|
||||
(update-grid-main-attrs shape-main
|
||||
shape-inst
|
||||
component-container
|
||||
container)
|
||||
|
||||
clear-remote-synced?
|
||||
(change-remote-synced shape-inst container nil)
|
||||
|
||||
@ -957,12 +972,12 @@
|
||||
(recur (next children-inst)
|
||||
(remove #(= (:id %) (:id child-main')) children-main)
|
||||
(-> changes
|
||||
(both-cb child-inst' child-main)
|
||||
(both-cb child-inst child-main')
|
||||
(moved-cb child-inst child-main')))
|
||||
(recur (remove #(= (:id %) (:id child-inst')) children-inst)
|
||||
(next children-main)
|
||||
(-> changes
|
||||
(both-cb child-inst child-main')
|
||||
(both-cb child-inst' child-main)
|
||||
(moved-cb child-inst' child-main)))))))))))
|
||||
|
||||
(defn- add-shape-to-instance
|
||||
@ -1286,7 +1301,9 @@
|
||||
origin-shape (reposition-shape origin-shape origin-root dest-root)
|
||||
touched (get dest-shape :touched #{})]
|
||||
|
||||
(loop [attrs (seq (keys ctk/sync-attrs))
|
||||
(loop [attrs (->> (seq (keys ctk/sync-attrs))
|
||||
;; We don't do automatic update of the `layout-grid-cells` property.
|
||||
(remove #(= :layout-grid-cells %)))
|
||||
roperations []
|
||||
uoperations '()]
|
||||
|
||||
@ -1335,6 +1352,50 @@
|
||||
(conj roperations roperation)
|
||||
(conj uoperations uoperation)))))))))
|
||||
|
||||
(defn- update-grid-copy-attrs
|
||||
"Synchronizes the `layout-grid-cells` property from the main shape to the copies"
|
||||
[changes shape-main shape-copy main-container main-component copy-container]
|
||||
(let [ids-map
|
||||
(into {}
|
||||
(comp
|
||||
(map #(dm/get-in copy-container [:objects %]))
|
||||
(keep
|
||||
(fn [copy-shape]
|
||||
(let [main-shape (ctf/get-ref-shape main-container main-component copy-shape)]
|
||||
[(:id main-shape) (:id copy-shape)]))))
|
||||
(:shapes shape-copy))]
|
||||
|
||||
(-> changes
|
||||
(pcb/with-container copy-container)
|
||||
(pcb/update-shapes
|
||||
[(:id shape-copy)]
|
||||
(fn [shape-copy]
|
||||
;; Take cells from main and remap the shapes to assign it to the copy
|
||||
(let [new-cells (-> (ctl/remap-grid-cells shape-main ids-map) :layout-grid-cells)]
|
||||
(assoc shape-copy :layout-grid-cells new-cells)))))))
|
||||
|
||||
(defn- update-grid-main-attrs
|
||||
"Synchronizes the `layout-grid-cells` property from the copy to the main shape"
|
||||
[changes shape-main shape-copy main-container copy-container]
|
||||
(let [ids-map
|
||||
(into {}
|
||||
(comp
|
||||
(map #(dm/get-in main-container [:objects %]))
|
||||
(keep
|
||||
(fn [main-shape]
|
||||
(let [copy-shape (ctf/get-shape-in-copy copy-container main-shape shape-copy)]
|
||||
[(:id copy-shape) (:id main-shape)]))))
|
||||
(:shapes shape-main))]
|
||||
(-> changes
|
||||
(pcb/with-page main-container)
|
||||
(pcb/with-objects (:objects main-container))
|
||||
(pcb/update-shapes
|
||||
[(:id shape-main)]
|
||||
(fn [shape-main]
|
||||
;; Take cells from copy and remap the shapes to assign it to the copy
|
||||
(let [new-cells (-> (ctl/remap-grid-cells shape-copy ids-map) :layout-grid-cells)]
|
||||
(assoc shape-main :layout-grid-cells new-cells)))))))
|
||||
|
||||
(defn- reposition-shape
|
||||
[shape origin-root dest-root]
|
||||
(let [shape-pos (fn [shape]
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
|
||||
(ns app.main.data.workspace.media
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.files.builder :as fb]
|
||||
@ -308,9 +309,37 @@
|
||||
|
||||
process-svg
|
||||
(fn [svg-data]
|
||||
(let [[shape children]
|
||||
(csvg.shapes-builder/create-svg-shapes svg-data pos objects uuid/zero nil #{} false)]
|
||||
[shape children]))]
|
||||
(let [[root-svg-shape children]
|
||||
(csvg.shapes-builder/create-svg-shapes svg-data pos objects uuid/zero nil #{} false)
|
||||
|
||||
frame-shape
|
||||
(cts/setup-shape
|
||||
{:type :frame
|
||||
:x (:x pos)
|
||||
:y (:y pos)
|
||||
:width (-> root-svg-shape :selrect :width)
|
||||
:height (-> root-svg-shape :selrect :height)
|
||||
:name (:name root-svg-shape)
|
||||
:frame-id uuid/zero
|
||||
:parent-id uuid/zero
|
||||
:fills []})
|
||||
|
||||
root-svg-shape
|
||||
(-> root-svg-shape
|
||||
(assoc :frame-id (:id frame-shape) :parent-id (:id frame-shape)))
|
||||
|
||||
shapes
|
||||
(->> children
|
||||
(filter #(= (:parent-id %) (:id root-svg-shape)))
|
||||
(mapv :id))
|
||||
|
||||
root-svg-shape
|
||||
(assoc root-svg-shape :shapes shapes)
|
||||
|
||||
children (->> children (mapv #(assoc % :frame-id (:id frame-shape))))
|
||||
children (d/concat-vec [root-svg-shape] children)]
|
||||
|
||||
[frame-shape children]))]
|
||||
|
||||
(->> (upload-images svg-data)
|
||||
(rx/map process-svg))))
|
||||
@ -427,4 +456,3 @@
|
||||
(rx/tap on-success)
|
||||
(rx/catch on-error)
|
||||
(rx/finalize #(st/emit! (msg/hide-tag :media-loading)))))))))
|
||||
|
||||
|
||||
@ -240,7 +240,7 @@
|
||||
changes (reduce (fn [changes component-id]
|
||||
;; It's important to delete the component before the main instance, because we
|
||||
;; need to store the instance position if we want to restore it later.
|
||||
(pcb/delete-component changes component-id))
|
||||
(pcb/delete-component changes component-id (:id page)))
|
||||
changes
|
||||
components-to-delete)
|
||||
|
||||
|
||||
@ -305,7 +305,7 @@
|
||||
|
||||
[:div {:class (stl/css :project-actions)}
|
||||
(when-not (:is-default project)
|
||||
[:> pin-button* {:is-pinned (:is-pinned project) :on-click toggle-pin :tab-index 0}])
|
||||
[:> pin-button* {:class (stl/css :pin-button) :is-pinned (:is-pinned project) :on-click toggle-pin :tab-index 0}])
|
||||
|
||||
[:button
|
||||
{:class (stl/css :btn-secondary :btn-small :tooltip :tooltip-bottom)
|
||||
|
||||
@ -108,10 +108,7 @@
|
||||
opacity: 1;
|
||||
margin-left: $s-32;
|
||||
|
||||
svg {
|
||||
fill: $df-primary;
|
||||
}
|
||||
.btn-small {
|
||||
.btn-small:not(.pin-button) {
|
||||
height: $s-32;
|
||||
margin: 0 $s-8;
|
||||
width: $s-32;
|
||||
@ -120,6 +117,7 @@
|
||||
background: transparent;
|
||||
}
|
||||
svg {
|
||||
fill: $df-primary;
|
||||
height: $s-16;
|
||||
width: $s-16;
|
||||
}
|
||||
|
||||
@ -18,19 +18,19 @@
|
||||
(mf/fnc bool-shape
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [shape (unchecked-get props "shape")
|
||||
children (unchecked-get props "childs")
|
||||
children (h/use-equal-memo children)
|
||||
(let [shape (unchecked-get props "shape")
|
||||
child-objs (unchecked-get props "childs")
|
||||
child-objs (h/use-equal-memo child-objs)
|
||||
|
||||
metadata? (mf/use-ctx use/include-metadata-ctx)
|
||||
content (mf/with-memo [shape children]
|
||||
content (mf/with-memo [shape child-objs]
|
||||
(let [content (:bool-content shape)]
|
||||
(cond
|
||||
(some? content)
|
||||
content
|
||||
|
||||
(some? children)
|
||||
(gsh/calc-bool-content shape children))))
|
||||
(some? child-objs)
|
||||
(gsh/calc-bool-content shape child-objs))))
|
||||
|
||||
shape (mf/with-memo [shape content]
|
||||
(assoc shape :content content))]
|
||||
@ -40,9 +40,8 @@
|
||||
[:& path-shape {:shape shape}])
|
||||
|
||||
(when metadata?
|
||||
;; FIXME: get children looks wrong
|
||||
[:> "penpot:bool" {}
|
||||
(for [item (map #(get children %) (:shapes shape))]
|
||||
(for [item (map #(get child-objs %) (:shapes shape))]
|
||||
[:& shape-wrapper
|
||||
{:shape item
|
||||
:key (dm/str (dm/get-prop item :id))}])])])))
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
:width width
|
||||
:height height}
|
||||
|
||||
pat-props (if (= :path type)
|
||||
pat-props (if (or (= :path type) (= :bool type))
|
||||
(obj/set! pat-props "patternTransform" transform)
|
||||
pat-props)]
|
||||
|
||||
|
||||
@ -179,7 +179,7 @@
|
||||
:on-key-down (fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(toggle-flag event)))
|
||||
:data-test "scale.-text"
|
||||
:data-test "scale-text"
|
||||
:id "file-menu-scale-text"}
|
||||
[:span {:class (stl/css :item-name)}
|
||||
(if (contains? layout :scale-text)
|
||||
|
||||
@ -281,7 +281,7 @@
|
||||
;; NOTE: this teoretically breaks hooks rules, but in practice
|
||||
;; it is imposible to really break it
|
||||
maybe-zoom
|
||||
(when (cf/check-browser? :safari)
|
||||
(when (cf/check-browser? :safari-16)
|
||||
(mf/deref refs/selected-zoom))
|
||||
|
||||
shape (cond-> shape
|
||||
@ -300,26 +300,27 @@
|
||||
width (mth/max (dm/get-prop bounds :width)
|
||||
(dm/get-prop shape :width))
|
||||
height (mth/max (dm/get-prop bounds :height)
|
||||
(dm/get-prop shape :height))]
|
||||
(dm/get-prop shape :height))
|
||||
|
||||
style
|
||||
(cond-> #js {:pointer-events "all"}
|
||||
(cf/check-browser? :safari-16)
|
||||
(obj/merge!
|
||||
#js {:position "fixed"
|
||||
:left 0
|
||||
:top (- (dm/get-prop shape :y) y)
|
||||
:transform-origin "top left"
|
||||
:transform (when (some? maybe-zoom)
|
||||
(dm/fmt "scale(%)" maybe-zoom))}))]
|
||||
|
||||
[:g.text-editor {:clip-path (dm/fmt "url(#%)" clip-id)
|
||||
:transform (dm/str (gsh/transform-matrix shape))}
|
||||
[:defs
|
||||
[:clipPath {:id clip-id}
|
||||
[:rect {:x x
|
||||
:y y
|
||||
:width width
|
||||
:height height
|
||||
:fill "red"}]]]
|
||||
[:rect {:x x :y y :width width :height height}]]]
|
||||
|
||||
[:foreignObject {:x x :y y :width width :height height}
|
||||
[:div {:style {:position "fixed"
|
||||
:left 0
|
||||
:top (- (dm/get-prop shape :y) y)
|
||||
:pointer-events "all"
|
||||
:transform-origin "top left"
|
||||
:transform (when (some? maybe-zoom)
|
||||
(dm/fmt "scale(%)" maybe-zoom))}}
|
||||
[:div {:style style}
|
||||
[:& text-shape-edit-html
|
||||
{:shape shape
|
||||
:key (dm/str shape-id)}]]]]))
|
||||
|
||||
@ -19,11 +19,13 @@
|
||||
[app.main.ui.workspace.right-header :refer [right-header]]
|
||||
[app.main.ui.workspace.sidebar.assets :refer [assets-toolbox]]
|
||||
[app.main.ui.workspace.sidebar.debug :refer [debug-panel]]
|
||||
[app.main.ui.workspace.sidebar.debug-shape-info :refer [debug-shape-info]]
|
||||
[app.main.ui.workspace.sidebar.history :refer [history-toolbox]]
|
||||
[app.main.ui.workspace.sidebar.layers :refer [layers-toolbox]]
|
||||
[app.main.ui.workspace.sidebar.options :refer [options-toolbox]]
|
||||
[app.main.ui.workspace.sidebar.shortcuts :refer [shortcuts-container]]
|
||||
[app.main.ui.workspace.sidebar.sitemap :refer [sitemap]]
|
||||
[app.util.debug :as dbg]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[app.util.object :as obj]
|
||||
[rumext.v2 :as mf]))
|
||||
@ -134,10 +136,11 @@
|
||||
current-section* (mf/use-state :info)
|
||||
current-section (deref current-section*)
|
||||
|
||||
can-be-expanded? (and (not is-comments?)
|
||||
(not is-history?)
|
||||
is-inspect?
|
||||
(= current-section :code))
|
||||
can-be-expanded? (or (dbg/enabled? :shape-panel)
|
||||
(and (not is-comments?)
|
||||
(not is-history?)
|
||||
is-inspect?
|
||||
(= current-section :code)))
|
||||
|
||||
{:keys [on-pointer-down on-lost-pointer-capture on-pointer-move set-size size]}
|
||||
(use-resize-hook :code 276 276 768 :x true :right)
|
||||
@ -176,6 +179,9 @@
|
||||
|
||||
[:div {:class (stl/css :settings-bar-inside)}
|
||||
(cond
|
||||
(dbg/enabled? :shape-panel)
|
||||
[:& debug-shape-info]
|
||||
|
||||
(true? is-comments?)
|
||||
[:& comments-sidebar]
|
||||
|
||||
|
||||
@ -60,6 +60,7 @@ $width-settings-bar-max: $s-500;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 0;
|
||||
&.not-expand {
|
||||
max-width: $width-settings-bar;
|
||||
}
|
||||
|
||||
101
frontend/src/app/main/ui/workspace/sidebar/debug_shape_info.cljs
Normal file
101
frontend/src/app/main/ui/workspace/sidebar/debug_shape_info.cljs
Normal file
@ -0,0 +1,101 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; 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) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.workspace.sidebar.debug-shape-info
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.icons :as i]
|
||||
[debug :as dbg]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def remove-attrs
|
||||
#{:id :name})
|
||||
|
||||
(def vertical-layout-attrs
|
||||
#{})
|
||||
|
||||
(def custom-renderer
|
||||
{:parent-id :shape-link
|
||||
:frame-id :shape-link
|
||||
:shapes :shape-list
|
||||
:shape-ref :shape-link
|
||||
:transform :matrix-render
|
||||
:transform-inverse :matrix-render
|
||||
:selrect :rect-render
|
||||
:points :points-render})
|
||||
|
||||
(mf/defc shape-link
|
||||
[{:keys [id objects]}]
|
||||
[:a {:class (stl/css :shape-link)
|
||||
:on-click #(st/emit! (dw/select-shape id))}
|
||||
(dm/str (dm/get-in objects [id :name]) " #" id)])
|
||||
|
||||
(mf/defc debug-shape-attr
|
||||
[{:keys [attr value objects]}]
|
||||
|
||||
(case (get custom-renderer attr)
|
||||
:shape-link
|
||||
[:& shape-link {:id value :objects objects}]
|
||||
|
||||
:shape-list
|
||||
[:div {:class (stl/css :shape-list)}
|
||||
(for [id value]
|
||||
[:& shape-link {:id id :objects objects}])]
|
||||
|
||||
:matrix-render
|
||||
[:div (dm/str (gmt/format-precision value 2))]
|
||||
|
||||
:rect-render
|
||||
[:div (dm/fmt "X:% Y:% W:% H:%" (:x value) (:y value) (:width value) (:height value))]
|
||||
|
||||
:points-render
|
||||
[:div {:class (stl/css :point-list)}
|
||||
(for [point value]
|
||||
[:div (dm/fmt "(%, %)" (:x point) (:y point))])]
|
||||
|
||||
[:div {:class (stl/css :attrs-container-value)} (str value)]))
|
||||
|
||||
(mf/defc debug-shape-info
|
||||
[]
|
||||
(let [objects (mf/deref refs/workspace-page-objects)
|
||||
selected (->> (mf/deref refs/selected-shapes)
|
||||
(map (d/getf objects)))]
|
||||
|
||||
[:div {:class (stl/css :shape-info)}
|
||||
[:div {:class (stl/css :shape-info-title)}
|
||||
[:span "Debug"]
|
||||
[:div {:class (stl/css :close-button)
|
||||
:on-click #(dbg/disable! :shape-panel)}
|
||||
i/close-refactor]]
|
||||
|
||||
(if (empty? selected)
|
||||
[:div {:class (stl/css :attrs-container)} "No shapes selected"]
|
||||
(for [[idx current] (d/enumerate selected)]
|
||||
[:div {:class (stl/css :attrs-container) :key (dm/str "shape" idx)}
|
||||
[:div {:class (stl/css :shape-title)}
|
||||
[:div {:class (stl/css :shape-name)} (:name current)]
|
||||
[:button {:on-click #(debug/dump-object (dm/str (:id current)))} "object"]
|
||||
[:button {:on-click #(debug/dump-subtree (dm/str (:id current)) true)} "tree"]]
|
||||
|
||||
[:div {:class (stl/css :shape-attrs)}
|
||||
(let [attrs (->> (keys current)
|
||||
(remove remove-attrs))
|
||||
attrs (concat [:frame-id :parent-id :shapes]
|
||||
(->> attrs (remove #{:frame-id :parent-id :shapes})))]
|
||||
(for [attr attrs]
|
||||
(when-let [value (get current attr)]
|
||||
[:div {:class (stl/css-case :attrs-container-attr true
|
||||
:vertical-layout (contains? vertical-layout-attrs attr))
|
||||
:key (dm/str "att-" idx "-" attr)}
|
||||
[:div {:class (stl/css :attrs-container-name)} (d/name attr)]
|
||||
|
||||
[:& debug-shape-attr {:attr attr :value value :objects objects}]])))]]))]))
|
||||
@ -0,0 +1,98 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// 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) KALEIDOS INC
|
||||
|
||||
@import "refactor/common-refactor.scss";
|
||||
|
||||
.shape-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--panel-background-color);
|
||||
color: white;
|
||||
font-size: $fs-12;
|
||||
}
|
||||
|
||||
.shape-info-title {
|
||||
@include flexCenter;
|
||||
@include tabTitleTipography;
|
||||
position: relative;
|
||||
height: $s-32;
|
||||
min-height: $s-32;
|
||||
margin: $s-8 $s-8 0 $s-8;
|
||||
border-radius: $br-8;
|
||||
background-color: var(--panel-title-background-color);
|
||||
|
||||
span {
|
||||
@include flexCenter;
|
||||
flex-grow: 1;
|
||||
color: var(--title-foreground-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
@extend .button-tertiary;
|
||||
position: absolute;
|
||||
right: $s-2;
|
||||
top: $s-2;
|
||||
height: $s-28;
|
||||
width: $s-28;
|
||||
border-radius: $br-6;
|
||||
svg {
|
||||
@extend .button-icon;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
}
|
||||
|
||||
.attrs-container {
|
||||
padding: $s-16 $s-8;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.shape-title {
|
||||
font-size: $fs-14;
|
||||
padding-bottom: $s-4;
|
||||
background: $db-cuaternary;
|
||||
color: $df-primary;
|
||||
padding: $s-8;
|
||||
border-radius: $s-8;
|
||||
display: flex;
|
||||
gap: $s-4;
|
||||
}
|
||||
.shape-name {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.attrs-container-attr {
|
||||
display: grid;
|
||||
grid-template-columns: 25% auto;
|
||||
padding: $s-4 0;
|
||||
|
||||
&.vertical-layout {
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.shape-attrs {
|
||||
overflow: auto;
|
||||
height: calc(100% - 8px);
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.shape-link {
|
||||
color: $df-primary;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.shape-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $s-4;
|
||||
}
|
||||
|
||||
.point-list {
|
||||
display: flex;
|
||||
gap: $s-8;
|
||||
}
|
||||
@ -508,7 +508,7 @@
|
||||
|
||||
[:div {:class (stl/css :component-name)} (if multi
|
||||
(tr "settings.multiple")
|
||||
shape-name)]
|
||||
(cfh/last-path shape-name))]
|
||||
(when show-menu?
|
||||
[:div {:class (stl/css :component-actions)}
|
||||
[:button {:class (stl/css :menu-btn)
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--title-foreground-color);
|
||||
margin-right: $s-8;
|
||||
}
|
||||
|
||||
.component-icon {
|
||||
@ -65,7 +66,6 @@
|
||||
.component-parent-name {
|
||||
@include titleTipography;
|
||||
@include textEllipsis;
|
||||
direction: rtl;
|
||||
text-align: left;
|
||||
max-width: 95%;
|
||||
padding-left: $s-36;
|
||||
|
||||
@ -377,8 +377,8 @@
|
||||
[:clipPath {:id "clip-handlers"}
|
||||
[:rect {:x (+ (:x vbox) rule-area-size)
|
||||
:y (+ (:y vbox) rule-area-size)
|
||||
:width (max 0 (- (:width vbox) (* rule-area-size 2)))
|
||||
:height (max 0 (- (:height vbox) (* rule-area-size 2)))}]]]
|
||||
:width (max 0 (- (:width vbox) rule-area-size))
|
||||
:height (max 0 (- (:height vbox) rule-area-size))}]]]
|
||||
|
||||
[:g {:style {:pointer-events (if disable-events? "none" "auto")}}
|
||||
(when show-text-editor?
|
||||
@ -539,12 +539,6 @@
|
||||
[:& presence/active-cursors
|
||||
{:page-id page-id}])
|
||||
|
||||
[:& scroll-bars/viewport-scrollbars
|
||||
{:objects base-objects
|
||||
:zoom zoom
|
||||
:vbox vbox
|
||||
:bottom-padding (when palete-size (+ palete-size 8))}]
|
||||
|
||||
(when-not hide-ui?
|
||||
[:& rules/rules
|
||||
{:zoom zoom
|
||||
@ -637,4 +631,10 @@
|
||||
:objects base-objects
|
||||
:modifiers modifiers
|
||||
:shape frame
|
||||
:view-only true}]))]]]]))
|
||||
:view-only true}]))
|
||||
|
||||
[:& scroll-bars/viewport-scrollbars
|
||||
{:objects base-objects
|
||||
:zoom zoom
|
||||
:vbox vbox
|
||||
:bottom-padding (when palete-size (+ palete-size 8))}]]]]]))
|
||||
|
||||
@ -114,6 +114,7 @@
|
||||
position: absolute;
|
||||
top: $s-44;
|
||||
left: 50%;
|
||||
z-index: $z-index-20;
|
||||
|
||||
.grid-actions-container {
|
||||
@include flexRow;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
(ns app.main.ui.workspace.viewport.pixel-overlay
|
||||
(:require
|
||||
[app.common.math :as mth]
|
||||
[app.config :as cfg]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace.colors :as dwc]
|
||||
[app.main.data.workspace.undo :as dwu]
|
||||
@ -99,7 +100,9 @@
|
||||
;; I don't know why, but the zoom view is offset by 24px
|
||||
;; instead of 25.
|
||||
sx (- x 32)
|
||||
sy (- y 17)
|
||||
|
||||
;; Safari has a different offset fro the y coord
|
||||
sy (if (cfg/check-browser? :safari) y (- y 17))
|
||||
sw 65
|
||||
sh 35
|
||||
dx 0
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
position: absolute;
|
||||
top: $s-44;
|
||||
left: 50%;
|
||||
z-index: $z-index-20;
|
||||
|
||||
.viewport-actions-container {
|
||||
@include flexRow;
|
||||
|
||||
@ -77,7 +77,10 @@
|
||||
:grid-layout
|
||||
|
||||
;; Show an overlay to the grid cells to know its properties
|
||||
:grid-cells})
|
||||
:grid-cells
|
||||
|
||||
;; Show info about shapes
|
||||
:shape-panel})
|
||||
|
||||
(defn enable!
|
||||
[option]
|
||||
|
||||
@ -728,7 +728,10 @@
|
||||
:method :get})
|
||||
(rx/map :body)
|
||||
(rx/mapcat (fn [file]
|
||||
(->> (rp/cmd! ::sse/import-binfile {:file file :project-id project-id})
|
||||
(->> (rp/cmd! ::sse/import-binfile
|
||||
{:name (str/replace (:name data) #".penpot$" "")
|
||||
:file file
|
||||
:project-id project-id})
|
||||
(rx/tap (fn [event]
|
||||
(let [payload (sse/get-payload event)
|
||||
type (sse/get-type event)]
|
||||
|
||||
@ -57,14 +57,14 @@
|
||||
:app.main.data.websocket/send-message
|
||||
:app.main.data.workspace.selection/change-hover-state})
|
||||
|
||||
(defn- enable!
|
||||
(defn enable!
|
||||
[option]
|
||||
(dbg/enable! option)
|
||||
(when (= :events option)
|
||||
(set! st/*debug-events* true))
|
||||
(js* "app.main.reinit()"))
|
||||
|
||||
(defn- disable!
|
||||
(defn disable!
|
||||
[option]
|
||||
(dbg/disable! option)
|
||||
(when (= :events option)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user