mirror of
https://github.com/penpot/penpot.git
synced 2025-05-22 05:06:14 +02:00
139 lines
5.4 KiB
Clojure
139 lines
5.4 KiB
Clojure
;; 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) UXBOX Labs SL
|
|
|
|
(ns app.main.ui.shapes.export
|
|
(:require
|
|
[app.common.data :as d]
|
|
[app.common.geom.matrix :as gmt]
|
|
[app.common.geom.shapes :as gsh]
|
|
[app.util.json :as json]
|
|
[app.util.object :as obj]
|
|
[app.util.svg :as usvg]
|
|
[cuerdas.core :as str]
|
|
[rumext.alpha :as mf]))
|
|
|
|
(mf/defc render-xml
|
|
[{{:keys [tag attrs content] :as node} :xml}]
|
|
|
|
(cond
|
|
(map? node)
|
|
[:> (d/name tag) (clj->js (usvg/clean-attrs attrs))
|
|
(for [child content]
|
|
[:& render-xml {:xml child}])]
|
|
|
|
(string? node)
|
|
node
|
|
|
|
:else
|
|
nil))
|
|
|
|
(defn bool->str [val]
|
|
(when (some? val) (str val)))
|
|
|
|
(defn add-data
|
|
"Adds as metadata properties that we cannot deduce from the exported SVG"
|
|
[props shape]
|
|
(letfn [(add!
|
|
([props attr]
|
|
(add! props attr str))
|
|
|
|
([props attr trfn]
|
|
(let [val (get shape attr)
|
|
val (if (keyword? val) (d/name val) val)
|
|
ns-attr (str "penpot:" (-> attr d/name))]
|
|
(cond-> props
|
|
(some? val)
|
|
(obj/set! ns-attr (trfn val))))))]
|
|
(let [frame? (= :frame (:type shape))
|
|
group? (= :group (:type shape))
|
|
rect? (= :rect (:type shape))
|
|
text? (= :text (:type shape))
|
|
mask? (and group? (:masked-group? shape))
|
|
center (gsh/center-shape shape)]
|
|
(-> props
|
|
(add! :name)
|
|
(add! :blocked)
|
|
(add! :hidden)
|
|
(add! :type)
|
|
(add! :stroke-style)
|
|
(add! :stroke-alignment)
|
|
(add! :transform)
|
|
(add! :transform-inverse)
|
|
(add! :flip-x)
|
|
(add! :flip-y)
|
|
(add! :proportion)
|
|
(add! :proportion-lock)
|
|
(add! :rotation)
|
|
(obj/set! "penpot:center-x" (-> center :x str))
|
|
(obj/set! "penpot:center-y" (-> center :y str))
|
|
|
|
(cond-> (and rect? (some? (:r1 shape)))
|
|
(-> (add! :r1)
|
|
(add! :r2)
|
|
(add! :r3)
|
|
(add! :r4)))
|
|
|
|
(cond-> text?
|
|
(-> (add! :grow-type)
|
|
(add! :content json/encode)))
|
|
|
|
(cond-> mask?
|
|
(obj/set! "penpot:masked-group" "true"))))))
|
|
|
|
(mf/defc export-data
|
|
[{:keys [shape]}]
|
|
(let [props (-> (obj/new)
|
|
(add-data shape))]
|
|
[:> "penpot:shape" props
|
|
(for [{:keys [style hidden color offset-x offset-y blur spread]} (:shadow shape)]
|
|
[:> "penpot:shadow" #js {:penpot:shadow-type (d/name style)
|
|
:penpot:hidden (str hidden)
|
|
:penpot:color (str (:color color))
|
|
:penpot:opacity (str (:opacity color))
|
|
:penpot:offset-x (str offset-x)
|
|
:penpot:offset-y (str offset-y)
|
|
:penpot:blur (str blur)
|
|
:penpot:spread (str spread)}])
|
|
|
|
(when (some? (:blur shape))
|
|
(let [{:keys [type hidden value]} (:blur shape)]
|
|
[:> "penpot:blur" #js {:penpot:blur-type (d/name type)
|
|
:penpot:hidden (str hidden)
|
|
:penpot:value (str value)}]))
|
|
|
|
(for [{:keys [scale suffix type]} (:exports shape)]
|
|
[:> "penpot:export" #js {:penpot:type (d/name type)
|
|
:penpot:suffix suffix
|
|
:penpot:scale (str scale)}])
|
|
|
|
(when (contains? shape :svg-attrs)
|
|
(let [svg-transform (get shape :svg-transform)
|
|
svg-attrs (->> shape :svg-attrs keys (mapv d/name) (str/join ",") )
|
|
svg-defs (->> shape :svg-defs keys (mapv d/name) (str/join ","))]
|
|
[:> "penpot:svg-import" #js {:penpot:svg-attrs (when-not (empty? svg-attrs) svg-attrs)
|
|
:penpot:svg-defs (when-not (empty? svg-defs) svg-defs)
|
|
:penpot:svg-transform (when svg-transform (str svg-transform))
|
|
:penpot:svg-viewbox-x (get-in shape [:svg-viewbox :x])
|
|
:penpot:svg-viewbox-y (get-in shape [:svg-viewbox :y])
|
|
:penpot:svg-viewbox-width (get-in shape [:svg-viewbox :width])
|
|
:penpot:svg-viewbox-height (get-in shape [:svg-viewbox :height])}
|
|
(for [[def-id def-xml] (:svg-defs shape)]
|
|
[:> "penpot:svg-def" #js {:def-id def-id}
|
|
[:& render-xml {:xml def-xml}]])]))
|
|
|
|
(when (= (:type shape) :svg-raw)
|
|
(let [props (-> (obj/new)
|
|
(obj/set! "penpot:x" (:x shape))
|
|
(obj/set! "penpot:y" (:y shape))
|
|
(obj/set! "penpot:width" (:width shape))
|
|
(obj/set! "penpot:height" (:height shape))
|
|
(obj/set! "penpot:tag" (-> (get-in shape [:content :tag]) d/name))
|
|
(obj/merge! (-> (get-in shape [:content :attrs])
|
|
(clj->js))))]
|
|
[:> "penpot:svg-content" props
|
|
(for [leaf (->> shape :content :content (filter string?))]
|
|
[:> "penpot:svg-child" {} leaf])]))]))
|
|
|