mirror of
https://github.com/penpot/penpot.git
synced 2025-03-12 07:41:43 -05:00
✨ Adds flip,proportion and rotation
This commit is contained in:
parent
a106c728ba
commit
d6e009ce78
7 changed files with 189 additions and 40 deletions
|
@ -87,15 +87,15 @@
|
|||
:changes []})))
|
||||
|
||||
(defn add-page
|
||||
[file name]
|
||||
(let [page-id (uuid/next)]
|
||||
[file data]
|
||||
(let [page-id (uuid/next)
|
||||
page (-> init/empty-page-data
|
||||
(assoc :id page-id)
|
||||
(d/deep-merge data))]
|
||||
(-> file
|
||||
(commit-change
|
||||
{:type :add-page
|
||||
:id page-id
|
||||
:name name
|
||||
:page (-> init/empty-page-data
|
||||
(assoc :name name))})
|
||||
:page page})
|
||||
|
||||
;; Current page being edited
|
||||
(assoc :current-page-id page-id)
|
||||
|
|
|
@ -7,14 +7,65 @@
|
|||
(ns app.libs.file-builder
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.file-builder :as fb]))
|
||||
[app.common.file-builder :as fb]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(defn parse-data [data]
|
||||
(as-> data $
|
||||
(js->clj $ :keywordize-keys true)
|
||||
;; Transforms camelCase to kebab-case
|
||||
(d/deep-mapm
|
||||
(fn [[k v]]
|
||||
[(-> k d/name str/kebab keyword) v]) $)))
|
||||
|
||||
(deftype File [^:mutable file]
|
||||
Object
|
||||
(addPage [self name]
|
||||
(set! file (fb/add-page file name))
|
||||
(str (:current-page-id file))))
|
||||
|
||||
(addPage
|
||||
([self name]
|
||||
(addPage self name nil))
|
||||
|
||||
([self name options]
|
||||
(set! file (fb/add-page file {:name name :options options}))
|
||||
(str (:current-page-id file))))
|
||||
|
||||
(closePage [self]
|
||||
(set! file (fb/close-page file)))
|
||||
|
||||
(addArtboard [self data]
|
||||
(set! file (fb/add-artboard file (parse-data data)))
|
||||
(str (:last-id file)))
|
||||
|
||||
(closeArtboard [self data]
|
||||
(set! file (fb/close-artboard file)))
|
||||
|
||||
(addGroup [self data]
|
||||
(set! file (fb/add-group file (parse-data data)))
|
||||
(str (:last-id file)))
|
||||
|
||||
(closeGroup [self]
|
||||
(set! file (fb/close-group file)))
|
||||
|
||||
(createRect [self data]
|
||||
(set! file (fb/create-rect file (parse-data data))))
|
||||
|
||||
(createCircle [self data]
|
||||
(set! file (fb/create-circle file (parse-data data))))
|
||||
|
||||
(createPath [self data]
|
||||
(set! file (fb/create-path file (parse-data data))))
|
||||
|
||||
(createText [self data]
|
||||
(set! file (fb/create-text file (parse-data data))))
|
||||
|
||||
(createImage [self data]
|
||||
(set! file (fb/create-image file (parse-data data))))
|
||||
|
||||
(createSVG [self data]
|
||||
(set! file (fb/create-svg-raw file (parse-data data))))
|
||||
|
||||
(closeSVG [self]
|
||||
(set! file (fb/close-svg-raw file))))
|
||||
|
||||
(defn create-file-export [^string name]
|
||||
(File. (fb/create-file name)))
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
[app.common.uuid :as uuid]
|
||||
[app.main.ui.shapes.circle :as circle]
|
||||
[app.main.ui.shapes.embed :as embed]
|
||||
[app.main.ui.shapes.export :as use]
|
||||
[app.main.ui.shapes.filters :as filters]
|
||||
[app.main.ui.shapes.frame :as frame]
|
||||
[app.main.ui.shapes.group :as group]
|
||||
|
@ -158,6 +159,9 @@
|
|||
:style {:width "100%"
|
||||
:height "100%"
|
||||
:background background-color}}
|
||||
|
||||
[:& use/export-page {:options (:options data)}]
|
||||
|
||||
(for [item shapes]
|
||||
(let [frame? (= (:type item) :frame)]
|
||||
(cond
|
||||
|
|
|
@ -83,6 +83,37 @@
|
|||
(cond-> mask?
|
||||
(obj/set! "penpot:masked-group" "true"))))))
|
||||
|
||||
(defn prefix-keys [m]
|
||||
(letfn [(prefix-entry [[k v]]
|
||||
[(str "penpot:" (d/name k)) v])]
|
||||
(into {} (map prefix-entry) m)))
|
||||
|
||||
(mf/defc export-grid-data
|
||||
[{:keys [grids]}]
|
||||
[:> "penpot:grids" #js {}
|
||||
(for [{:keys [type display params]} grids]
|
||||
(let [props (->> (d/without-keys params [:color])
|
||||
(prefix-keys)
|
||||
(clj->js))]
|
||||
[:> "penpot:grid"
|
||||
(-> props
|
||||
(obj/set! "penpot:color" (get-in params [:color :color]))
|
||||
(obj/set! "penpot:opacity" (get-in params [:color :opacity]))
|
||||
(obj/set! "penpot:type" (d/name type))
|
||||
(cond-> (some? display)
|
||||
(obj/set! "penpot:display" (str display))))]))])
|
||||
|
||||
(mf/defc export-page
|
||||
[{:keys [options]}]
|
||||
[:> "penpot:page" #js {}
|
||||
(let [saved-grids (get options :saved-grids)]
|
||||
(when-not (empty? saved-grids)
|
||||
(let [parse-grid
|
||||
(fn [[type params]]
|
||||
{:type type :params params})
|
||||
grids (->> saved-grids (mapv parse-grid))]
|
||||
[:& export-grid-data {:grids grids}])))])
|
||||
|
||||
(mf/defc export-data
|
||||
[{:keys [shape]}]
|
||||
(let [props (-> (obj/new)
|
||||
|
@ -135,5 +166,10 @@
|
|||
(clj->js))))]
|
||||
[:> "penpot:svg-content" props
|
||||
(for [leaf (->> shape :content :content (filter string?))]
|
||||
[:> "penpot:svg-child" {} leaf])]))]))
|
||||
[:> "penpot:svg-child" {} leaf])]))
|
||||
|
||||
|
||||
(when (and (= (:type shape) :frame)
|
||||
(not (empty? (:grids shape))))
|
||||
[:& export-grid-data {:grids (:grids shape)}])]))
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[app.main.ui.context :as muc]
|
||||
[app.main.ui.measurements :as msr]
|
||||
[app.main.ui.shapes.embed :as embed]
|
||||
[app.main.ui.shapes.export :as use]
|
||||
[app.main.ui.workspace.shapes :as shapes]
|
||||
[app.main.ui.workspace.shapes.text.editor :as editor]
|
||||
[app.main.ui.workspace.viewport.actions :as actions]
|
||||
|
@ -188,6 +189,8 @@
|
|||
:style {:background-color (get options :background "#E8E9EA")
|
||||
:pointer-events "none"}}
|
||||
|
||||
[:& use/export-page {:options options}]
|
||||
|
||||
[:& (mf/provider embed/context) {:value true}
|
||||
;; Render root shape
|
||||
[:& shapes/root-shape {:key page-id
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
|
||||
(defn get-data
|
||||
([node]
|
||||
(->> node :content (d/seek #(= :penpot:shape (:tag %)))))
|
||||
(->> node :content (d/seek #(or (= :penpot:shape (:tag %))
|
||||
(= :penpot:page (:tag %))))))
|
||||
([node tag]
|
||||
(->> (get-data node)
|
||||
:content
|
||||
|
@ -98,6 +99,41 @@
|
|||
m
|
||||
attrs))
|
||||
|
||||
(defn without-penpot-prefix
|
||||
[m]
|
||||
(let [no-penpot-prefix?
|
||||
(fn [[k v]]
|
||||
(not (str/starts-with? (d/name k) "penpot:")))]
|
||||
(into {} (filter no-penpot-prefix?) m)))
|
||||
|
||||
(defn remove-penpot-prefix
|
||||
[m]
|
||||
(into {}
|
||||
(map (fn [[k v]]
|
||||
(if (str/starts-with? (d/name k) "penpot:")
|
||||
[(-> k d/name (str/replace "penpot:" "") keyword) v]
|
||||
[k v])))
|
||||
m))
|
||||
|
||||
(defn camelize [[k v]]
|
||||
[(-> k d/name str/camel keyword) v])
|
||||
|
||||
(defn camelize-keys
|
||||
[m]
|
||||
(assert (map? m) (str m))
|
||||
|
||||
(into {} (map camelize) m))
|
||||
|
||||
(defn fix-style-attr
|
||||
[m]
|
||||
(let [fix-style
|
||||
(fn [[k v]]
|
||||
(if (= k :style)
|
||||
[k (-> v parse-style camelize-keys)]
|
||||
[k v]))]
|
||||
|
||||
(d/deep-mapm (comp camelize fix-style) m)))
|
||||
|
||||
(def search-data-node? #{:rect :image :path :text :circle})
|
||||
|
||||
(defn get-svg-data
|
||||
|
@ -372,6 +408,26 @@
|
|||
:suffix (get-meta node :suffix)
|
||||
:scale (get-meta node :scale d/parse-double)})
|
||||
|
||||
|
||||
(defn parse-grid-node [node]
|
||||
(let [attrs (-> node :attrs remove-penpot-prefix)
|
||||
color {:color (:color attrs)
|
||||
:opacity (-> attrs :opacity d/parse-double)}
|
||||
|
||||
params (-> (d/without-keys attrs [:color :opacity :display :type])
|
||||
(d/update-when :size d/parse-double)
|
||||
(d/update-when :item-length d/parse-double)
|
||||
(d/update-when :gutter d/parse-double)
|
||||
(d/update-when :margin d/parse-double)
|
||||
(assoc :color color))]
|
||||
{:type (-> attrs :type keyword)
|
||||
:display (-> attrs :display str->bool)
|
||||
:params params}))
|
||||
|
||||
(defn parse-grids [node]
|
||||
(let [grid-node (get-data node :penpot:grids)]
|
||||
(->> grid-node :content (mapv parse-grid-node))))
|
||||
|
||||
(defn extract-from-data
|
||||
([node tag]
|
||||
(extract-from-data node tag identity))
|
||||
|
@ -477,32 +533,6 @@
|
|||
|
||||
props)))
|
||||
|
||||
(defn without-penpot-prefix
|
||||
[m]
|
||||
(let [no-penpot-prefix?
|
||||
(fn [[k v]]
|
||||
(not (str/starts-with? (d/name k) "penpot:")))]
|
||||
(into {} (filter no-penpot-prefix?) m)))
|
||||
|
||||
(defn camelize [[k v]]
|
||||
[(-> k d/name str/camel keyword) v])
|
||||
|
||||
(defn camelize-keys
|
||||
[m]
|
||||
(assert (map? m) (str m))
|
||||
|
||||
(into {} (map camelize) m))
|
||||
|
||||
(defn fix-style-attr
|
||||
[m]
|
||||
(let [fix-style
|
||||
(fn [[k v]]
|
||||
(if (= k :style)
|
||||
[k (-> v parse-style camelize-keys)]
|
||||
[k v]))]
|
||||
|
||||
(d/deep-mapm (comp camelize fix-style) m)))
|
||||
|
||||
(defn add-svg-content
|
||||
[props node]
|
||||
(let [svg-content (get-data node :penpot:svg-content)
|
||||
|
@ -522,6 +552,12 @@
|
|||
:tag tag
|
||||
:content node-content})))
|
||||
|
||||
(defn add-frame-data [props node]
|
||||
(let [grids (parse-grids node)]
|
||||
(cond-> props
|
||||
(not (empty? grids))
|
||||
(assoc :grids grids))))
|
||||
|
||||
(defn get-image-name
|
||||
[node]
|
||||
(get-in node [:attrs :penpot:name]))
|
||||
|
@ -550,6 +586,9 @@
|
|||
(cond-> (= :svg-raw type)
|
||||
(add-svg-content node))
|
||||
|
||||
(cond-> (= :frame type)
|
||||
(add-frame-data node))
|
||||
|
||||
(cond-> (= :group type)
|
||||
(add-group-data node))
|
||||
|
||||
|
@ -561,3 +600,17 @@
|
|||
|
||||
(cond-> (= :text type)
|
||||
(add-text-data node))))))
|
||||
|
||||
(defn parse-page-data
|
||||
[node]
|
||||
(let [style (parse-style (get-in node [:attrs :style]))
|
||||
background (:background style)
|
||||
grids (->> (parse-grids node)
|
||||
(group-by :type)
|
||||
(d/mapm (fn [k v] (-> v first :params))))]
|
||||
(cond-> {}
|
||||
(some? background)
|
||||
(assoc-in [:options :background] background)
|
||||
|
||||
(not (empty? grids))
|
||||
(assoc-in [:options :saved-grids] grids))))
|
||||
|
|
|
@ -137,11 +137,13 @@
|
|||
[file [page-name content]]
|
||||
(if (cip/valid? content)
|
||||
(let [nodes (->> content cip/node-seq)
|
||||
file-id (:id file)]
|
||||
file-id (:id file)
|
||||
page-data (-> (cip/parse-page-data content)
|
||||
(assoc :name page-name))]
|
||||
(->> (rx/from nodes)
|
||||
(rx/filter cip/shape?)
|
||||
(rx/mapcat (partial resolve-images file-id))
|
||||
(rx/reduce add-shape-file (fb/add-page file page-name))
|
||||
(rx/reduce add-shape-file (fb/add-page file page-data))
|
||||
(rx/map fb/close-page)))
|
||||
(rx/empty)))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue