mirror of
https://github.com/penpot/penpot.git
synced 2025-02-25 08:16:49 -05:00
commit
fa852a1ab8
6 changed files with 115 additions and 89 deletions
|
@ -18,7 +18,7 @@
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
|
[app.util.svg :as usvg]
|
||||||
[app.util.geom.path :as ugp]))
|
[app.util.geom.path :as ugp]))
|
||||||
|
|
||||||
(defn- svg-dimensions [data]
|
(defn- svg-dimensions [data]
|
||||||
|
@ -30,37 +30,6 @@
|
||||||
height (d/parse-integer height-str)]
|
height (d/parse-integer height-str)]
|
||||||
[width height]))
|
[width height]))
|
||||||
|
|
||||||
|
|
||||||
(defn clean-attrs
|
|
||||||
"Transforms attributes to their react equivalent"
|
|
||||||
[attrs]
|
|
||||||
(letfn [(transform-key [key]
|
|
||||||
(-> (name key)
|
|
||||||
(str/replace ":" "-")
|
|
||||||
(str/camel)
|
|
||||||
(keyword)))
|
|
||||||
|
|
||||||
(format-styles [style-str]
|
|
||||||
(->> (str/split style-str ";")
|
|
||||||
(map str/trim)
|
|
||||||
(map #(str/split % ":"))
|
|
||||||
(group-by first)
|
|
||||||
(map (fn [[key val]]
|
|
||||||
(vector
|
|
||||||
(transform-key key)
|
|
||||||
(second (first val)))))
|
|
||||||
(into {})))
|
|
||||||
|
|
||||||
(map-fn [[key val]]
|
|
||||||
(cond
|
|
||||||
(= key :class) [:className val]
|
|
||||||
(= key :style) [key (format-styles val)]
|
|
||||||
:else (vector (transform-key key) val)))]
|
|
||||||
|
|
||||||
(->> attrs
|
|
||||||
(map map-fn)
|
|
||||||
(into {}))))
|
|
||||||
|
|
||||||
(defn tag-name [{:keys [tag]}]
|
(defn tag-name [{:keys [tag]}]
|
||||||
(cond (string? tag) tag
|
(cond (string? tag) tag
|
||||||
(keyword? tag) (name tag)
|
(keyword? tag) (name tag)
|
||||||
|
@ -103,7 +72,7 @@
|
||||||
:height height
|
:height height
|
||||||
:x x
|
:x x
|
||||||
:y y
|
:y y
|
||||||
:content (if (map? data) (update data :attrs clean-attrs) data)}
|
:content (if (map? data) (update data :attrs usvg/clean-attrs) data)}
|
||||||
(gsh/setup-selrect)))
|
(gsh/setup-selrect)))
|
||||||
|
|
||||||
(defn parse-path [name frame-id {:keys [attrs] :as data}]
|
(defn parse-path [name frame-id {:keys [attrs] :as data}]
|
||||||
|
|
|
@ -228,55 +228,56 @@
|
||||||
(let [page-id (:current-page-id state)
|
(let [page-id (:current-page-id state)
|
||||||
|
|
||||||
objects0 (get-in state [:workspace-file :data :pages-index page-id :objects])
|
objects0 (get-in state [:workspace-file :data :pages-index page-id :objects])
|
||||||
objects1 (get-in state [:workspace-data :pages-index page-id :objects])
|
objects1 (get-in state [:workspace-data :pages-index page-id :objects])]
|
||||||
|
(if-not (every? #(contains? objects1(first %)) changes)
|
||||||
|
(rx/empty)
|
||||||
|
(let [change-text-shape
|
||||||
|
(fn [objects [id [new-width new-height]]]
|
||||||
|
(when (contains? objects id)
|
||||||
|
(let [shape (get objects id)
|
||||||
|
{:keys [selrect grow-type overflow-text]} (gsh/transform-shape shape)
|
||||||
|
{shape-width :width shape-height :height} selrect
|
||||||
|
|
||||||
change-text-shape
|
modifier-width (gsh/resize-modifiers shape :width new-width)
|
||||||
(fn [objects [id [new-width new-height]]]
|
modifier-height (gsh/resize-modifiers shape :height new-height)
|
||||||
|
|
||||||
(let [shape (get objects id)
|
shape (cond-> shape
|
||||||
{:keys [selrect grow-type overflow-text]} (gsh/transform-shape shape)
|
(and overflow-text (not= :fixed grow-type))
|
||||||
{shape-width :width shape-height :height} selrect
|
(assoc :overflow-text false)
|
||||||
|
|
||||||
modifier-width (gsh/resize-modifiers shape :width new-width)
|
(and (= :fixed grow-type) (not overflow-text) (> new-height shape-height))
|
||||||
modifier-height (gsh/resize-modifiers shape :height new-height)
|
(assoc :overflow-text true)
|
||||||
|
|
||||||
shape (cond-> shape
|
(and (= :fixed grow-type) overflow-text (<= new-height shape-height))
|
||||||
(and overflow-text (not= :fixed grow-type))
|
(assoc :overflow-text true)
|
||||||
(assoc :overflow-text false)
|
|
||||||
|
|
||||||
(and (= :fixed grow-type) (not overflow-text) (> new-height shape-height))
|
(and (not-changed? shape-width new-width) (= grow-type :auto-width))
|
||||||
(assoc :overflow-text true)
|
(-> (assoc :modifiers modifier-width)
|
||||||
|
(gsh/transform-shape))
|
||||||
|
|
||||||
(and (= :fixed grow-type) overflow-text (<= new-height shape-height))
|
(and (not-changed? shape-height new-height)
|
||||||
(assoc :overflow-text true)
|
(or (= grow-type :auto-height) (= grow-type :auto-width)))
|
||||||
|
(-> (assoc :modifiers modifier-height)
|
||||||
|
(gsh/transform-shape)))]
|
||||||
|
(assoc objects id shape))))
|
||||||
|
|
||||||
(and (not-changed? shape-width new-width) (= grow-type :auto-width))
|
undo-transaction (get-in state [:workspace-undo :transaction])
|
||||||
(-> (assoc :modifiers modifier-width)
|
objects2 (->> changes (reduce change-text-shape objects1))
|
||||||
(gsh/transform-shape))
|
|
||||||
|
|
||||||
(and (not-changed? shape-height new-height)
|
regchg {:type :reg-objects
|
||||||
(or (= grow-type :auto-height) (= grow-type :auto-width)))
|
:page-id page-id
|
||||||
(-> (assoc :modifiers modifier-height)
|
:shapes (vec (keys changes))}
|
||||||
(gsh/transform-shape)))]
|
|
||||||
(assoc objects id shape)))
|
|
||||||
|
|
||||||
undo-transaction (get-in state [:workspace-undo :transaction])
|
rchanges (dwc/generate-changes page-id objects1 objects2)
|
||||||
objects2 (->> changes (reduce change-text-shape objects1))
|
uchanges (dwc/generate-changes page-id objects2 objects0)]
|
||||||
|
|
||||||
regchg {:type :reg-objects
|
(if (seq rchanges)
|
||||||
:page-id page-id
|
(rx/concat
|
||||||
:shapes (vec (keys changes))}
|
(when-not undo-transaction
|
||||||
|
(rx/of (dwc/start-undo-transaction)))
|
||||||
rchanges (dwc/generate-changes page-id objects1 objects2)
|
(rx/of (dwc/commit-changes (conj rchanges regchg) (conj uchanges regchg) {:commit-local? true}))
|
||||||
uchanges (dwc/generate-changes page-id objects2 objects0)]
|
(when-not undo-transaction
|
||||||
|
(rx/of (dwc/discard-undo-transaction)))))))))))
|
||||||
(if (seq rchanges)
|
|
||||||
(rx/concat
|
|
||||||
(when-not undo-transaction
|
|
||||||
(rx/of (dwc/start-undo-transaction)))
|
|
||||||
(rx/of (dwc/commit-changes (conj rchanges regchg) (conj uchanges regchg) {:commit-local? true}))
|
|
||||||
(when-not undo-transaction
|
|
||||||
(rx/of (dwc/discard-undo-transaction)))))))))
|
|
||||||
|
|
||||||
;; When a resize-event arrives we start "buffering" for a time
|
;; When a resize-event arrives we start "buffering" for a time
|
||||||
;; after that time we invoke `resize-text-batch` with all the changes
|
;; after that time we invoke `resize-text-batch` with all the changes
|
||||||
|
@ -292,22 +293,33 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [;; This stream aggregates the events of "resizing"
|
(let [;; This stream aggregates the events of "resizing"
|
||||||
resize-events (rx/merge
|
resize-events
|
||||||
(->> (rx/of (resize-text id new-width new-height)))
|
(rx/merge
|
||||||
(->> stream (rx/filter (ptk/type? ::resize-text))))
|
(->> (rx/of (resize-text id new-width new-height)))
|
||||||
|
(->> stream (rx/filter (ptk/type? ::resize-text))))
|
||||||
|
|
||||||
;; Stop buffering after time without resizes
|
;; Stop buffering after time without resizes
|
||||||
stop-buffer (->> resize-events (rx/debounce 100))]
|
stop-buffer (->> resize-events (rx/debounce 100))
|
||||||
|
|
||||||
|
;; Agregates the resizes so only send the resize when the sizes are stable
|
||||||
|
resize-batch
|
||||||
|
(->> resize-events
|
||||||
|
(rx/take-until stop-buffer)
|
||||||
|
(rx/reduce (fn [acc event]
|
||||||
|
(assoc acc (:id @event) [(:width @event) (:height @event)]))
|
||||||
|
{id [new-width new-height]})
|
||||||
|
(rx/map #(resize-text-batch %)))
|
||||||
|
|
||||||
|
;; This stream retrieves the changes of page so we cancel the agregation
|
||||||
|
change-page
|
||||||
|
(->> stream
|
||||||
|
(rx/filter (ptk/type? :app.main.data.workspace/finalize-page))
|
||||||
|
(rx/take 1)
|
||||||
|
(rx/ignore))]
|
||||||
|
|
||||||
(if-not (::handling-texts state)
|
(if-not (::handling-texts state)
|
||||||
(->> (rx/concat
|
(->> (rx/concat
|
||||||
(rx/of #(assoc % ::handling-texts true))
|
(rx/of #(assoc % ::handling-texts true))
|
||||||
(->> resize-events
|
(rx/race resize-batch change-page)
|
||||||
(rx/take-until stop-buffer)
|
|
||||||
(rx/reduce (fn [acc event]
|
|
||||||
(assoc acc (:id @event) [(:width @event) (:height @event)]))
|
|
||||||
{id [new-width new-height]})
|
|
||||||
(rx/map #(resize-text-batch %)))
|
|
||||||
|
|
||||||
(rx/of #(dissoc % ::handling-texts))))
|
(rx/of #(dissoc % ::handling-texts))))
|
||||||
(rx/empty))))))
|
(rx/empty))))))
|
||||||
|
|
|
@ -29,14 +29,14 @@
|
||||||
(mapv resolve-shape selected)))]
|
(mapv resolve-shape selected)))]
|
||||||
#(l/derived selected->shapes st/state)))
|
#(l/derived selected->shapes st/state)))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc right-sidebar
|
(mf/defc right-sidebar
|
||||||
[{:keys [frame page-id file-id]}]
|
[{:keys [frame page-id file-id]}]
|
||||||
(let [expanded (mf/use-state false)
|
(let [expanded (mf/use-state false)
|
||||||
locale (mf/deref i18n/locale)
|
locale (mf/deref i18n/locale)
|
||||||
section (mf/use-state :info #_:code)
|
section (mf/use-state :info #_:code)
|
||||||
selected-ref (mf/use-memo (make-selected-shapes-iref))
|
selected-ref (mf/use-memo (make-selected-shapes-iref))
|
||||||
shapes (mf/deref selected-ref)]
|
shapes (mf/deref selected-ref)
|
||||||
|
selected-type (-> shapes first (:type :not-found))]
|
||||||
[:aside.settings-bar.settings-bar-right {:class (when @expanded "expanded")}
|
[:aside.settings-bar.settings-bar-right {:class (when @expanded "expanded")}
|
||||||
[:div.settings-bar-inside
|
[:div.settings-bar-inside
|
||||||
(when (seq shapes)
|
(when (seq shapes)
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
[:*
|
[:*
|
||||||
[:span.tool-window-bar-icon
|
[:span.tool-window-bar-icon
|
||||||
[:& element-icon {:shape (-> shapes first)}]]
|
[:& element-icon {:shape (-> shapes first)}]]
|
||||||
[:span.tool-window-bar-title (->> shapes first :type name (str "handoff.tabs.code.selected.") (t locale))]])
|
[:span.tool-window-bar-title (->> selected-type name (str "handoff.tabs.code.selected.") (t locale))]])
|
||||||
]
|
]
|
||||||
[:div.tool-window-content
|
[:div.tool-window-content
|
||||||
[:& tab-container {:on-change-tab #(do
|
[:& tab-container {:on-change-tab #(do
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
(let [selected (get-in state [:viewer-local :selected])
|
(let [selected (get-in state [:viewer-local :selected])
|
||||||
objects (get-in state [:viewer-data :page :objects])
|
objects (get-in state [:viewer-data :page :objects])
|
||||||
resolve-shape #(get objects %)]
|
resolve-shape #(get objects %)]
|
||||||
(mapv resolve-shape selected)))]
|
(->> selected (map resolve-shape) (filterv (comp not nil?)))))]
|
||||||
#(l/derived selected->shapes st/state)))
|
#(l/derived selected->shapes st/state)))
|
||||||
|
|
||||||
(defn make-hover-shapes-iref
|
(defn make-hover-shapes-iref
|
||||||
|
|
|
@ -9,14 +9,15 @@
|
||||||
|
|
||||||
(ns app.main.ui.shapes.svg-raw
|
(ns app.main.ui.shapes.svg-raw
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as cd]
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.ui.shapes.attrs :as usa]
|
[app.main.ui.shapes.attrs :as usa]
|
||||||
[app.util.data :as ud]
|
[app.util.data :as ud]
|
||||||
[app.common.data :as cd]
|
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
|
[app.util.svg :as usvg]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
|
@ -49,6 +50,8 @@
|
||||||
|
|
||||||
(defn set-styles [attrs shape]
|
(defn set-styles [attrs shape]
|
||||||
(let [custom-attrs (usa/extract-style-attrs shape)
|
(let [custom-attrs (usa/extract-style-attrs shape)
|
||||||
|
attrs (cond-> attrs
|
||||||
|
(string? (:style attrs)) usvg/clean-attrs)
|
||||||
style (obj/merge! (clj->js (:style attrs {}))
|
style (obj/merge! (clj->js (:style attrs {}))
|
||||||
(obj/get custom-attrs "style"))]
|
(obj/get custom-attrs "style"))]
|
||||||
(-> (clj->js attrs)
|
(-> (clj->js attrs)
|
||||||
|
|
42
frontend/src/app/util/svg.cljs
Normal file
42
frontend/src/app/util/svg.cljs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
;; 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/.
|
||||||
|
;;
|
||||||
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2020-2021 UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.util.svg
|
||||||
|
(:require
|
||||||
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
|
(defn clean-attrs
|
||||||
|
"Transforms attributes to their react equivalent"
|
||||||
|
[attrs]
|
||||||
|
(letfn [(transform-key [key]
|
||||||
|
(-> (name key)
|
||||||
|
(str/replace ":" "-")
|
||||||
|
(str/camel)
|
||||||
|
(keyword)))
|
||||||
|
|
||||||
|
(format-styles [style-str]
|
||||||
|
(->> (str/split style-str ";")
|
||||||
|
(map str/trim)
|
||||||
|
(map #(str/split % ":"))
|
||||||
|
(group-by first)
|
||||||
|
(map (fn [[key val]]
|
||||||
|
(vector
|
||||||
|
(transform-key key)
|
||||||
|
(second (first val)))))
|
||||||
|
(into {})))
|
||||||
|
|
||||||
|
(map-fn [[key val]]
|
||||||
|
(cond
|
||||||
|
(= key :class) [:className val]
|
||||||
|
(and (= key :style) (string? val)) [key (format-styles val)]
|
||||||
|
:else (vector (transform-key key) val)))]
|
||||||
|
|
||||||
|
(->> attrs
|
||||||
|
(map map-fn)
|
||||||
|
(into {}))))
|
Loading…
Add table
Reference in a new issue