From 26d3d7f1a8214e8d56de20544aec1659f8f37b36 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 13 Nov 2023 18:09:25 +0100 Subject: [PATCH] :bug: Fix features related issues with render entrypoint (exporter) --- backend/src/app/rpc/commands/files.clj | 22 +- backend/src/app/rpc/commands/teams.clj | 14 +- common/src/app/common/schema.cljc | 5 + frontend/src/app/main/data/workspace.cljs | 4 +- frontend/src/app/main/render.cljs | 67 ++-- .../src/app/main/ui/viewer/thumbnails.cljs | 2 +- frontend/src/app/render.cljs | 373 ++++++++++-------- frontend/src/app/worker/thumbnails.cljs | 4 +- 8 files changed, 264 insertions(+), 227 deletions(-) diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index 28ff8ad61..7db6cd78a 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -443,10 +443,17 @@ "Given the page data and the object-id returns the page data with all other not needed objects removed from the `:objects` data structure." - [{:keys [objects] :as page} object-id] - (let [objects (->> (cph/get-children-with-self objects object-id) - (filter some?))] - (assoc page :objects (d/index-by :id objects)))) + [page id-or-ids] + (update page :objects (fn [objects] + (reduce (fn [result object-id] + (->> (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 "Given the page data, removes the `:thumbnail` prop from all @@ -480,7 +487,7 @@ page)))] (cond-> (prune-thumbnails page) - (uuid? object-id) + (some? object-id) (prune-objects object-id)))) (def schema:get-page @@ -488,7 +495,7 @@ [:file-id ::sm/uuid] [:page-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]]) (sv/defmethod ::get-page @@ -500,7 +507,8 @@ If you specify the object-id, the page-id parameter becomes mandatory. - Mainly used for rendering purposes." + Mainly used for rendering purposes on the exporter. It does not + accepts client features." {::doc/added "1.17" ::sm/params schema:get-page} [cfg {:keys [::rpc/profile-id file-id share-id] :as params}] diff --git a/backend/src/app/rpc/commands/teams.clj b/backend/src/app/rpc/commands/teams.clj index 39dc53495..92f0a2b2f 100644 --- a/backend/src/app/rpc/commands/teams.clj +++ b/backend/src/app/rpc/commands/teams.clj @@ -138,14 +138,20 @@ (declare get-team) (def ^:private schema:get-team - [:map {:title "get-team"} - [:id ::sm/uuid]]) + [:and + [: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 {::doc/added "1.17" ::sm/params schema:get-team} - [cfg {:keys [::rpc/profile-id id]}] - (db/tx-run! cfg #(get-team % :profile-id profile-id :team-id id))) + [cfg {:keys [::rpc/profile-id id file-id]}] + (db/tx-run! cfg #(get-team % :profile-id profile-id :team-id id :file-id file-id))) (defn get-team [conn & {:keys [profile-id team-id project-id file-id] :as params}] diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index 82aca3ffe..047118742 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -143,6 +143,11 @@ ([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 [{:keys [schema errors value]} & {:keys [length level]}] (let [errors (mapv #(update % :schema form) errors)] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index cf26ed78e..dabc8ecf6 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -326,8 +326,8 @@ (rx/map deref) (rx/map bundle-fetched))) - (rx/take-until - (rx/filter (ptk/type? ::fetch-bundle) stream)))))) + (rx/take-until + (rx/filter (ptk/type? ::fetch-bundle) stream)))))) (defn initialize-file [project-id file-id] diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index 5b7fbcaa8..93df65f9a 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -43,7 +43,6 @@ [app.main.ui.shapes.text :as text] [app.main.ui.shapes.text.fontfaces :as ff] [app.util.http :as http] - [app.util.object :as obj] [app.util.strings :as ust] [app.util.thumbnails :as th] [app.util.timers :as ts] @@ -83,11 +82,11 @@ (let [shape-wrapper (shape-wrapper-factory objects) frame-shape (frame/frame-shape shape-wrapper)] (mf/fnc frame-wrapper - [{:keys [shape] :as props}] - - (let [render-thumbnails? (mf/use-ctx muc/render-thumbnails) - childs (mapv #(get objects %) (:shapes shape))] - (if (and render-thumbnails? (some? (:thumbnail shape))) + {::mf/wrap-props false} + [{:keys [shape]}] + (let [thumbnails? (mf/use-ctx muc/render-thumbnails) + childs (mapv (d/getf objects) (:shapes shape))] + (if (and thumbnails? (some? (:thumbnail shape))) [:& frame/frame-thumbnail {:shape shape :bounds (:children-bounds shape)}] [:& frame-shape {:shape shape :childs childs}]))))) @@ -193,8 +192,8 @@ (mf/defc page-svg {::mf/wrap [mf/memo]} - [{:keys [data thumbnails? render-embed? include-metadata?] :as props - :or {render-embed? false include-metadata? false}}] + [{:keys [data use-thumbnails embed include-metadata] :as props + :or {embed false include-metadata false}}] (let [objects (:objects data) shapes (cph/get-immediate-children objects) dim (calculate-dimensions objects) @@ -206,20 +205,20 @@ (mf/deps objects) #(shape-wrapper-factory objects))] - [:& (mf/provider muc/render-thumbnails) {:value thumbnails?} - [:& (mf/provider embed/context) {:value render-embed?} - [:& (mf/provider export/include-metadata-ctx) {:value include-metadata?} + [:& (mf/provider muc/render-thumbnails) {:value use-thumbnails} + [:& (mf/provider embed/context) {:value embed} + [:& (mf/provider export/include-metadata-ctx) {:value include-metadata} [:svg {:view-box vbox :version "1.1" :xmlns "http://www.w3.org/2000/svg" :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%" :height "100%" :background bgcolor} :fill "none"} - (when include-metadata? + (when include-metadata [:& export/export-page {:id (:id data) :options (:options data)}]) (let [shapes (->> shapes @@ -250,9 +249,9 @@ ;; the viewer and inspector (mf/defc frame-svg {::mf/wrap [mf/memo]} - [{:keys [objects frame zoom show-thumbnails?] :or {zoom 1} :as props}] - (let [frame-id (:id frame) - include-metadata? (mf/use-ctx export/include-metadata-ctx) + [{:keys [objects frame zoom use-thumbnails] :or {zoom 1} :as props}] + (let [frame-id (:id frame) + include-metadata (mf/use-ctx export/include-metadata-ctx) bounds (gsb/get-object-bounds objects frame) @@ -294,14 +293,14 @@ height (* (:height bounds) zoom) 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 :width (ust/format-precision width viewbox-decimal-precision) :height (ust/format-precision height viewbox-decimal-precision) :version "1.1" :xmlns "http://www.w3.org/2000/svg" :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"} [:& shape-wrapper {:shape frame}]]])) @@ -312,7 +311,7 @@ [{:keys [objects root-shape zoom] :or {zoom 1} :as props}] (when 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 (mf/use-memo @@ -348,7 +347,7 @@ :version "1.1" :xmlns "http://www.w3.org/2000/svg" :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"} [:> shape-container {:shape root-shape'} @@ -357,8 +356,8 @@ (mf/defc object-svg {::mf/wrap [mf/memo]} - [{:keys [objects object-id render-embed?] - :or {render-embed? false} + [{:keys [objects object-id embed] + :or {embed false} :as props}] (let [object (get objects object-id) object (cond-> object @@ -375,7 +374,7 @@ (shape-wrapper-factory objects))] [:& (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) :view-box vbox :width (ust/format-precision width viewbox-decimal-precision) @@ -439,20 +438,16 @@ :group [:& group-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} - [props] - (let [data (obj/get props "data") - children (obj/get props "children") - render-embed? (obj/get props "render-embed?") - 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?} + [{:keys [data children embed include-metadata source]}] + (let [source (keyword (d/nilv source "components"))] + [:& (mf/provider embed/context) {:value embed} + [:& (mf/provider export/include-metadata-ctx) {:value include-metadata} [:svg {:version "1.1" :xmlns "http://www.w3.org/2000/svg" :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")} :fill "none"} [:defs @@ -511,7 +506,7 @@ (->> (rx/of data) (rx/map (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))))))) (defn render-components @@ -531,8 +526,8 @@ (->> (rx/of data) (rx/map (fn [data] - (let [elem (mf/element components-sprite-svg - #js {:data data :render-embed? true :include-metadata? true + (let [elem (mf/element components-svg + #js {:data data :embed true :include-metadata true :source (name source)})] (rds/renderToStaticMarkup elem)))))))) diff --git a/frontend/src/app/main/ui/viewer/thumbnails.cljs b/frontend/src/app/main/ui/viewer/thumbnails.cljs index 4dc8c8394..6e8423c76 100644 --- a/frontend/src/app/main/ui/viewer/thumbnails.cljs +++ b/frontend/src/app/main/ui/viewer/thumbnails.cljs @@ -88,7 +88,7 @@ (assoc :thumbnail (get thumbnail-data (dm/str page-id (:id frame)))) (assoc :children-bounds children-bounds)) :objects objects - :show-thumbnails? true}]] + :use-thumbnails true}]] [:div.thumbnail-info [:span.name {:title (:name frame)} (:name frame)]]])) diff --git a/frontend/src/app/render.cljs b/frontend/src/app/render.cljs index 485d72081..1bb1d1387 100644 --- a/frontend/src/app/render.cljs +++ b/frontend/src/app/render.cljs @@ -8,125 +8,54 @@ "The main entry point for UI part needed by the exporter." (:require [app.common.geom.shapes.bounds :as gsb] - [app.common.logging :as l] + [app.common.logging :as log] [app.common.math :as mth] - [app.common.spec :as us] + [app.common.schema :as sm] [app.common.types.components-list :as ctkl] [app.common.uri :as u] [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.repo :as repo] [app.main.store :as st] [app.util.dom :as dom] [app.util.globals :as glob] [beicon.core :as rx] - [clojure.spec.alpha :as s] [cuerdas.core :as str] [garden.core :refer [css]] + [okulary.core :as l] + [potok.core :as ptk] [rumext.v2 :as mf])) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; SETUP -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(log/setup! {:app :info}) -(l/setup! {:app :info}) - -(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! (feat/initialize)) - (init-ui)) - -(defn reinit - [] - (mf/unmount! app-root) - (init-ui)) - -(defn ^:dev/after-load after-load - [] - (reinit)) +(defn- fetch-team + [& {:keys [file-id]}] + (ptk/reify ::fetch-team + ptk/WatchEvent + (watch [_ _ _] + (->> (repo/cmd! :get-team {:file-id file-id}) + (rx/mapcat (fn [team] + (rx/of (du/set-current-team team) + (ptk/data-event ::team-fetched team)))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; COMPONENTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ---- SINGLE OBJECT - -(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)) +(def ^:private ref:objects + (l/derived :objects st/state)) (mf/defc object-svg - [{:keys [page-id file-id share-id object-id render-embed?]}] - (let [components-v2 (feat/use-feature "components/v2") - fetch-state (mf/use-fn - (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)] + {::mf/wrap-props false} + [{:keys [object-id embed]}] + (let [objects (mf/deref ref:objects)] ;; Set the globa CSS to assign the page size, needed for PDF ;; exportation process. - (mf/with-effect [object] - (when object + (mf/with-effect [objects] + (when-let [object (get objects object-id)] (let [{:keys [width height]} (gsb/get-object-bounds [objects] object)] (dom/set-page-style! {:size (str/concat @@ -137,90 +66,107 @@ [:& render/object-svg {:objects objects :object-id object-id - :render-embed? render-embed?}]))) + :embed embed}]))) (mf/defc objects-svg - [{:keys [page-id file-id share-id object-ids render-embed?]}] - (let [components-v2 (feat/use-feature "components/v2") - fetch-state (mf/use-fn - (mf/deps file-id page-id share-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 - :features features})) - (rx/tap (fn [[fonts]] - (when (seq fonts) - (st/emit! (df/fonts-fetched fonts))))) - (rx/map (fn [[_ page]] {:objects (:objects page)})))))) + {::mf/wrap-props false} + [{:keys [object-ids embed]}] + (when-let [objects (mf/deref ref:objects)] + (for [object-id object-ids] + (let [objects (render/adapt-objects-for-shape objects object-id)] + [:& render/object-svg + {:objects objects + :key (str object-id) + :object-id object-id + :embed embed}])))) - {: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 - (for [object-id object-ids] - (let [objects (render/adapt-objects-for-shape objects object-id)] - [:& render/object-svg - {:objects objects - :key (str object-id) - :object-id object-id - :render-embed? render-embed?}]))))) +(def ^:private schema:render-objects + [:map {:title "render-objets"} + [:page-id ::sm/uuid] + [:file-id ::sm/uuid] + [:share-id {:optional true} ::sm/uuid] + [:embed {:optional true} :boolean] + [:object-id + [:or + ::sm/uuid + ::sm/coll-of-uuid]]]) -(s/def ::page-id ::us/uuid) -(s/def ::file-id ::us/uuid) -(s/def ::share-id ::us/uuid) -(s/def ::object-id - (s/or :single ::us/uuid - :multiple (s/coll-of ::us/uuid))) -(s/def ::embed ::us/boolean) +(def ^:private render-objects-decoder + (sm/lazy-decoder schema:render-objects + sm/default-transformer)) -(s/def ::render-objects - (s/keys :req-un [::file-id ::page-id ::object-id] - :opt-un [::render-embed ::share-id])) +(def ^:private render-objects-validator + (sm/lazy-validator schema:render-objects)) (defn- render-objects [params] - (let [{:keys [file-id - page-id - render-embed - share-id] - :as params} - (us/conform ::render-objects params) + (let [{:keys [file-id page-id embed share-id object-id] :as params} (render-objects-decoder params)] + (if-not (render-objects-validator params) + (do + (js/console.error "invalid arguments") + (sm/pretty-explain schema:render-objects params) + nil) - [type object-id] (:object-id params)] - (case type - :single - (mf/html - [:& object-svg - {:file-id file-id - :page-id page-id - :share-id share-id - :object-id object-id - :render-embed? render-embed}]) + (do + (st/emit! (ptk/reify ::initialize-render-objects + ptk/WatchEvent + (watch [_ _ stream] + (rx/merge + (rx/of (fetch-team :file-id file-id)) - :multiple - (mf/html - [:& objects-svg - {:file-id file-id - :page-id page-id - :share-id share-id - :object-ids (into #{} object-id) - :render-embed? render-embed}])))) + (->> stream + (rx/filter (ptk/type? ::team-fetched)) + (rx/observe-on :async) + (rx/map (constantly params)) + (rx/map fetch-objects-bundle)))))) + + (if (uuid? object-id) + (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 -(mf/defc components-sprite-svg - [{:keys [file-id embed] :as props}] - (let [fetch (mf/use-fn - (mf/deps file-id) - (fn [] (repo/cmd! :get-file {:id file-id}))) - - file (use-resource fetch) - state (mf/use-state nil)] - - (when file +(mf/defc components-svg + {::mf/wrap-props false} + [{:keys [embed component-id]}] + (let [file-ref (mf/with-memo [] (l/derived :file st/state)) + state (mf/use-state {:component-id component-id})] + (when-let [file (mf/deref file-ref)] [:* [:style (css [[:body @@ -266,7 +212,7 @@ [:a {:on-click on-click} (:name data)]]))] [:main - [:& render/components-sprite-svg + [:& render/components-svg {:data (:data file) :embed embed} @@ -275,16 +221,93 @@ ]))) -(s/def ::component-id ::us/uuid) -(s/def ::render-components - (s/keys :req-un [::file-id] - :opt-un [::embed ::component-id])) +(defn- fetch-components-bundle + [& {:keys [file-id]}] + (ptk/reify ::fetch-components-bundle + 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 [params] - (let [{:keys [file-id component-id embed]} (us/conform ::render-components params)] - (mf/html - [:& components-sprite-svg - {:file-id file-id - :component-id component-id - :embed embed}]))) + (let [{:keys [file-id component-id embed] :as params} (render-components-decoder params)] + (if-not (render-components-validator params) + (do + (js/console.error "invalid arguments") + (sm/pretty-explain schema:render-components params) + 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)) + + + diff --git a/frontend/src/app/worker/thumbnails.cljs b/frontend/src/app/worker/thumbnails.cljs index 56437a3d8..3e3cbbfef 100644 --- a/frontend/src/app/worker/thumbnails.cljs +++ b/frontend/src/app/worker/thumbnails.cljs @@ -63,8 +63,8 @@ (let [objects (:objects page) frame (some->> page :thumbnail-frame-id (get objects)) element (if frame - (mf/element render/frame-svg #js {:objects objects :frame frame :show-thumbnails? true}) - (mf/element render/page-svg #js {:data page :thumbnails? true :render-embed? true})) + (mf/element render/frame-svg #js {:objects objects :frame frame :use-thumbnails true}) + (mf/element render/page-svg #js {:data page :use-thumbnails true :embed true})) data (rds/renderToStaticMarkup element)] {:data data :fonts @fonts/loaded-hints