mirror of
https://github.com/penpot/penpot.git
synced 2025-05-29 11:56:10 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
c27d709b6b
27 changed files with 427 additions and 219 deletions
|
@ -23,6 +23,7 @@
|
||||||
- Add actions to go to main component context menu option [Taiga #2053](https://tree.taiga.io/project/penpot/us/2053).
|
- Add actions to go to main component context menu option [Taiga #2053](https://tree.taiga.io/project/penpot/us/2053).
|
||||||
- Add contrast between component select color and shape select color [Taiga #2121](https://tree.taiga.io/project/penpot/issue/2121).
|
- Add contrast between component select color and shape select color [Taiga #2121](https://tree.taiga.io/project/penpot/issue/2121).
|
||||||
- Add animations in interactions [Taiga #2244](https://tree.taiga.io/project/penpot/us/2244).
|
- Add animations in interactions [Taiga #2244](https://tree.taiga.io/project/penpot/us/2244).
|
||||||
|
- Add performance improvements on .penpot file import process [Taiga 2497](https://tree.taiga.io/project/penpot/us/2497).
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
|
@ -69,6 +70,7 @@
|
||||||
- Avoid modifying component when moving into a group [Taiga #2534](https://tree.taiga.io/project/penpot/issue/2534)
|
- Avoid modifying component when moving into a group [Taiga #2534](https://tree.taiga.io/project/penpot/issue/2534)
|
||||||
- Show correctly group types label in handoff [Taiga #2482](https://tree.taiga.io/project/penpot/issue/2482)
|
- Show correctly group types label in handoff [Taiga #2482](https://tree.taiga.io/project/penpot/issue/2482)
|
||||||
- Display view mode buttons always centered in viewer [#Taiga 2466](https://tree.taiga.io/project/penpot/issue/2466)
|
- Display view mode buttons always centered in viewer [#Taiga 2466](https://tree.taiga.io/project/penpot/issue/2466)
|
||||||
|
- Fix default profile image generation issue [Taiga #2601](https://tree.taiga.io/project/penpot/issue/2601)
|
||||||
|
|
||||||
### :arrow_up: Deps updates
|
### :arrow_up: Deps updates
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ export OPTIONS="
|
||||||
-J-Dlog4j2.configurationFile=log4j2-devenv.xml \
|
-J-Dlog4j2.configurationFile=log4j2-devenv.xml \
|
||||||
-J-XX:+UseZGC \
|
-J-XX:+UseZGC \
|
||||||
-J-XX:-OmitStackTraceInFastThrow \
|
-J-XX:-OmitStackTraceInFastThrow \
|
||||||
-J-Xms50m -J-Xmx512m \
|
-J-Xms50m -J-Xmx1024m \
|
||||||
-J-Djdk.attach.allowAttachSelf \
|
-J-Djdk.attach.allowAttachSelf \
|
||||||
-J-XX:+UnlockDiagnosticVMOptions \
|
-J-XX:+UnlockDiagnosticVMOptions \
|
||||||
-J-XX:+DebugNonSafepoints";
|
-J-XX:+DebugNonSafepoints";
|
||||||
|
|
|
@ -414,7 +414,9 @@
|
||||||
[conn project-id]
|
[conn project-id]
|
||||||
(:team-id (db/get-by-id conn :project project-id {:columns [:team-id]})))
|
(:team-id (db/get-by-id conn :project project-id {:columns [:team-id]})))
|
||||||
|
|
||||||
;; TEMPORARY FILE CREATION
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; TEMPORARY FILES (behaves differently)
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(s/def ::create-temp-file ::create-file)
|
(s/def ::create-temp-file ::create-file)
|
||||||
|
|
||||||
|
@ -424,6 +426,23 @@
|
||||||
(proj/check-edition-permissions! conn profile-id project-id)
|
(proj/check-edition-permissions! conn profile-id project-id)
|
||||||
(create-file conn (assoc params :deleted-at (dt/in-future {:days 1})))))
|
(create-file conn (assoc params :deleted-at (dt/in-future {:days 1})))))
|
||||||
|
|
||||||
|
(s/def ::update-temp-file
|
||||||
|
(s/keys :req-un [::changes ::revn ::session-id ::id]))
|
||||||
|
|
||||||
|
(sv/defmethod ::update-temp-file
|
||||||
|
[{:keys [pool] :as cfg} {:keys [profile-id session-id id revn changes] :as params}]
|
||||||
|
(db/with-atomic [conn pool]
|
||||||
|
(db/insert! conn :file-change
|
||||||
|
{:id (uuid/next)
|
||||||
|
:session-id session-id
|
||||||
|
:profile-id profile-id
|
||||||
|
:created-at (dt/now)
|
||||||
|
:file-id id
|
||||||
|
:revn revn
|
||||||
|
:data nil
|
||||||
|
:changes (blob/encode changes)})
|
||||||
|
nil))
|
||||||
|
|
||||||
(s/def ::persist-temp-file
|
(s/def ::persist-temp-file
|
||||||
(s/keys :req-un [::id ::profile-id]))
|
(s/keys :req-un [::id ::profile-id]))
|
||||||
|
|
||||||
|
@ -431,6 +450,25 @@
|
||||||
[{:keys [pool] :as cfg} {:keys [id profile-id] :as params}]
|
[{:keys [pool] :as cfg} {:keys [id profile-id] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
(db/with-atomic [conn pool]
|
||||||
(files/check-edition-permissions! conn profile-id id)
|
(files/check-edition-permissions! conn profile-id id)
|
||||||
(db/update! conn :file
|
(let [file (db/get-by-id conn :file id)
|
||||||
{:deleted-at nil}
|
revs (db/query conn :file-change
|
||||||
{:id id})))
|
{:file-id id}
|
||||||
|
{:order-by [[:revn :asc]]})
|
||||||
|
revn (count revs)]
|
||||||
|
|
||||||
|
(when (nil? (:deleted-at file))
|
||||||
|
(ex/raise :type :validation
|
||||||
|
:code :cant-persist-already-persisted-file))
|
||||||
|
|
||||||
|
(loop [revs (seq revs)
|
||||||
|
data (blob/decode (:data file))]
|
||||||
|
(if-let [rev (first revs)]
|
||||||
|
(recur (rest revs)
|
||||||
|
(->> rev :changes blob/decode (cp/process-changes data)))
|
||||||
|
(db/update! conn :file
|
||||||
|
{:deleted-at nil
|
||||||
|
:revn revn
|
||||||
|
:data (blob/encode data)}
|
||||||
|
{:id id})))
|
||||||
|
|
||||||
|
nil)))
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
(ns app.rpc.queries.files
|
(ns app.rpc.queries.files
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.pages :as cp]
|
||||||
[app.common.pages.migrations :as pmg]
|
[app.common.pages.migrations :as pmg]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
@ -215,8 +217,66 @@
|
||||||
(some-> (retrieve-file cfg id)
|
(some-> (retrieve-file cfg id)
|
||||||
(assoc :permissions perms)))))
|
(assoc :permissions perms)))))
|
||||||
|
|
||||||
(defn remove-thumbnails-frames
|
(declare trim-file-data)
|
||||||
"Removes from data the children for frames that have a thumbnail set up"
|
|
||||||
|
(s/def ::page-id ::us/uuid)
|
||||||
|
(s/def ::object-id ::us/uuid)
|
||||||
|
|
||||||
|
(s/def ::trimmed-file
|
||||||
|
(s/keys :req-un [::profile-id ::id ::object-id ::page-id]))
|
||||||
|
|
||||||
|
(sv/defmethod ::trimmed-file
|
||||||
|
"Retrieve a file by its ID and trims all unnecesary content from
|
||||||
|
it. It is mainly used for rendering a concrete object, so we don't
|
||||||
|
need force download all shapes when only a small subset is
|
||||||
|
necesseary."
|
||||||
|
[{:keys [pool] :as cfg} {:keys [profile-id id] :as params}]
|
||||||
|
(db/with-atomic [conn pool]
|
||||||
|
(let [cfg (assoc cfg :conn conn)
|
||||||
|
perms (get-permissions conn profile-id id)]
|
||||||
|
(check-read-permissions! perms)
|
||||||
|
(some-> (retrieve-file cfg id)
|
||||||
|
(trim-file-data params)
|
||||||
|
(assoc :permissions perms)))))
|
||||||
|
|
||||||
|
(defn- trim-file-data
|
||||||
|
[file {:keys [page-id object-id]}]
|
||||||
|
(let [page (get-in file [:data :pages-index page-id])
|
||||||
|
objects (->> (:objects page)
|
||||||
|
(cp/get-object-with-children object-id)
|
||||||
|
(map #(dissoc % :thumbnail)))
|
||||||
|
|
||||||
|
objects (d/index-by :id objects)
|
||||||
|
page (assoc page :objects objects)]
|
||||||
|
|
||||||
|
(-> file
|
||||||
|
(update :data assoc :pages-index {page-id page})
|
||||||
|
(assoc :pages [page-id]))))
|
||||||
|
|
||||||
|
(declare strip-frames-with-thumbnails)
|
||||||
|
|
||||||
|
(s/def ::strip-frames-with-thumbnails ::us/boolean)
|
||||||
|
|
||||||
|
(s/def ::page
|
||||||
|
(s/keys :req-un [::profile-id ::file-id]
|
||||||
|
:opt-un [::strip-frames-with-thumbnails]))
|
||||||
|
|
||||||
|
(sv/defmethod ::page
|
||||||
|
"Retrieves the first page of the file. Used mainly for render
|
||||||
|
thumbnails on dashboard."
|
||||||
|
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as props}]
|
||||||
|
(db/with-atomic [conn pool]
|
||||||
|
(check-read-permissions! conn profile-id file-id)
|
||||||
|
|
||||||
|
(let [cfg (assoc cfg :conn conn)
|
||||||
|
file (retrieve-file cfg file-id)
|
||||||
|
page-id (get-in file [:data :pages 0])]
|
||||||
|
(cond-> (get-in file [:data :pages-index page-id])
|
||||||
|
(true? (:strip-frames-with-thumbnails props))
|
||||||
|
(strip-frames-with-thumbnails)))))
|
||||||
|
|
||||||
|
(defn strip-frames-with-thumbnails
|
||||||
|
"Remove unnecesary shapes from frames that have thumbnail."
|
||||||
[data]
|
[data]
|
||||||
(let [filter-shape?
|
(let [filter-shape?
|
||||||
(fn [objects [id shape]]
|
(fn [objects [id shape]]
|
||||||
|
@ -242,22 +302,6 @@
|
||||||
|
|
||||||
(update data :objects update-objects)))
|
(update data :objects update-objects)))
|
||||||
|
|
||||||
(s/def ::page
|
|
||||||
(s/keys :req-un [::profile-id ::file-id]))
|
|
||||||
|
|
||||||
(sv/defmethod ::page
|
|
||||||
"Retrieves the first page of the file. Used mainly for render
|
|
||||||
thumbnails on dashboard."
|
|
||||||
[{:keys [pool] :as cfg} {:keys [profile-id file-id strip-thumbnails]}]
|
|
||||||
(db/with-atomic [conn pool]
|
|
||||||
(check-read-permissions! conn profile-id file-id)
|
|
||||||
|
|
||||||
(let [cfg (assoc cfg :conn conn)
|
|
||||||
file (retrieve-file cfg file-id)
|
|
||||||
page-id (get-in file [:data :pages 0])]
|
|
||||||
(cond-> (get-in file [:data :pages-index page-id])
|
|
||||||
strip-thumbnails
|
|
||||||
(remove-thumbnails-frames)))))
|
|
||||||
|
|
||||||
;; --- Query: Shared Library Files
|
;; --- Query: Shared Library Files
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
|
|
||||||
(ns app.common.geom.align
|
(ns app.common.geom.align
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.pages.helpers :refer [get-children]]
|
||||||
[clojure.spec.alpha :as s]))
|
[clojure.spec.alpha :as s]))
|
||||||
|
|
||||||
;; --- Alignment
|
;; --- Alignment
|
||||||
|
@ -15,23 +17,13 @@
|
||||||
|
|
||||||
(declare calc-align-pos)
|
(declare calc-align-pos)
|
||||||
|
|
||||||
;; TODO: revisit on how to reuse code and dont have this function
|
|
||||||
;; duplicated because the implementation right now differs from the
|
|
||||||
;; original function.
|
|
||||||
|
|
||||||
;; Duplicated from pages/helpers to remove cyclic dependencies
|
|
||||||
(defn- get-children [id objects]
|
|
||||||
(let [shapes (vec (get-in objects [id :shapes]))]
|
|
||||||
(if shapes
|
|
||||||
(into shapes (mapcat #(get-children % objects)) shapes)
|
|
||||||
[])))
|
|
||||||
|
|
||||||
(defn- recursive-move
|
(defn- recursive-move
|
||||||
"Move the shape and all its recursive children."
|
"Move the shape and all its recursive children."
|
||||||
[shape dpoint objects]
|
[shape dpoint objects]
|
||||||
(let [children-ids (get-children (:id shape) objects)
|
(->> (get-children (:id shape) objects)
|
||||||
children (map #(get objects %) children-ids)]
|
(map (d/getf objects))
|
||||||
(map #(gsh/move % dpoint) (cons shape children))))
|
(cons shape)
|
||||||
|
(map #(gsh/move % dpoint))))
|
||||||
|
|
||||||
(defn align-to-rect
|
(defn align-to-rect
|
||||||
"Move the shape so that it is aligned with the given rectangle
|
"Move the shape so that it is aligned with the given rectangle
|
||||||
|
|
|
@ -412,7 +412,7 @@
|
||||||
{:rotation angle
|
{:rotation angle
|
||||||
:displacement displacement}))
|
:displacement displacement}))
|
||||||
|
|
||||||
(defn merge-modifiers*
|
(defn merge-modifiers
|
||||||
[objects modifiers]
|
[objects modifiers]
|
||||||
|
|
||||||
(let [set-modifier
|
(let [set-modifier
|
||||||
|
@ -422,8 +422,6 @@
|
||||||
(->> modifiers
|
(->> modifiers
|
||||||
(reduce set-modifier objects))))
|
(reduce set-modifier objects))))
|
||||||
|
|
||||||
(def merge-modifiers (memoize merge-modifiers*))
|
|
||||||
|
|
||||||
(defn modifiers->transform
|
(defn modifiers->transform
|
||||||
([modifiers]
|
([modifiers]
|
||||||
(modifiers->transform nil modifiers))
|
(modifiers->transform nil modifiers))
|
||||||
|
|
|
@ -168,7 +168,7 @@
|
||||||
`(write-log! ~(or logger (str *ns*))
|
`(write-log! ~(or logger (str *ns*))
|
||||||
~level
|
~level
|
||||||
~cause
|
~cause
|
||||||
~(dissoc props :level :cause ::logger ::raw))
|
(or ~raw ~(dissoc props :level :cause ::logger ::raw)))
|
||||||
(let [props (dissoc props :level :cause ::logger ::async ::raw)
|
(let [props (dissoc props :level :cause ::logger ::async ::raw)
|
||||||
logger (or logger (str *ns*))
|
logger (or logger (str *ns*))
|
||||||
logger-sym (gensym "log")
|
logger-sym (gensym "log")
|
||||||
|
|
|
@ -99,37 +99,10 @@
|
||||||
[component]
|
[component]
|
||||||
(get-in component [:objects (:id component)]))
|
(get-in component [:objects (:id component)]))
|
||||||
|
|
||||||
;; Implemented with transient for performance
|
(defn get-children [id objects]
|
||||||
(defn get-children*
|
(if-let [shapes (-> (get objects id) :shapes (some-> vec))]
|
||||||
"Retrieve all children ids recursively for a given object. The
|
(into shapes (mapcat #(get-children % objects)) shapes)
|
||||||
children's order will be breadth first."
|
[]))
|
||||||
[id objects]
|
|
||||||
(loop [result (transient [])
|
|
||||||
pending (transient [])
|
|
||||||
next id]
|
|
||||||
(let [children (get-in objects [next :shapes] [])
|
|
||||||
[result pending]
|
|
||||||
;; Iterate through children and add them to the result
|
|
||||||
;; also add them in pending to check for their children
|
|
||||||
(loop [result result
|
|
||||||
pending pending
|
|
||||||
current (first children)
|
|
||||||
children (rest children)]
|
|
||||||
(if current
|
|
||||||
(recur (conj! result current)
|
|
||||||
(conj! pending current)
|
|
||||||
(first children)
|
|
||||||
(rest children))
|
|
||||||
[result pending]))
|
|
||||||
|
|
||||||
;; If we have still pending, advance the iterator
|
|
||||||
length (count pending)]
|
|
||||||
(if (pos? length)
|
|
||||||
(let [next (get pending (dec length))]
|
|
||||||
(recur result (pop! pending) next))
|
|
||||||
(persistent! result)))))
|
|
||||||
|
|
||||||
(def get-children (memoize get-children*))
|
|
||||||
|
|
||||||
(defn get-children-objects
|
(defn get-children-objects
|
||||||
"Retrieve all children objects recursively for a given object"
|
"Retrieve all children objects recursively for a given object"
|
||||||
|
@ -175,7 +148,7 @@
|
||||||
shape
|
shape
|
||||||
(get objects (:frame-id shape))))
|
(get objects (:frame-id shape))))
|
||||||
|
|
||||||
(defn clean-loops*
|
(defn clean-loops
|
||||||
"Clean a list of ids from circular references."
|
"Clean a list of ids from circular references."
|
||||||
[objects ids]
|
[objects ids]
|
||||||
|
|
||||||
|
@ -192,8 +165,6 @@
|
||||||
|
|
||||||
(reduce add-element (d/ordered-set) ids)))
|
(reduce add-element (d/ordered-set) ids)))
|
||||||
|
|
||||||
(def clean-loops (memoize clean-loops*))
|
|
||||||
|
|
||||||
(defn calculate-invalid-targets
|
(defn calculate-invalid-targets
|
||||||
[shape-id objects]
|
[shape-id objects]
|
||||||
(let [result #{shape-id}
|
(let [result #{shape-id}
|
||||||
|
|
|
@ -2,17 +2,21 @@
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
|
CURRENT_VERSION=$1;
|
||||||
|
|
||||||
yarn install
|
yarn install
|
||||||
rm -rf target
|
rm -rf target
|
||||||
|
|
||||||
export NODE_ENV=production;
|
export NODE_ENV=production;
|
||||||
|
|
||||||
# Build the application
|
# Build the application
|
||||||
clojure -M:dev:shadow-cljs release main
|
clojure -M:dev:shadow-cljs release main;
|
||||||
|
|
||||||
# Remove source
|
# Remove source
|
||||||
rm -rf target/app
|
rm -rf target/app;
|
||||||
|
|
||||||
# Copy package*.json files
|
# Copy package*.json files
|
||||||
cp yarn.lock target/
|
cp yarn.lock target/;
|
||||||
cp package.json target/
|
cp package.json target/;
|
||||||
|
|
||||||
|
sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./target/app.js;
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as l]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
|
[app.util.object :as obj]
|
||||||
[promesa.core :as p]))
|
[promesa.core :as p]))
|
||||||
|
|
||||||
|
|
||||||
(l/set-level! :trace)
|
(l/set-level! :trace)
|
||||||
|
|
||||||
;; --- BROWSER API
|
;; --- BROWSER API
|
||||||
|
@ -35,7 +35,8 @@
|
||||||
[page {:keys [timeout cookie user-agent viewport]}]
|
[page {:keys [timeout cookie user-agent viewport]}]
|
||||||
(let [timeout (or timeout default-timeout)
|
(let [timeout (or timeout default-timeout)
|
||||||
user-agent (or user-agent default-user-agent)
|
user-agent (or user-agent default-user-agent)
|
||||||
viewport (d/merge default-viewport viewport)]
|
viewport (merge default-viewport viewport)]
|
||||||
|
|
||||||
(p/do!
|
(p/do!
|
||||||
(.setViewport ^js page #js {:width (:width viewport)
|
(.setViewport ^js page #js {:width (:width viewport)
|
||||||
:height (:height viewport)
|
:height (:height viewport)
|
||||||
|
@ -63,29 +64,27 @@
|
||||||
(defn screenshot
|
(defn screenshot
|
||||||
([frame] (screenshot frame nil))
|
([frame] (screenshot frame nil))
|
||||||
([frame {:keys [full-page? omit-background? type]
|
([frame {:keys [full-page? omit-background? type]
|
||||||
:or {full-page? false
|
:or {type "png"
|
||||||
type "png"
|
full-page? false
|
||||||
omit-background? false}}]
|
omit-background? false}}]
|
||||||
(.screenshot ^js frame #js {:fullPage full-page?
|
(let [options (-> (obj/new)
|
||||||
:type (name type)
|
(obj/set! "type" (name type))
|
||||||
:omitBackground omit-background?})))
|
(obj/set! "omitBackground" omit-background?)
|
||||||
|
(cond-> full-page? (-> (obj/set! "fullPage" true)
|
||||||
|
(obj/set! "clip" nil))))]
|
||||||
|
(.screenshot ^js frame options))))
|
||||||
|
|
||||||
(defn pdf
|
(defn pdf
|
||||||
([page] (pdf page nil))
|
([page] (pdf page nil))
|
||||||
([page {:keys [viewport omit-background? prefer-css-page-size? save-path]
|
([page {:keys [viewport save-path]}]
|
||||||
:or {viewport {}
|
(p/let [viewport (d/merge default-viewport viewport)]
|
||||||
omit-background? true
|
(.emulateMediaType ^js page "screen")
|
||||||
prefer-css-page-size? true
|
|
||||||
save-path nil}}]
|
|
||||||
(let [viewport (d/merge default-viewport viewport)]
|
|
||||||
(.pdf ^js page #js {:path save-path
|
(.pdf ^js page #js {:path save-path
|
||||||
:width (:width viewport)
|
:width (:width viewport)
|
||||||
:height (:height viewport)
|
:height (:height viewport)
|
||||||
:scale (:scale viewport)
|
:scale (:scale viewport)
|
||||||
:omitBackground omit-background?
|
:printBackground true
|
||||||
:printBackground (not omit-background?)
|
:preferCSSPageSize true}))))
|
||||||
:preferCSSPageSize prefer-css-page-size?}))))
|
|
||||||
|
|
||||||
(defn eval!
|
(defn eval!
|
||||||
[frame f]
|
[frame f]
|
||||||
(.evaluate ^js frame f))
|
(.evaluate ^js frame f))
|
||||||
|
@ -104,10 +103,17 @@
|
||||||
(defonce pool (atom nil))
|
(defonce pool (atom nil))
|
||||||
(defonce pool-browser-id (atom 1))
|
(defonce pool-browser-id (atom 1))
|
||||||
|
|
||||||
|
(def default-chrome-args
|
||||||
|
#js ["--no-sandbox"
|
||||||
|
"--font-render-hinting=none"
|
||||||
|
"--disable-setuid-sandbox"
|
||||||
|
"--disable-accelerated-2d-canvas"
|
||||||
|
"--disable-gpu"])
|
||||||
|
|
||||||
(def browser-pool-factory
|
(def browser-pool-factory
|
||||||
(letfn [(create []
|
(letfn [(create []
|
||||||
(let [path (cf/get :browser-executable-path "/usr/bin/google-chrome")]
|
(let [path (cf/get :browser-executable-path "/usr/bin/google-chrome")]
|
||||||
(-> (pp/launch #js {:executablePath path :args #js ["--no-sandbox" "--font-render-hinting=none"]})
|
(-> (pp/launch #js {:executablePath path :args default-chrome-args})
|
||||||
(p/then (fn [browser]
|
(p/then (fn [browser]
|
||||||
(let [id (deref pool-browser-id)]
|
(let [id (deref pool-browser-id)]
|
||||||
(l/info :origin "factory" :action "create" :browser-id id)
|
(l/info :origin "factory" :action "create" :browser-id id)
|
||||||
|
|
|
@ -71,9 +71,7 @@
|
||||||
(atom (prepare-config)))
|
(atom (prepare-config)))
|
||||||
|
|
||||||
(def version
|
(def version
|
||||||
(atom (v/parse (or (some-> (ex/ignoring (fs/readFileSync "version.txt"))
|
(atom (v/parse "%version%")))
|
||||||
(str/trim))
|
|
||||||
"%version%"))))
|
|
||||||
|
|
||||||
(defn get
|
(defn get
|
||||||
"A configuration getter."
|
"A configuration getter."
|
||||||
|
|
|
@ -31,20 +31,26 @@
|
||||||
(let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
(let [path (str "/render-object/" file-id "/" page-id "/" object-id)
|
||||||
uri (-> (u/uri (cf/get :public-uri))
|
uri (-> (u/uri (cf/get :public-uri))
|
||||||
(assoc :path "/")
|
(assoc :path "/")
|
||||||
|
(assoc :query "essential=t")
|
||||||
(assoc :fragment path))
|
(assoc :fragment path))
|
||||||
|
|
||||||
cookie (create-cookie uri token)]
|
cookie (create-cookie uri token)]
|
||||||
(pdf-from page (str uri) cookie)))
|
(pdf-from page (str uri) cookie)))
|
||||||
|
|
||||||
(pdf-from [page uri cookie]
|
(pdf-from [page uri cookie]
|
||||||
(l/info :uri uri)
|
(l/info :uri uri)
|
||||||
(let [options {:cookie cookie}]
|
(p/let [options {:cookie cookie}]
|
||||||
(p/do!
|
(bw/configure-page! page options)
|
||||||
(bw/configure-page! page options)
|
(bw/navigate! page uri)
|
||||||
(bw/navigate! page uri)
|
(bw/wait-for page "#screenshot")
|
||||||
(bw/wait-for page "#screenshot")
|
;; taking png screenshot before pdf, helps to make the
|
||||||
(if save-path
|
;; pdf rendering works as expected.
|
||||||
(bw/pdf page {:save-path save-path})
|
(p/let [dom (bw/select page "#screenshot")]
|
||||||
(bw/pdf page)))))]
|
(bw/screenshot dom {:full-page? true}))
|
||||||
|
|
||||||
|
(if save-path
|
||||||
|
(bw/pdf page {:save-path save-path})
|
||||||
|
(bw/pdf page))))]
|
||||||
|
|
||||||
(bw/exec! handle)))
|
(bw/exec! handle)))
|
||||||
|
|
||||||
|
|
86
exporter/src/app/util/object.cljs
Normal file
86
exporter/src/app/util/object.cljs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
;; 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.util.object
|
||||||
|
"A collection of helpers for work with javascript objects."
|
||||||
|
(:refer-clojure :exclude [set! get get-in merge clone contains?])
|
||||||
|
(:require
|
||||||
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
|
(defn new [] #js {})
|
||||||
|
|
||||||
|
(defn get
|
||||||
|
([obj k]
|
||||||
|
(when-not (nil? obj)
|
||||||
|
(unchecked-get obj k)))
|
||||||
|
([obj k default]
|
||||||
|
(let [result (get obj k)]
|
||||||
|
(if (undefined? result) default result))))
|
||||||
|
|
||||||
|
(defn contains?
|
||||||
|
[obj k]
|
||||||
|
(some? (unchecked-get obj k)))
|
||||||
|
|
||||||
|
(defn get-keys
|
||||||
|
[obj]
|
||||||
|
(js/Object.keys ^js obj))
|
||||||
|
|
||||||
|
(defn get-in
|
||||||
|
([obj keys]
|
||||||
|
(get-in obj keys nil))
|
||||||
|
|
||||||
|
([obj keys default]
|
||||||
|
(loop [key (first keys)
|
||||||
|
keys (rest keys)
|
||||||
|
res obj]
|
||||||
|
(if (or (nil? key) (nil? res))
|
||||||
|
(or res default)
|
||||||
|
(recur (first keys)
|
||||||
|
(rest keys)
|
||||||
|
(unchecked-get res key))))))
|
||||||
|
|
||||||
|
(defn clone
|
||||||
|
[a]
|
||||||
|
(js/Object.assign #js {} a))
|
||||||
|
|
||||||
|
(defn merge!
|
||||||
|
([a b]
|
||||||
|
(js/Object.assign a b))
|
||||||
|
([a b & more]
|
||||||
|
(reduce merge! (merge! a b) more)))
|
||||||
|
|
||||||
|
(defn merge
|
||||||
|
([a b]
|
||||||
|
(js/Object.assign #js {} a b))
|
||||||
|
([a b & more]
|
||||||
|
(reduce merge! (merge a b) more)))
|
||||||
|
|
||||||
|
(defn set!
|
||||||
|
[obj key value]
|
||||||
|
(unchecked-set obj key value)
|
||||||
|
obj)
|
||||||
|
|
||||||
|
(defn update!
|
||||||
|
[obj key f & args]
|
||||||
|
(let [found (get obj key ::not-found)]
|
||||||
|
(if-not (identical? ::not-found found)
|
||||||
|
(do (unchecked-set obj key (apply f found args))
|
||||||
|
obj)
|
||||||
|
obj)))
|
||||||
|
|
||||||
|
(defn- props-key-fn
|
||||||
|
[key]
|
||||||
|
(if (or (= key :class) (= key :class-name))
|
||||||
|
"className"
|
||||||
|
(str/camel (name key))))
|
||||||
|
|
||||||
|
(defn clj->props
|
||||||
|
[props]
|
||||||
|
(clj->js props :keyword-fn props-key-fn))
|
||||||
|
|
||||||
|
(defn ^boolean in?
|
||||||
|
[obj prop]
|
||||||
|
(js* "~{} in ~{}" prop obj))
|
|
@ -20,9 +20,11 @@
|
||||||
[app.main.ui.routes :as rt]
|
[app.main.ui.routes :as rt]
|
||||||
[app.main.worker :as worker]
|
[app.main.worker :as worker]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
[app.util.globals :as glob]
|
||||||
[app.util.i18n :as i18n]
|
[app.util.i18n :as i18n]
|
||||||
[app.util.theme :as theme]
|
[app.util.theme :as theme]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
|
[cuerdas.core :as str]
|
||||||
[debug]
|
[debug]
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
@ -58,12 +60,18 @@
|
||||||
(rx/take 1)
|
(rx/take 1)
|
||||||
(rx/map #(rt/init-routes)))))))
|
(rx/map #(rt/init-routes)))))))
|
||||||
|
|
||||||
|
(def essential-only?
|
||||||
|
(let [href (.-href ^js glob/location)]
|
||||||
|
(str/includes? href "essential=t")))
|
||||||
|
|
||||||
(defn ^:export init
|
(defn ^:export init
|
||||||
[]
|
[]
|
||||||
(worker/init!)
|
(when-not essential-only?
|
||||||
(sentry/init!)
|
(worker/init!)
|
||||||
(i18n/init! cf/translations)
|
(sentry/init!)
|
||||||
(theme/init! cf/themes)
|
(i18n/init! cf/translations)
|
||||||
|
(theme/init! cf/themes))
|
||||||
|
|
||||||
(init-ui)
|
(init-ui)
|
||||||
(st/emit! (initialize)))
|
(st/emit! (initialize)))
|
||||||
|
|
||||||
|
|
|
@ -101,10 +101,12 @@
|
||||||
bool-shape (bool/bool-shape shape-wrapper)]
|
bool-shape (bool/bool-shape shape-wrapper)]
|
||||||
(mf/fnc bool-wrapper
|
(mf/fnc bool-wrapper
|
||||||
[{:keys [shape] :as props}]
|
[{:keys [shape] :as props}]
|
||||||
(let [childs (->> (cp/get-children (:id shape) objects)
|
(let [childs (mf/use-memo
|
||||||
(select-keys objects))]
|
(mf/deps (:id shape) objects)
|
||||||
[:& bool-shape {:shape shape
|
(fn []
|
||||||
:childs childs}]))))
|
(->> (cp/get-children (:id shape) objects)
|
||||||
|
(select-keys objects))))]
|
||||||
|
[:& bool-shape {:shape shape :childs childs}]))))
|
||||||
|
|
||||||
(defn svg-raw-wrapper-factory
|
(defn svg-raw-wrapper-factory
|
||||||
[objects]
|
[objects]
|
||||||
|
@ -221,26 +223,39 @@
|
||||||
(mf/defc frame-svg
|
(mf/defc frame-svg
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [objects frame zoom] :or {zoom 1} :as props}]
|
[{:keys [objects frame zoom] :or {zoom 1} :as props}]
|
||||||
(let [modifier (-> (gpt/point (:x frame) (:y frame))
|
(let [frame-id (:id frame)
|
||||||
(gpt/negate)
|
|
||||||
(gmt/translate-matrix))
|
|
||||||
|
|
||||||
frame-id (:id frame)
|
|
||||||
|
|
||||||
include-metadata? (mf/use-ctx export/include-metadata-ctx)
|
include-metadata? (mf/use-ctx export/include-metadata-ctx)
|
||||||
|
|
||||||
modifier-ids (concat [frame-id] (cp/get-children frame-id objects))
|
modifier
|
||||||
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)
|
(mf/use-memo
|
||||||
objects (reduce update-fn objects modifier-ids)
|
(mf/deps (:x frame) (:y frame))
|
||||||
frame (assoc-in frame [:modifiers :displacement] modifier)
|
(fn []
|
||||||
|
(-> (gpt/point (:x frame) (:y frame))
|
||||||
|
(gpt/negate)
|
||||||
|
(gmt/translate-matrix))))
|
||||||
|
|
||||||
|
objects
|
||||||
|
(mf/use-memo
|
||||||
|
(mf/deps frame-id objects modifier)
|
||||||
|
(fn []
|
||||||
|
(let [update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)]
|
||||||
|
(->> (cp/get-children frame-id objects)
|
||||||
|
(into [frame-id])
|
||||||
|
(reduce update-fn objects)))))
|
||||||
|
|
||||||
|
frame
|
||||||
|
(mf/use-memo
|
||||||
|
(mf/deps modifier)
|
||||||
|
(fn [] (assoc-in frame [:modifiers :displacement] modifier)))
|
||||||
|
|
||||||
|
wrapper
|
||||||
|
(mf/use-memo
|
||||||
|
(mf/deps objects)
|
||||||
|
(fn [] (frame-wrapper-factory objects)))
|
||||||
|
|
||||||
width (* (:width frame) zoom)
|
width (* (:width frame) zoom)
|
||||||
height (* (:height frame) zoom)
|
height (* (:height frame) zoom)
|
||||||
vbox (format-viewbox {:width (:width frame 0) :height (:height frame 0)})
|
vbox (format-viewbox {:width (:width frame 0) :height (:height frame 0)})]
|
||||||
|
|
||||||
wrapper (mf/use-memo
|
|
||||||
(mf/deps objects)
|
|
||||||
#(frame-wrapper-factory objects))]
|
|
||||||
|
|
||||||
[:svg {:view-box vbox
|
[:svg {:view-box vbox
|
||||||
:width (ust/format-precision width viewbox-decimal-precision)
|
:width (ust/format-precision width viewbox-decimal-precision)
|
||||||
|
@ -254,19 +269,25 @@
|
||||||
(mf/defc component-svg
|
(mf/defc component-svg
|
||||||
{::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
|
{::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
|
||||||
[{:keys [objects group zoom] :or {zoom 1} :as props}]
|
[{:keys [objects group zoom] :or {zoom 1} :as props}]
|
||||||
(let [modifier (-> (gpt/point (:x group) (:y group))
|
(let [group-id (:id group)
|
||||||
(gpt/negate)
|
|
||||||
(gmt/translate-matrix))
|
|
||||||
|
|
||||||
group-id (:id group)
|
|
||||||
|
|
||||||
include-metadata? (mf/use-ctx export/include-metadata-ctx)
|
include-metadata? (mf/use-ctx export/include-metadata-ctx)
|
||||||
|
|
||||||
modifier-ids (concat [group-id] (cp/get-children group-id objects))
|
modifier
|
||||||
|
(mf/use-memo
|
||||||
|
(mf/deps (:x group) (:y group))
|
||||||
|
(fn []
|
||||||
|
(-> (gpt/point (:x group) (:y group))
|
||||||
|
(gpt/negate)
|
||||||
|
(gmt/translate-matrix))))
|
||||||
|
|
||||||
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)
|
objects
|
||||||
modifiers (reduce update-fn {} modifier-ids)
|
(mf/use-memo
|
||||||
objects (gsh/merge-modifiers objects modifiers)
|
(mf/deps modifier objects group-id)
|
||||||
|
(fn []
|
||||||
|
(let [modifier-ids (concat [group-id] (cp/get-children group-id objects))
|
||||||
|
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)
|
||||||
|
modifiers (reduce update-fn {} modifier-ids)]
|
||||||
|
(gsh/merge-modifiers objects modifiers))))
|
||||||
|
|
||||||
group (get objects group-id)
|
group (get objects group-id)
|
||||||
width (* (:width group) zoom)
|
width (* (:width group) zoom)
|
||||||
|
@ -276,7 +297,7 @@
|
||||||
group-wrapper
|
group-wrapper
|
||||||
(mf/use-memo
|
(mf/use-memo
|
||||||
(mf/deps objects)
|
(mf/deps objects)
|
||||||
#(group-wrapper-factory objects))]
|
(fn [] (group-wrapper-factory objects)))]
|
||||||
|
|
||||||
[:svg {:view-box vbox
|
[:svg {:view-box vbox
|
||||||
:width (ust/format-precision width viewbox-decimal-precision)
|
:width (ust/format-precision width viewbox-decimal-precision)
|
||||||
|
@ -285,31 +306,51 @@
|
||||||
:xmlns "http://www.w3.org/2000/svg"
|
:xmlns "http://www.w3.org/2000/svg"
|
||||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||||
:xmlns:penpot (when include-metadata? "https://penpot.app/xmlns")}
|
:xmlns:penpot (when include-metadata? "https://penpot.app/xmlns")}
|
||||||
|
|
||||||
[:> shape-container {:shape group}
|
[:> shape-container {:shape group}
|
||||||
[:& group-wrapper {:shape group :view-box vbox}]]]))
|
[:& group-wrapper {:shape group :view-box vbox}]]]))
|
||||||
|
|
||||||
(mf/defc component-symbol
|
(mf/defc component-symbol
|
||||||
[{:keys [id data] :as props}]
|
{::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
(let [id (obj/get props "id")
|
||||||
|
data (obj/get props "data")
|
||||||
|
name (:name data)
|
||||||
|
path (:path data)
|
||||||
|
objects (:objects data)
|
||||||
|
root (get objects id)
|
||||||
|
selrect (:selrect root)
|
||||||
|
|
||||||
(let [{:keys [name path objects]} data
|
vbox
|
||||||
root (get objects id)
|
(format-viewbox
|
||||||
|
{:width (:width selrect)
|
||||||
|
:height (:height selrect)})
|
||||||
|
|
||||||
{:keys [width height]} (:selrect root)
|
modifier
|
||||||
vbox (format-viewbox {:width width :height height})
|
(mf/use-memo
|
||||||
|
(mf/deps (:x root) (:y root))
|
||||||
|
(fn []
|
||||||
|
(-> (gpt/point (:x root) (:y root))
|
||||||
|
(gpt/negate)
|
||||||
|
(gmt/translate-matrix))))
|
||||||
|
|
||||||
modifier (-> (gpt/point (:x root) (:y root))
|
objects
|
||||||
(gpt/negate)
|
(mf/use-memo
|
||||||
(gmt/translate-matrix))
|
(mf/deps modifier id objects)
|
||||||
|
(fn []
|
||||||
|
(let [modifier-ids (concat [id] (cp/get-children id objects))
|
||||||
|
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)]
|
||||||
|
(reduce update-fn objects modifier-ids))))
|
||||||
|
|
||||||
modifier-ids (concat [id] (cp/get-children id objects))
|
root
|
||||||
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)
|
(mf/use-memo
|
||||||
objects (reduce update-fn objects modifier-ids)
|
(mf/deps modifier root)
|
||||||
root (assoc-in root [:modifiers :displacement] modifier)
|
(fn [] (assoc-in root [:modifiers :displacement] modifier)))
|
||||||
|
|
||||||
group-wrapper
|
group-wrapper
|
||||||
(mf/use-memo
|
(mf/use-memo
|
||||||
(mf/deps objects)
|
(mf/deps objects)
|
||||||
#(group-wrapper-factory objects))]
|
(fn [] (group-wrapper-factory objects)))]
|
||||||
|
|
||||||
[:> "symbol" #js {:id (str id)
|
[:> "symbol" #js {:id (str id)
|
||||||
:viewBox vbox
|
:viewBox vbox
|
||||||
|
@ -321,10 +362,9 @@
|
||||||
(mf/defc components-sprite-svg
|
(mf/defc components-sprite-svg
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
|
(let [data (obj/get props "data")
|
||||||
(let [data (obj/get props "data")
|
children (obj/get props "children")
|
||||||
children (obj/get props "children")
|
embed? (obj/get props "embed?")
|
||||||
embed? (obj/get props "embed?")
|
|
||||||
include-metadata? (obj/get props "include-metadata?")]
|
include-metadata? (obj/get props "include-metadata?")]
|
||||||
[:& (mf/provider embed/context) {:value embed?}
|
[:& (mf/provider embed/context) {:value embed?}
|
||||||
[:& (mf/provider export/include-metadata-ctx) {:value include-metadata?}
|
[:& (mf/provider export/include-metadata-ctx) {:value include-metadata?}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
(ns app.main.ui.dashboard.export
|
(ns app.main.ui.dashboard.export
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.main.data.events :as ev]
|
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
@ -15,7 +14,6 @@
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :as i18n :refer [tr]]
|
[app.util.i18n :as i18n :refer [tr]]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[potok.core :as ptk]
|
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
(def ^:const options [:all :merge :detach])
|
(def ^:const options [:all :merge :detach])
|
||||||
|
@ -60,10 +58,6 @@
|
||||||
|
|
||||||
start-export
|
start-export
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (ptk/event ::ev/event {::ev/name "export-files"
|
|
||||||
:num-files (count (:files @state))
|
|
||||||
:option @selected-option}))
|
|
||||||
|
|
||||||
(swap! state assoc :status :exporting)
|
(swap! state assoc :status :exporting)
|
||||||
(->> (uw/ask-many!
|
(->> (uw/ask-many!
|
||||||
{:cmd :export-file
|
{:cmd :export-file
|
||||||
|
|
|
@ -162,6 +162,7 @@
|
||||||
(mf/deps files current-team-id)
|
(mf/deps files current-team-id)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(st/emit! (ptk/event ::ev/event {::ev/name "export-files"
|
(st/emit! (ptk/event ::ev/event {::ev/name "export-files"
|
||||||
|
::ev/origin "dashboard"
|
||||||
:num-files (count files)}))
|
:num-files (count files)}))
|
||||||
(->> (rx/from files)
|
(->> (rx/from files)
|
||||||
(rx/flat-map
|
(rx/flat-map
|
||||||
|
|
|
@ -153,7 +153,7 @@
|
||||||
(fn []
|
(fn []
|
||||||
(->> (rx/zip
|
(->> (rx/zip
|
||||||
(repo/query! :font-variants {:file-id file-id})
|
(repo/query! :font-variants {:file-id file-id})
|
||||||
(repo/query! :file {:id file-id}))
|
(repo/query! :trimmed-file {:id file-id :page-id page-id :object-id object-id}))
|
||||||
(rx/subs
|
(rx/subs
|
||||||
(fn [[fonts {:keys [data]}]]
|
(fn [[fonts {:keys [data]}]]
|
||||||
(when (seq fonts)
|
(when (seq fonts)
|
||||||
|
|
|
@ -199,6 +199,18 @@
|
||||||
:penpot:suffix suffix
|
:penpot:suffix suffix
|
||||||
:penpot:scale (str scale)}])))
|
:penpot:scale (str scale)}])))
|
||||||
|
|
||||||
|
(defn str->style
|
||||||
|
[style-str]
|
||||||
|
(if (string? style-str)
|
||||||
|
(->> (str/split style-str ";")
|
||||||
|
(map str/trim)
|
||||||
|
(map #(str/split % ":"))
|
||||||
|
(group-by first)
|
||||||
|
(map (fn [[key val]]
|
||||||
|
(vector (keyword key) (second (first val)))))
|
||||||
|
(into {}))
|
||||||
|
style-str))
|
||||||
|
|
||||||
(defn style->str
|
(defn style->str
|
||||||
[style]
|
[style]
|
||||||
(->> style
|
(->> style
|
||||||
|
@ -229,7 +241,8 @@
|
||||||
[:& render-xml {:xml def-xml}]])]))
|
[:& render-xml {:xml def-xml}]])]))
|
||||||
|
|
||||||
(when (= (:type shape) :svg-raw)
|
(when (= (:type shape) :svg-raw)
|
||||||
(let [props
|
(let [shape (-> shape (d/update-in-when [:content :attrs :style] str->style))
|
||||||
|
props
|
||||||
(-> (obj/new)
|
(-> (obj/new)
|
||||||
(obj/set! "penpot:x" (:x shape))
|
(obj/set! "penpot:x" (:x shape))
|
||||||
(obj/set! "penpot:y" (:y shape))
|
(obj/set! "penpot:y" (:y shape))
|
||||||
|
@ -263,7 +276,6 @@
|
||||||
(mf/defc export-data
|
(mf/defc export-data
|
||||||
[{:keys [shape]}]
|
[{:keys [shape]}]
|
||||||
(let [props (-> (obj/new) (add-data shape) (add-library-refs shape))]
|
(let [props (-> (obj/new) (add-data shape) (add-library-refs shape))]
|
||||||
(js/console.log props)
|
|
||||||
[:> "penpot:shape" props
|
[:> "penpot:shape" props
|
||||||
(export-shadow-data shape)
|
(export-shadow-data shape)
|
||||||
(export-blur-data shape)
|
(export-blur-data shape)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
[app.util.router :as rt]
|
[app.util.router :as rt]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
|
[potok.core :as ptk]
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
;; --- Zoom Widget
|
;; --- Zoom Widget
|
||||||
|
@ -152,6 +154,10 @@
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(mf/deps file team-id)
|
(mf/deps file team-id)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
|
(st/emit! (ptk/event ::ev/event {::ev/name "export-files"
|
||||||
|
::ev/origin "workspace"
|
||||||
|
:num-files 1}))
|
||||||
|
|
||||||
(->> (rx/of file)
|
(->> (rx/of file)
|
||||||
(rx/flat-map
|
(rx/flat-map
|
||||||
(fn [file]
|
(fn [file]
|
||||||
|
@ -251,7 +257,7 @@
|
||||||
(tr "workspace.header.menu.hide-palette")
|
(tr "workspace.header.menu.hide-palette")
|
||||||
(tr "workspace.header.menu.show-palette"))]
|
(tr "workspace.header.menu.show-palette"))]
|
||||||
[:span.shortcut (sc/get-tooltip :toggle-palette)]]
|
[:span.shortcut (sc/get-tooltip :toggle-palette)]]
|
||||||
|
|
||||||
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :display-artboard-names))}
|
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :display-artboard-names))}
|
||||||
[:span
|
[:span
|
||||||
(if (contains? layout :display-artboard-names)
|
(if (contains? layout :display-artboard-names)
|
||||||
|
|
|
@ -96,18 +96,21 @@
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
|
|
||||||
(let [shape (unchecked-get props "shape")
|
(when-let [shape (unchecked-get props "shape")]
|
||||||
objects (unchecked-get props "objects")
|
(let [objects (unchecked-get props "objects")
|
||||||
thumbnail? (unchecked-get props "thumbnail?")
|
thumbnail? (unchecked-get props "thumbnail?")
|
||||||
|
|
||||||
children (-> (mapv (d/getf objects) (:shapes shape))
|
children
|
||||||
(hooks/use-equal-memo))
|
(-> (mapv (d/getf objects) (:shapes shape))
|
||||||
all-children (-> (cp/get-children-objects (:id shape) objects)
|
(hooks/use-equal-memo))
|
||||||
(hooks/use-equal-memo))
|
|
||||||
|
|
||||||
show-thumbnail? (and thumbnail? (some? (:thumbnail shape)))]
|
all-children
|
||||||
|
(-> (cp/get-children-objects (:id shape) objects)
|
||||||
|
(hooks/use-equal-memo))
|
||||||
|
|
||||||
|
show-thumbnail?
|
||||||
|
(and thumbnail? (some? (:thumbnail shape)))]
|
||||||
|
|
||||||
(when (some? shape)
|
|
||||||
[:g.frame-wrapper {:display (when (:hidden shape) "none")}
|
[:g.frame-wrapper {:display (when (:hidden shape) "none")}
|
||||||
[:> shape-container {:shape shape}
|
[:> shape-container {:shape shape}
|
||||||
[:& ff/fontfaces-style {:shapes all-children}]
|
[:& ff/fontfaces-style {:shapes all-children}]
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
(defn on-error
|
(defn on-error
|
||||||
[error]
|
[error]
|
||||||
(js/console.error "Error on worker" error))
|
(js/console.error "Error on worker" (pr-str error)))
|
||||||
|
|
||||||
(defonce instance (atom nil))
|
(defonce instance (atom nil))
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
|
|
||||||
(defn generate*
|
(defn generate*
|
||||||
[{:keys [name color size]
|
[{:keys [name color size]
|
||||||
:or {color "var(--color-black)" size 128}}]
|
:or {color "#000000" size 128}}]
|
||||||
|
|
||||||
(let [parts (str/words (str/upper name))
|
(let [parts (str/words (str/upper name))
|
||||||
letters (if (= 1 (count parts))
|
letters (if (= 1 (count parts))
|
||||||
(ffirst parts)
|
(ffirst parts)
|
||||||
|
@ -27,7 +28,7 @@
|
||||||
|
|
||||||
(obj/set! context "font" (str (/ size 2) "px Arial"))
|
(obj/set! context "font" (str (/ size 2) "px Arial"))
|
||||||
(obj/set! context "textAlign" "center")
|
(obj/set! context "textAlign" "center")
|
||||||
(obj/set! context "fillStyle" "var(--color-white)")
|
(obj/set! context "fillStyle" "#ffffff")
|
||||||
(.fillText context letters (/ size 2) (/ size 1.5))
|
(.fillText context letters (/ size 2) (/ size 1.5))
|
||||||
|
|
||||||
(.toDataURL canvas)))
|
(.toDataURL canvas)))
|
||||||
|
|
|
@ -210,7 +210,8 @@
|
||||||
|
|
||||||
svg-node (if (= :svg tag)
|
svg-node (if (= :svg tag)
|
||||||
(->> node :content last :content last)
|
(->> node :content last :content last)
|
||||||
(->> node :content last))]
|
(->> node :content last))
|
||||||
|
svg-node (d/update-in-when svg-node [:attrs :style] parse-style)]
|
||||||
(merge (add-attrs {} (:attrs svg-node)) node-attrs))
|
(merge (add-attrs {} (:attrs svg-node)) node-attrs))
|
||||||
|
|
||||||
(= type :bool)
|
(= type :bool)
|
||||||
|
@ -633,7 +634,8 @@
|
||||||
(defn add-svg-content
|
(defn add-svg-content
|
||||||
[props node]
|
[props node]
|
||||||
(let [svg-content (get-data node :penpot:svg-content)
|
(let [svg-content (get-data node :penpot:svg-content)
|
||||||
attrs (-> (:attrs svg-content) (without-penpot-prefix))
|
attrs (-> (:attrs svg-content) (without-penpot-prefix)
|
||||||
|
(d/update-when :style parse-style))
|
||||||
tag (-> svg-content :attrs :penpot:tag keyword)
|
tag (-> svg-content :attrs :penpot:tag keyword)
|
||||||
|
|
||||||
node-content
|
node-content
|
||||||
|
@ -641,13 +643,17 @@
|
||||||
(= tag :svg)
|
(= tag :svg)
|
||||||
(->> node :content last :content last :content fix-style-attr)
|
(->> node :content last :content last :content fix-style-attr)
|
||||||
|
|
||||||
(= tag :text)
|
(some? (:content svg-content))
|
||||||
(-> node :content last :content))]
|
(->> (:content svg-content)
|
||||||
(assoc
|
(filter #(= :penpot:svg-child (:tag %)))
|
||||||
props :content
|
(mapv :content)
|
||||||
{:attrs attrs
|
(first)))]
|
||||||
:tag tag
|
(-> props
|
||||||
:content node-content})))
|
(assoc
|
||||||
|
:content
|
||||||
|
{:attrs attrs
|
||||||
|
:tag tag
|
||||||
|
:content node-content}))))
|
||||||
|
|
||||||
(defn add-frame-data [props node]
|
(defn add-frame-data [props node]
|
||||||
(let [grids (parse-grids node)]
|
(let [grids (parse-grids node)]
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
(post {:payload result}))
|
(post {:payload result}))
|
||||||
|
|
||||||
(reply-error [err]
|
(reply-error [err]
|
||||||
(.error js/console "error" err)
|
(.error js/console "error" (pr-str err))
|
||||||
(post {:error {:data (ex-data err)
|
(post {:error {:data (ex-data err)
|
||||||
:message (ex-message err)}}))
|
:message (ex-message err)}}))
|
||||||
|
|
||||||
|
|
|
@ -141,38 +141,30 @@
|
||||||
(rx/map #(hash-map :file-id file-id :library-id %))
|
(rx/map #(hash-map :file-id file-id :library-id %))
|
||||||
(rx/flat-map (partial rp/mutation :link-file-to-library)))))
|
(rx/flat-map (partial rp/mutation :link-file-to-library)))))
|
||||||
|
|
||||||
(defn persist-file [file]
|
|
||||||
(rp/mutation :persist-temp-file {:id (:id file)}))
|
|
||||||
|
|
||||||
(defn send-changes
|
(defn send-changes
|
||||||
"Creates batches of changes to be sent to the backend"
|
"Creates batches of changes to be sent to the backend"
|
||||||
[context file]
|
[context file]
|
||||||
(let [revn (atom (:revn file))
|
(let [file-id (:id file)
|
||||||
file-id (:id file)
|
|
||||||
session-id (uuid/next)
|
session-id (uuid/next)
|
||||||
changes-batches
|
batches (->> (fb/generate-changes file)
|
||||||
(->> (fb/generate-changes file)
|
(partition change-batch-size change-batch-size nil)
|
||||||
(partition change-batch-size change-batch-size nil)
|
(mapv vec))
|
||||||
(mapv vec))
|
|
||||||
|
|
||||||
current (atom 0)
|
processed (atom 0)
|
||||||
total (count changes-batches)]
|
total (count batches)]
|
||||||
|
|
||||||
(rx/concat
|
(rx/concat
|
||||||
(->> (rx/from changes-batches)
|
(->> (rx/from (d/enumerate batches))
|
||||||
(rx/mapcat
|
(rx/merge-map
|
||||||
(fn [change-batch]
|
(fn [[i change-batch]]
|
||||||
(->> (rp/mutation :update-file
|
(->> (rp/mutation :update-temp-file
|
||||||
{:id file-id
|
{:id file-id
|
||||||
:session-id session-id
|
:session-id session-id
|
||||||
:revn @revn
|
:revn i
|
||||||
:changes change-batch})
|
:changes change-batch})
|
||||||
(rx/tap #(do (swap! current inc)
|
(rx/tap #(do (swap! processed inc)
|
||||||
(progress! context
|
(progress! context :upload-data @processed total))))))
|
||||||
:upload-data @current total))))))
|
|
||||||
|
|
||||||
(rx/map first)
|
(rx/map first)
|
||||||
(rx/tap #(reset! revn (:revn %)))
|
|
||||||
(rx/ignore))
|
(rx/ignore))
|
||||||
|
|
||||||
(->> (rp/mutation :persist-temp-file {:id file-id})
|
(->> (rp/mutation :persist-temp-file {:id file-id})
|
||||||
|
@ -340,7 +332,7 @@
|
||||||
file (-> file (fb/add-page page-data))]
|
file (-> file (fb/add-page page-data))]
|
||||||
(->> (rx/from nodes)
|
(->> (rx/from nodes)
|
||||||
(rx/filter cip/shape?)
|
(rx/filter cip/shape?)
|
||||||
(rx/mapcat (partial resolve-media context file-id))
|
(rx/merge-map (partial resolve-media context file-id))
|
||||||
(rx/reduce (partial process-import-node context) file)
|
(rx/reduce (partial process-import-node context) file)
|
||||||
(rx/map (comp fb/close-page setup-interactions)))))
|
(rx/map (comp fb/close-page setup-interactions)))))
|
||||||
|
|
||||||
|
@ -362,7 +354,7 @@
|
||||||
(rx/filter cip/shape?)
|
(rx/filter cip/shape?)
|
||||||
(rx/skip 1)
|
(rx/skip 1)
|
||||||
(rx/skip-last 1)
|
(rx/skip-last 1)
|
||||||
(rx/mapcat (partial resolve-media context file-id))
|
(rx/merge-map (partial resolve-media context file-id))
|
||||||
(rx/reduce (partial process-import-node context) file)
|
(rx/reduce (partial process-import-node context) file)
|
||||||
(rx/map fb/finish-component))))
|
(rx/map fb/finish-component))))
|
||||||
|
|
||||||
|
@ -382,6 +374,7 @@
|
||||||
(fn [[page-id page-name]]
|
(fn [[page-id page-name]]
|
||||||
(->> (get-file context :page page-id)
|
(->> (get-file context :page page-id)
|
||||||
(rx/map (fn [page-data] [page-id page-name page-data])))))
|
(rx/map (fn [page-data] [page-id page-name page-data])))))
|
||||||
|
|
||||||
(rx/concat-reduce (partial import-page context) file))))
|
(rx/concat-reduce (partial import-page context) file))))
|
||||||
|
|
||||||
(defn process-library-colors
|
(defn process-library-colors
|
||||||
|
@ -420,7 +413,7 @@
|
||||||
(let [resolve (:resolve context)]
|
(let [resolve (:resolve context)]
|
||||||
(->> (get-file context :media-list)
|
(->> (get-file context :media-list)
|
||||||
(rx/flat-map (comp d/kebab-keys cip/string->uuid))
|
(rx/flat-map (comp d/kebab-keys cip/string->uuid))
|
||||||
(rx/mapcat
|
(rx/merge-map
|
||||||
(fn [[id media]]
|
(fn [[id media]]
|
||||||
(let [media (assoc media :id (resolve id))]
|
(let [media (assoc media :id (resolve id))]
|
||||||
(->> (get-file context :media id media)
|
(->> (get-file context :media id media)
|
||||||
|
@ -432,12 +425,11 @@
|
||||||
:content content
|
:content content
|
||||||
:is-local false})))
|
:is-local false})))
|
||||||
(rx/tap #(progress! context :upload-media (:name %)))
|
(rx/tap #(progress! context :upload-media (:name %)))
|
||||||
(rx/flat-map #(rp/mutation! :upload-file-media-object %))
|
(rx/merge-map #(rp/mutation! :upload-file-media-object %))
|
||||||
(rx/map (constantly media))
|
(rx/map (constantly media))
|
||||||
(rx/catch #(do (.error js/console (str "Error uploading media: " (:name media)) )
|
(rx/catch #(do (.error js/console (str "Error uploading media: " (:name media)) )
|
||||||
(rx/empty)))))))
|
(rx/empty)))))))
|
||||||
(rx/reduce fb/add-library-media file)))
|
(rx/reduce fb/add-library-media file)))
|
||||||
|
|
||||||
(rx/of file)))
|
(rx/of file)))
|
||||||
|
|
||||||
(defn process-library-components
|
(defn process-library-components
|
||||||
|
@ -511,7 +503,7 @@
|
||||||
(fn [[file data]]
|
(fn [[file data]]
|
||||||
(->> (uz/load-from-url (:uri data))
|
(->> (uz/load-from-url (:uri data))
|
||||||
(rx/map #(-> context (assoc :zip %) (merge data)))
|
(rx/map #(-> context (assoc :zip %) (merge data)))
|
||||||
(rx/flat-map
|
(rx/merge-map
|
||||||
(fn [context]
|
(fn [context]
|
||||||
;; process file retrieves a stream that will emit progress notifications
|
;; process file retrieves a stream that will emit progress notifications
|
||||||
;; and other that will emit the files once imported
|
;; and other that will emit the files once imported
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
(let [uri (u/join (cfg/get-public-uri) "api/rpc/query/page")
|
(let [uri (u/join (cfg/get-public-uri) "api/rpc/query/page")
|
||||||
params {:file-id file-id
|
params {:file-id file-id
|
||||||
:id page-id
|
:id page-id
|
||||||
:strip-thumbnails true}]
|
:strip-frames-with-thumbnails true}]
|
||||||
(->> (http/send!
|
(->> (http/send!
|
||||||
{:method :get
|
{:method :get
|
||||||
:uri uri
|
:uri uri
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue