mirror of
https://github.com/penpot/penpot.git
synced 2025-05-14 17:47:58 +02:00
🐛 Fix features related issues with render entrypoint (exporter)
This commit is contained in:
parent
0a656e9e62
commit
26d3d7f1a8
8 changed files with 264 additions and 227 deletions
|
@ -443,10 +443,17 @@
|
||||||
"Given the page data and the object-id returns the page data with all
|
"Given the page data and the object-id returns the page data with all
|
||||||
other not needed objects removed from the `:objects` data
|
other not needed objects removed from the `:objects` data
|
||||||
structure."
|
structure."
|
||||||
[{:keys [objects] :as page} object-id]
|
[page id-or-ids]
|
||||||
(let [objects (->> (cph/get-children-with-self objects object-id)
|
(update page :objects (fn [objects]
|
||||||
(filter some?))]
|
(reduce (fn [result object-id]
|
||||||
(assoc page :objects (d/index-by :id objects))))
|
(->> (cph/get-children-with-self objects object-id)
|
||||||
|
(filter some?)
|
||||||
|
(d/index-by :id)
|
||||||
|
(merge result)))
|
||||||
|
{}
|
||||||
|
(if (uuid? id-or-ids)
|
||||||
|
[id-or-ids]
|
||||||
|
id-or-ids)))))
|
||||||
|
|
||||||
(defn- prune-thumbnails
|
(defn- prune-thumbnails
|
||||||
"Given the page data, removes the `:thumbnail` prop from all
|
"Given the page data, removes the `:thumbnail` prop from all
|
||||||
|
@ -480,7 +487,7 @@
|
||||||
page)))]
|
page)))]
|
||||||
|
|
||||||
(cond-> (prune-thumbnails page)
|
(cond-> (prune-thumbnails page)
|
||||||
(uuid? object-id)
|
(some? object-id)
|
||||||
(prune-objects object-id))))
|
(prune-objects object-id))))
|
||||||
|
|
||||||
(def schema:get-page
|
(def schema:get-page
|
||||||
|
@ -488,7 +495,7 @@
|
||||||
[:file-id ::sm/uuid]
|
[:file-id ::sm/uuid]
|
||||||
[:page-id {:optional true} ::sm/uuid]
|
[:page-id {:optional true} ::sm/uuid]
|
||||||
[:share-id {:optional true} ::sm/uuid]
|
[:share-id {:optional true} ::sm/uuid]
|
||||||
[:object-id {:optional true} ::sm/uuid]
|
[:object-id {:optional true} [:or ::sm/uuid ::sm/coll-of-uuid]]
|
||||||
[:features {:optional true} ::cfeat/features]])
|
[:features {:optional true} ::cfeat/features]])
|
||||||
|
|
||||||
(sv/defmethod ::get-page
|
(sv/defmethod ::get-page
|
||||||
|
@ -500,7 +507,8 @@
|
||||||
If you specify the object-id, the page-id parameter becomes
|
If you specify the object-id, the page-id parameter becomes
|
||||||
mandatory.
|
mandatory.
|
||||||
|
|
||||||
Mainly used for rendering purposes."
|
Mainly used for rendering purposes on the exporter. It does not
|
||||||
|
accepts client features."
|
||||||
{::doc/added "1.17"
|
{::doc/added "1.17"
|
||||||
::sm/params schema:get-page}
|
::sm/params schema:get-page}
|
||||||
[cfg {:keys [::rpc/profile-id file-id share-id] :as params}]
|
[cfg {:keys [::rpc/profile-id file-id share-id] :as params}]
|
||||||
|
|
|
@ -138,14 +138,20 @@
|
||||||
(declare get-team)
|
(declare get-team)
|
||||||
|
|
||||||
(def ^:private schema:get-team
|
(def ^:private schema:get-team
|
||||||
[:map {:title "get-team"}
|
[:and
|
||||||
[:id ::sm/uuid]])
|
[:map {:title "get-team"}
|
||||||
|
[:id {:optional true} ::sm/uuid]
|
||||||
|
[:file-id {:optional true} ::sm/uuid]]
|
||||||
|
|
||||||
|
[:fn (fn [params]
|
||||||
|
(or (contains? params :id)
|
||||||
|
(contains? params :file-id)))]])
|
||||||
|
|
||||||
(sv/defmethod ::get-team
|
(sv/defmethod ::get-team
|
||||||
{::doc/added "1.17"
|
{::doc/added "1.17"
|
||||||
::sm/params schema:get-team}
|
::sm/params schema:get-team}
|
||||||
[cfg {:keys [::rpc/profile-id id]}]
|
[cfg {:keys [::rpc/profile-id id file-id]}]
|
||||||
(db/tx-run! cfg #(get-team % :profile-id profile-id :team-id id)))
|
(db/tx-run! cfg #(get-team % :profile-id profile-id :team-id id :file-id file-id)))
|
||||||
|
|
||||||
(defn get-team
|
(defn get-team
|
||||||
[conn & {:keys [profile-id team-id project-id file-id] :as params}]
|
[conn & {:keys [profile-id team-id project-id file-id] :as params}]
|
||||||
|
|
|
@ -143,6 +143,11 @@
|
||||||
([s options transformer]
|
([s options transformer]
|
||||||
(m/decoder s options transformer)))
|
(m/decoder s options transformer)))
|
||||||
|
|
||||||
|
(defn lazy-decoder
|
||||||
|
[s transformer]
|
||||||
|
(let [vfn (delay (decoder s transformer))]
|
||||||
|
(fn [v] (@vfn v))))
|
||||||
|
|
||||||
(defn humanize-data
|
(defn humanize-data
|
||||||
[{:keys [schema errors value]} & {:keys [length level]}]
|
[{:keys [schema errors value]} & {:keys [length level]}]
|
||||||
(let [errors (mapv #(update % :schema form) errors)]
|
(let [errors (mapv #(update % :schema form) errors)]
|
||||||
|
|
|
@ -326,8 +326,8 @@
|
||||||
(rx/map deref)
|
(rx/map deref)
|
||||||
(rx/map bundle-fetched)))
|
(rx/map bundle-fetched)))
|
||||||
|
|
||||||
(rx/take-until
|
(rx/take-until
|
||||||
(rx/filter (ptk/type? ::fetch-bundle) stream))))))
|
(rx/filter (ptk/type? ::fetch-bundle) stream))))))
|
||||||
|
|
||||||
(defn initialize-file
|
(defn initialize-file
|
||||||
[project-id file-id]
|
[project-id file-id]
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
[app.main.ui.shapes.text :as text]
|
[app.main.ui.shapes.text :as text]
|
||||||
[app.main.ui.shapes.text.fontfaces :as ff]
|
[app.main.ui.shapes.text.fontfaces :as ff]
|
||||||
[app.util.http :as http]
|
[app.util.http :as http]
|
||||||
[app.util.object :as obj]
|
|
||||||
[app.util.strings :as ust]
|
[app.util.strings :as ust]
|
||||||
[app.util.thumbnails :as th]
|
[app.util.thumbnails :as th]
|
||||||
[app.util.timers :as ts]
|
[app.util.timers :as ts]
|
||||||
|
@ -83,11 +82,11 @@
|
||||||
(let [shape-wrapper (shape-wrapper-factory objects)
|
(let [shape-wrapper (shape-wrapper-factory objects)
|
||||||
frame-shape (frame/frame-shape shape-wrapper)]
|
frame-shape (frame/frame-shape shape-wrapper)]
|
||||||
(mf/fnc frame-wrapper
|
(mf/fnc frame-wrapper
|
||||||
[{:keys [shape] :as props}]
|
{::mf/wrap-props false}
|
||||||
|
[{:keys [shape]}]
|
||||||
(let [render-thumbnails? (mf/use-ctx muc/render-thumbnails)
|
(let [thumbnails? (mf/use-ctx muc/render-thumbnails)
|
||||||
childs (mapv #(get objects %) (:shapes shape))]
|
childs (mapv (d/getf objects) (:shapes shape))]
|
||||||
(if (and render-thumbnails? (some? (:thumbnail shape)))
|
(if (and thumbnails? (some? (:thumbnail shape)))
|
||||||
[:& frame/frame-thumbnail {:shape shape :bounds (:children-bounds shape)}]
|
[:& frame/frame-thumbnail {:shape shape :bounds (:children-bounds shape)}]
|
||||||
[:& frame-shape {:shape shape :childs childs}])))))
|
[:& frame-shape {:shape shape :childs childs}])))))
|
||||||
|
|
||||||
|
@ -193,8 +192,8 @@
|
||||||
|
|
||||||
(mf/defc page-svg
|
(mf/defc page-svg
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [data thumbnails? render-embed? include-metadata?] :as props
|
[{:keys [data use-thumbnails embed include-metadata] :as props
|
||||||
:or {render-embed? false include-metadata? false}}]
|
:or {embed false include-metadata false}}]
|
||||||
(let [objects (:objects data)
|
(let [objects (:objects data)
|
||||||
shapes (cph/get-immediate-children objects)
|
shapes (cph/get-immediate-children objects)
|
||||||
dim (calculate-dimensions objects)
|
dim (calculate-dimensions objects)
|
||||||
|
@ -206,20 +205,20 @@
|
||||||
(mf/deps objects)
|
(mf/deps objects)
|
||||||
#(shape-wrapper-factory objects))]
|
#(shape-wrapper-factory objects))]
|
||||||
|
|
||||||
[:& (mf/provider muc/render-thumbnails) {:value thumbnails?}
|
[:& (mf/provider muc/render-thumbnails) {:value use-thumbnails}
|
||||||
[:& (mf/provider embed/context) {:value render-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}
|
||||||
[:svg {:view-box vbox
|
[:svg {:view-box vbox
|
||||||
:version "1.1"
|
:version "1.1"
|
||||||
: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")
|
||||||
:style {:width "100%"
|
:style {:width "100%"
|
||||||
:height "100%"
|
:height "100%"
|
||||||
:background bgcolor}
|
:background bgcolor}
|
||||||
:fill "none"}
|
:fill "none"}
|
||||||
|
|
||||||
(when include-metadata?
|
(when include-metadata
|
||||||
[:& export/export-page {:id (:id data) :options (:options data)}])
|
[:& export/export-page {:id (:id data) :options (:options data)}])
|
||||||
|
|
||||||
(let [shapes (->> shapes
|
(let [shapes (->> shapes
|
||||||
|
@ -250,9 +249,9 @@
|
||||||
;; the viewer and inspector
|
;; the viewer and inspector
|
||||||
(mf/defc frame-svg
|
(mf/defc frame-svg
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [objects frame zoom show-thumbnails?] :or {zoom 1} :as props}]
|
[{:keys [objects frame zoom use-thumbnails] :or {zoom 1} :as props}]
|
||||||
(let [frame-id (:id frame)
|
(let [frame-id (:id frame)
|
||||||
include-metadata? (mf/use-ctx export/include-metadata-ctx)
|
include-metadata (mf/use-ctx export/include-metadata-ctx)
|
||||||
|
|
||||||
bounds (gsb/get-object-bounds objects frame)
|
bounds (gsb/get-object-bounds objects frame)
|
||||||
|
|
||||||
|
@ -294,14 +293,14 @@
|
||||||
height (* (:height bounds) zoom)
|
height (* (:height bounds) zoom)
|
||||||
vbox (format-viewbox {:width (:width bounds 0) :height (:height bounds 0)})]
|
vbox (format-viewbox {:width (:width bounds 0) :height (:height bounds 0)})]
|
||||||
|
|
||||||
[:& (mf/provider muc/render-thumbnails) {:value show-thumbnails?}
|
[:& (mf/provider muc/render-thumbnails) {:value use-thumbnails}
|
||||||
[:svg {:view-box vbox
|
[:svg {:view-box vbox
|
||||||
:width (ust/format-precision width viewbox-decimal-precision)
|
:width (ust/format-precision width viewbox-decimal-precision)
|
||||||
:height (ust/format-precision height viewbox-decimal-precision)
|
:height (ust/format-precision height viewbox-decimal-precision)
|
||||||
:version "1.1"
|
:version "1.1"
|
||||||
: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")
|
||||||
:fill "none"}
|
:fill "none"}
|
||||||
[:& shape-wrapper {:shape frame}]]]))
|
[:& shape-wrapper {:shape frame}]]]))
|
||||||
|
|
||||||
|
@ -312,7 +311,7 @@
|
||||||
[{:keys [objects root-shape zoom] :or {zoom 1} :as props}]
|
[{:keys [objects root-shape zoom] :or {zoom 1} :as props}]
|
||||||
(when root-shape
|
(when root-shape
|
||||||
(let [root-shape-id (:id root-shape)
|
(let [root-shape-id (:id root-shape)
|
||||||
include-metadata? (mf/use-ctx export/include-metadata-ctx)
|
include-metadata (mf/use-ctx export/include-metadata-ctx)
|
||||||
|
|
||||||
vector
|
vector
|
||||||
(mf/use-memo
|
(mf/use-memo
|
||||||
|
@ -348,7 +347,7 @@
|
||||||
:version "1.1"
|
:version "1.1"
|
||||||
: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")
|
||||||
:fill "none"}
|
:fill "none"}
|
||||||
|
|
||||||
[:> shape-container {:shape root-shape'}
|
[:> shape-container {:shape root-shape'}
|
||||||
|
@ -357,8 +356,8 @@
|
||||||
|
|
||||||
(mf/defc object-svg
|
(mf/defc object-svg
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [objects object-id render-embed?]
|
[{:keys [objects object-id embed]
|
||||||
:or {render-embed? false}
|
:or {embed false}
|
||||||
:as props}]
|
:as props}]
|
||||||
(let [object (get objects object-id)
|
(let [object (get objects object-id)
|
||||||
object (cond-> object
|
object (cond-> object
|
||||||
|
@ -375,7 +374,7 @@
|
||||||
(shape-wrapper-factory objects))]
|
(shape-wrapper-factory objects))]
|
||||||
|
|
||||||
[:& (mf/provider export/include-metadata-ctx) {:value false}
|
[:& (mf/provider export/include-metadata-ctx) {:value false}
|
||||||
[:& (mf/provider embed/context) {:value render-embed?}
|
[:& (mf/provider embed/context) {:value embed}
|
||||||
[:svg {:id (dm/str "screenshot-" object-id)
|
[:svg {:id (dm/str "screenshot-" object-id)
|
||||||
:view-box vbox
|
:view-box vbox
|
||||||
:width (ust/format-precision width viewbox-decimal-precision)
|
:width (ust/format-precision width viewbox-decimal-precision)
|
||||||
|
@ -439,20 +438,16 @@
|
||||||
:group [:& group-wrapper {:shape root-shape :view-box vbox}]
|
:group [:& group-wrapper {:shape root-shape :view-box vbox}]
|
||||||
:frame [:& frame-wrapper {:shape root-shape :view-box vbox}])]]))
|
:frame [:& frame-wrapper {:shape root-shape :view-box vbox}])]]))
|
||||||
|
|
||||||
(mf/defc components-sprite-svg
|
(mf/defc components-svg
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[{:keys [data children embed include-metadata source]}]
|
||||||
(let [data (obj/get props "data")
|
(let [source (keyword (d/nilv source "components"))]
|
||||||
children (obj/get props "children")
|
[:& (mf/provider embed/context) {:value embed}
|
||||||
render-embed? (obj/get props "render-embed?")
|
[:& (mf/provider export/include-metadata-ctx) {:value include-metadata}
|
||||||
include-metadata? (obj/get props "include-metadata?")
|
|
||||||
source (keyword (obj/get props "source" "components"))]
|
|
||||||
[:& (mf/provider embed/context) {:value render-embed?}
|
|
||||||
[:& (mf/provider export/include-metadata-ctx) {:value include-metadata?}
|
|
||||||
[:svg {:version "1.1"
|
[:svg {:version "1.1"
|
||||||
: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")
|
||||||
:style {:display (when-not (some? children) "none")}
|
:style {:display (when-not (some? children) "none")}
|
||||||
:fill "none"}
|
:fill "none"}
|
||||||
[:defs
|
[:defs
|
||||||
|
@ -511,7 +506,7 @@
|
||||||
(->> (rx/of data)
|
(->> (rx/of data)
|
||||||
(rx/map
|
(rx/map
|
||||||
(fn [data]
|
(fn [data]
|
||||||
(let [elem (mf/element page-svg #js {:data data :render-embed? true :include-metadata? true})]
|
(let [elem (mf/element page-svg #js {:data data :embed true :include-metadata true})]
|
||||||
(rds/renderToStaticMarkup elem)))))))
|
(rds/renderToStaticMarkup elem)))))))
|
||||||
|
|
||||||
(defn render-components
|
(defn render-components
|
||||||
|
@ -531,8 +526,8 @@
|
||||||
(->> (rx/of data)
|
(->> (rx/of data)
|
||||||
(rx/map
|
(rx/map
|
||||||
(fn [data]
|
(fn [data]
|
||||||
(let [elem (mf/element components-sprite-svg
|
(let [elem (mf/element components-svg
|
||||||
#js {:data data :render-embed? true :include-metadata? true
|
#js {:data data :embed true :include-metadata true
|
||||||
:source (name source)})]
|
:source (name source)})]
|
||||||
(rds/renderToStaticMarkup elem))))))))
|
(rds/renderToStaticMarkup elem))))))))
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
|
(assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame))))
|
||||||
(assoc :children-bounds children-bounds))
|
(assoc :children-bounds children-bounds))
|
||||||
:objects objects
|
:objects objects
|
||||||
:show-thumbnails? true}]]
|
:use-thumbnails true}]]
|
||||||
[:div.thumbnail-info
|
[:div.thumbnail-info
|
||||||
[:span.name {:title (:name frame)} (:name frame)]]]))
|
[:span.name {:title (:name frame)} (:name frame)]]]))
|
||||||
|
|
||||||
|
|
|
@ -8,125 +8,54 @@
|
||||||
"The main entry point for UI part needed by the exporter."
|
"The main entry point for UI part needed by the exporter."
|
||||||
(:require
|
(:require
|
||||||
[app.common.geom.shapes.bounds :as gsb]
|
[app.common.geom.shapes.bounds :as gsb]
|
||||||
[app.common.logging :as l]
|
[app.common.logging :as log]
|
||||||
[app.common.math :as mth]
|
[app.common.math :as mth]
|
||||||
[app.common.spec :as us]
|
[app.common.schema :as sm]
|
||||||
[app.common.types.components-list :as ctkl]
|
[app.common.types.components-list :as ctkl]
|
||||||
[app.common.uri :as u]
|
[app.common.uri :as u]
|
||||||
[app.main.data.fonts :as df]
|
[app.main.data.fonts :as df]
|
||||||
[app.main.features :as feat]
|
[app.main.data.users :as du]
|
||||||
|
[app.main.features :as features]
|
||||||
[app.main.render :as render]
|
[app.main.render :as render]
|
||||||
[app.main.repo :as repo]
|
[app.main.repo :as repo]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.globals :as glob]
|
[app.util.globals :as glob]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[clojure.spec.alpha :as s]
|
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[garden.core :refer [css]]
|
[garden.core :refer [css]]
|
||||||
|
[okulary.core :as l]
|
||||||
|
[potok.core :as ptk]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
(log/setup! {:app :info})
|
||||||
;; SETUP
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
|
|
||||||
(l/setup! {:app :info})
|
(defn- fetch-team
|
||||||
|
[& {:keys [file-id]}]
|
||||||
(defonce app-root
|
(ptk/reify ::fetch-team
|
||||||
(let [el (dom/get-element "app")]
|
ptk/WatchEvent
|
||||||
(mf/create-root el)))
|
(watch [_ _ _]
|
||||||
|
(->> (repo/cmd! :get-team {:file-id file-id})
|
||||||
(declare ^:private render-single-object)
|
(rx/mapcat (fn [team]
|
||||||
(declare ^:private render-components)
|
(rx/of (du/set-current-team team)
|
||||||
(declare ^:private render-objects)
|
(ptk/data-event ::team-fetched team))))))))
|
||||||
|
|
||||||
(defn- parse-params
|
|
||||||
[loc]
|
|
||||||
(let [href (unchecked-get loc "href")]
|
|
||||||
(some-> href u/uri :query u/query-string->map)))
|
|
||||||
|
|
||||||
(defn init-ui
|
|
||||||
[]
|
|
||||||
(when-let [params (parse-params glob/location)]
|
|
||||||
(when-let [component (case (:route params)
|
|
||||||
"objects" (render-objects params)
|
|
||||||
"components" (render-components params)
|
|
||||||
nil)]
|
|
||||||
(mf/render! app-root component))))
|
|
||||||
|
|
||||||
(defn ^:export init
|
|
||||||
[]
|
|
||||||
(st/emit! (feat/initialize))
|
|
||||||
(init-ui))
|
|
||||||
|
|
||||||
(defn reinit
|
|
||||||
[]
|
|
||||||
(mf/unmount! app-root)
|
|
||||||
(init-ui))
|
|
||||||
|
|
||||||
(defn ^:dev/after-load after-load
|
|
||||||
[]
|
|
||||||
(reinit))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; COMPONENTS
|
;; COMPONENTS
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;; ---- SINGLE OBJECT
|
(def ^:private ref:objects
|
||||||
|
(l/derived :objects st/state))
|
||||||
(defn use-resource
|
|
||||||
"A general purpose hook for retrieve or subscribe to remote changes
|
|
||||||
using the reactive-streams mechanism mechanism.
|
|
||||||
|
|
||||||
It receives a function to execute for retrieve the stream that will
|
|
||||||
be used for creating the subscription. The function should be
|
|
||||||
stable, so is the responsibility of the user of this hook to
|
|
||||||
properly memoize it.
|
|
||||||
|
|
||||||
TODO: this should be placed in some generic hooks namespace but his
|
|
||||||
right now is pending of refactor and it will be done later."
|
|
||||||
[f]
|
|
||||||
(let [[state ^js update-state!] (mf/useState {:loaded? false})]
|
|
||||||
(mf/with-effect [f]
|
|
||||||
(update-state! (fn [prev] (assoc prev :refreshing? true)))
|
|
||||||
(let [on-value (fn [data]
|
|
||||||
(update-state! #(-> %
|
|
||||||
(assoc :refreshing? false)
|
|
||||||
(assoc :loaded? true)
|
|
||||||
(merge data))))
|
|
||||||
subs (rx/subscribe (f) on-value)]
|
|
||||||
#(rx/dispose! subs)))
|
|
||||||
state))
|
|
||||||
|
|
||||||
(mf/defc object-svg
|
(mf/defc object-svg
|
||||||
[{:keys [page-id file-id share-id object-id render-embed?]}]
|
{::mf/wrap-props false}
|
||||||
(let [components-v2 (feat/use-feature "components/v2")
|
[{:keys [object-id embed]}]
|
||||||
fetch-state (mf/use-fn
|
(let [objects (mf/deref ref:objects)]
|
||||||
(mf/deps file-id page-id share-id object-id components-v2)
|
|
||||||
(fn []
|
|
||||||
(let [features (cond-> #{} components-v2 (conj "components/v2"))]
|
|
||||||
(->> (rx/zip
|
|
||||||
(repo/cmd! :get-font-variants {:file-id file-id :share-id share-id})
|
|
||||||
(repo/cmd! :get-page {:file-id file-id
|
|
||||||
:page-id page-id
|
|
||||||
:share-id share-id
|
|
||||||
:object-id object-id
|
|
||||||
:features features}))
|
|
||||||
(rx/tap (fn [[fonts]]
|
|
||||||
(when (seq fonts)
|
|
||||||
(st/emit! (df/fonts-fetched fonts)))))
|
|
||||||
(rx/map (comp :objects second))
|
|
||||||
(rx/map (fn [objects]
|
|
||||||
(let [objects (render/adapt-objects-for-shape objects object-id)]
|
|
||||||
{:objects objects
|
|
||||||
:object (get objects object-id)})))))))
|
|
||||||
|
|
||||||
{:keys [objects object]} (use-resource fetch-state)]
|
|
||||||
|
|
||||||
;; Set the globa CSS to assign the page size, needed for PDF
|
;; Set the globa CSS to assign the page size, needed for PDF
|
||||||
;; exportation process.
|
;; exportation process.
|
||||||
(mf/with-effect [object]
|
(mf/with-effect [objects]
|
||||||
(when object
|
(when-let [object (get objects object-id)]
|
||||||
(let [{:keys [width height]} (gsb/get-object-bounds [objects] object)]
|
(let [{:keys [width height]} (gsb/get-object-bounds [objects] object)]
|
||||||
(dom/set-page-style!
|
(dom/set-page-style!
|
||||||
{:size (str/concat
|
{:size (str/concat
|
||||||
|
@ -137,90 +66,107 @@
|
||||||
[:& render/object-svg
|
[:& render/object-svg
|
||||||
{:objects objects
|
{:objects objects
|
||||||
:object-id object-id
|
:object-id object-id
|
||||||
:render-embed? render-embed?}])))
|
:embed embed}])))
|
||||||
|
|
||||||
(mf/defc objects-svg
|
(mf/defc objects-svg
|
||||||
[{:keys [page-id file-id share-id object-ids render-embed?]}]
|
{::mf/wrap-props false}
|
||||||
(let [components-v2 (feat/use-feature "components/v2")
|
[{:keys [object-ids embed]}]
|
||||||
fetch-state (mf/use-fn
|
(when-let [objects (mf/deref ref:objects)]
|
||||||
(mf/deps file-id page-id share-id components-v2)
|
(for [object-id object-ids]
|
||||||
(fn []
|
(let [objects (render/adapt-objects-for-shape objects object-id)]
|
||||||
(let [features (cond-> #{} components-v2 (conj "components/v2"))]
|
[:& render/object-svg
|
||||||
(->> (rx/zip
|
{:objects objects
|
||||||
(repo/cmd! :get-font-variants {:file-id file-id :share-id share-id})
|
:key (str object-id)
|
||||||
(repo/cmd! :get-page {:file-id file-id
|
:object-id object-id
|
||||||
:page-id page-id
|
:embed embed}]))))
|
||||||
:share-id share-id
|
|
||||||
:features features}))
|
|
||||||
(rx/tap (fn [[fonts]]
|
|
||||||
(when (seq fonts)
|
|
||||||
(st/emit! (df/fonts-fetched fonts)))))
|
|
||||||
(rx/map (fn [[_ page]] {:objects (:objects page)}))))))
|
|
||||||
|
|
||||||
{:keys [objects]} (use-resource fetch-state)]
|
(defn- fetch-objects-bundle
|
||||||
|
[& {:keys [file-id page-id share-id object-id] :as options}]
|
||||||
|
(ptk/reify ::fetch-objects-bundle
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [features (features/get-team-enabled-features state)]
|
||||||
|
(->> (rx/zip
|
||||||
|
(repo/cmd! :get-font-variants {:file-id file-id :share-id share-id})
|
||||||
|
(repo/cmd! :get-page {:file-id file-id
|
||||||
|
:page-id page-id
|
||||||
|
:share-id share-id
|
||||||
|
:object-id object-id
|
||||||
|
:features features}))
|
||||||
|
(rx/tap (fn [[fonts]]
|
||||||
|
(when (seq fonts)
|
||||||
|
(st/emit! (df/fonts-fetched fonts)))))
|
||||||
|
(rx/observe-on :async)
|
||||||
|
(rx/map (comp :objects second))
|
||||||
|
(rx/map (fn [objects]
|
||||||
|
(let [objects (render/adapt-objects-for-shape objects object-id)]
|
||||||
|
#(assoc % :objects objects)))))))))
|
||||||
|
|
||||||
(when objects
|
(def ^:private schema:render-objects
|
||||||
(for [object-id object-ids]
|
[:map {:title "render-objets"}
|
||||||
(let [objects (render/adapt-objects-for-shape objects object-id)]
|
[:page-id ::sm/uuid]
|
||||||
[:& render/object-svg
|
[:file-id ::sm/uuid]
|
||||||
{:objects objects
|
[:share-id {:optional true} ::sm/uuid]
|
||||||
:key (str object-id)
|
[:embed {:optional true} :boolean]
|
||||||
:object-id object-id
|
[:object-id
|
||||||
:render-embed? render-embed?}])))))
|
[:or
|
||||||
|
::sm/uuid
|
||||||
|
::sm/coll-of-uuid]]])
|
||||||
|
|
||||||
(s/def ::page-id ::us/uuid)
|
(def ^:private render-objects-decoder
|
||||||
(s/def ::file-id ::us/uuid)
|
(sm/lazy-decoder schema:render-objects
|
||||||
(s/def ::share-id ::us/uuid)
|
sm/default-transformer))
|
||||||
(s/def ::object-id
|
|
||||||
(s/or :single ::us/uuid
|
|
||||||
:multiple (s/coll-of ::us/uuid)))
|
|
||||||
(s/def ::embed ::us/boolean)
|
|
||||||
|
|
||||||
(s/def ::render-objects
|
(def ^:private render-objects-validator
|
||||||
(s/keys :req-un [::file-id ::page-id ::object-id]
|
(sm/lazy-validator schema:render-objects))
|
||||||
:opt-un [::render-embed ::share-id]))
|
|
||||||
|
|
||||||
(defn- render-objects
|
(defn- render-objects
|
||||||
[params]
|
[params]
|
||||||
(let [{:keys [file-id
|
(let [{:keys [file-id page-id embed share-id object-id] :as params} (render-objects-decoder params)]
|
||||||
page-id
|
(if-not (render-objects-validator params)
|
||||||
render-embed
|
(do
|
||||||
share-id]
|
(js/console.error "invalid arguments")
|
||||||
:as params}
|
(sm/pretty-explain schema:render-objects params)
|
||||||
(us/conform ::render-objects params)
|
nil)
|
||||||
|
|
||||||
[type object-id] (:object-id params)]
|
(do
|
||||||
(case type
|
(st/emit! (ptk/reify ::initialize-render-objects
|
||||||
:single
|
ptk/WatchEvent
|
||||||
(mf/html
|
(watch [_ _ stream]
|
||||||
[:& object-svg
|
(rx/merge
|
||||||
{:file-id file-id
|
(rx/of (fetch-team :file-id file-id))
|
||||||
:page-id page-id
|
|
||||||
:share-id share-id
|
|
||||||
:object-id object-id
|
|
||||||
:render-embed? render-embed}])
|
|
||||||
|
|
||||||
:multiple
|
(->> stream
|
||||||
(mf/html
|
(rx/filter (ptk/type? ::team-fetched))
|
||||||
[:& objects-svg
|
(rx/observe-on :async)
|
||||||
{:file-id file-id
|
(rx/map (constantly params))
|
||||||
:page-id page-id
|
(rx/map fetch-objects-bundle))))))
|
||||||
:share-id share-id
|
|
||||||
:object-ids (into #{} object-id)
|
(if (uuid? object-id)
|
||||||
:render-embed? render-embed}]))))
|
(mf/html
|
||||||
|
[:& object-svg
|
||||||
|
{:file-id file-id
|
||||||
|
:page-id page-id
|
||||||
|
:share-id share-id
|
||||||
|
:object-id object-id
|
||||||
|
:embed embed}])
|
||||||
|
|
||||||
|
(mf/html
|
||||||
|
[:& objects-svg
|
||||||
|
{:file-id file-id
|
||||||
|
:page-id page-id
|
||||||
|
:share-id share-id
|
||||||
|
:object-ids (into #{} object-id)
|
||||||
|
:embed embed}]))))))
|
||||||
|
|
||||||
;; ---- COMPONENTS SPRITE
|
;; ---- COMPONENTS SPRITE
|
||||||
|
|
||||||
(mf/defc components-sprite-svg
|
(mf/defc components-svg
|
||||||
[{:keys [file-id embed] :as props}]
|
{::mf/wrap-props false}
|
||||||
(let [fetch (mf/use-fn
|
[{:keys [embed component-id]}]
|
||||||
(mf/deps file-id)
|
(let [file-ref (mf/with-memo [] (l/derived :file st/state))
|
||||||
(fn [] (repo/cmd! :get-file {:id file-id})))
|
state (mf/use-state {:component-id component-id})]
|
||||||
|
(when-let [file (mf/deref file-ref)]
|
||||||
file (use-resource fetch)
|
|
||||||
state (mf/use-state nil)]
|
|
||||||
|
|
||||||
(when file
|
|
||||||
[:*
|
[:*
|
||||||
[:style
|
[:style
|
||||||
(css [[:body
|
(css [[:body
|
||||||
|
@ -266,7 +212,7 @@
|
||||||
[:a {:on-click on-click} (:name data)]]))]
|
[:a {:on-click on-click} (:name data)]]))]
|
||||||
|
|
||||||
[:main
|
[:main
|
||||||
[:& render/components-sprite-svg
|
[:& render/components-svg
|
||||||
{:data (:data file)
|
{:data (:data file)
|
||||||
:embed embed}
|
:embed embed}
|
||||||
|
|
||||||
|
@ -275,16 +221,93 @@
|
||||||
|
|
||||||
])))
|
])))
|
||||||
|
|
||||||
(s/def ::component-id ::us/uuid)
|
(defn- fetch-components-bundle
|
||||||
(s/def ::render-components
|
[& {:keys [file-id]}]
|
||||||
(s/keys :req-un [::file-id]
|
(ptk/reify ::fetch-components-bundle
|
||||||
:opt-un [::embed ::component-id]))
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [features (features/get-team-enabled-features state)]
|
||||||
|
(->> (repo/cmd! :get-file {:id file-id :features features})
|
||||||
|
(rx/map (fn [file] #(assoc % :file file))))))))
|
||||||
|
|
||||||
|
(def ^:private schema:render-components
|
||||||
|
[:map {:title "render-components"}
|
||||||
|
[:file-id ::sm/uuid]
|
||||||
|
[:embed {:optional true} :boolean]
|
||||||
|
[:component-id {:optional true} ::sm/uuid]])
|
||||||
|
|
||||||
|
(def ^:private render-components-decoder
|
||||||
|
(sm/lazy-decoder schema:render-components
|
||||||
|
sm/default-transformer))
|
||||||
|
|
||||||
|
(def ^:private render-components-validator
|
||||||
|
(sm/lazy-validator schema:render-components))
|
||||||
|
|
||||||
(defn render-components
|
(defn render-components
|
||||||
[params]
|
[params]
|
||||||
(let [{:keys [file-id component-id embed]} (us/conform ::render-components params)]
|
(let [{:keys [file-id component-id embed] :as params} (render-components-decoder params)]
|
||||||
(mf/html
|
(if-not (render-components-validator params)
|
||||||
[:& components-sprite-svg
|
(do
|
||||||
{:file-id file-id
|
(js/console.error "invalid arguments")
|
||||||
:component-id component-id
|
(sm/pretty-explain schema:render-components params)
|
||||||
:embed embed}])))
|
nil)
|
||||||
|
|
||||||
|
(do
|
||||||
|
(st/emit! (ptk/reify ::initialize-render-components
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ _ stream]
|
||||||
|
(rx/merge
|
||||||
|
(rx/of (fetch-team :file-id file-id))
|
||||||
|
|
||||||
|
(->> stream
|
||||||
|
(rx/filter (ptk/type? ::team-fetched))
|
||||||
|
(rx/observe-on :async)
|
||||||
|
(rx/map (constantly params))
|
||||||
|
(rx/map fetch-components-bundle))))))
|
||||||
|
|
||||||
|
(mf/html
|
||||||
|
[:& components-svg
|
||||||
|
{:component-id component-id
|
||||||
|
:embed embed}])))))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; SETUP
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(defonce app-root
|
||||||
|
(let [el (dom/get-element "app")]
|
||||||
|
(mf/create-root el)))
|
||||||
|
|
||||||
|
(declare ^:private render-single-object)
|
||||||
|
(declare ^:private render-components)
|
||||||
|
(declare ^:private render-objects)
|
||||||
|
|
||||||
|
(defn- parse-params
|
||||||
|
[loc]
|
||||||
|
(let [href (unchecked-get loc "href")]
|
||||||
|
(some-> href u/uri :query u/query-string->map)))
|
||||||
|
|
||||||
|
(defn init-ui
|
||||||
|
[]
|
||||||
|
(when-let [params (parse-params glob/location)]
|
||||||
|
(when-let [component (case (:route params)
|
||||||
|
"objects" (render-objects params)
|
||||||
|
"components" (render-components params)
|
||||||
|
nil)]
|
||||||
|
(mf/render! app-root component))))
|
||||||
|
|
||||||
|
(defn ^:export init
|
||||||
|
[]
|
||||||
|
(st/emit! (features/initialize))
|
||||||
|
(init-ui))
|
||||||
|
|
||||||
|
(defn reinit
|
||||||
|
[]
|
||||||
|
(init-ui))
|
||||||
|
|
||||||
|
(defn ^:dev/after-load after-load
|
||||||
|
[]
|
||||||
|
(reinit))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,8 @@
|
||||||
(let [objects (:objects page)
|
(let [objects (:objects page)
|
||||||
frame (some->> page :thumbnail-frame-id (get objects))
|
frame (some->> page :thumbnail-frame-id (get objects))
|
||||||
element (if frame
|
element (if frame
|
||||||
(mf/element render/frame-svg #js {:objects objects :frame frame :show-thumbnails? true})
|
(mf/element render/frame-svg #js {:objects objects :frame frame :use-thumbnails true})
|
||||||
(mf/element render/page-svg #js {:data page :thumbnails? true :render-embed? true}))
|
(mf/element render/page-svg #js {:data page :use-thumbnails true :embed true}))
|
||||||
data (rds/renderToStaticMarkup element)]
|
data (rds/renderToStaticMarkup element)]
|
||||||
{:data data
|
{:data data
|
||||||
:fonts @fonts/loaded-hints
|
:fonts @fonts/loaded-hints
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue