From f639c73d0333d6574a3bfbb3fda97d2a9e37b0d0 Mon Sep 17 00:00:00 2001 From: Aitor Date: Thu, 14 Sep 2023 15:57:21 +0200 Subject: [PATCH] :tada: Add component thumbnails --- frontend/src/app/main/data/workspace.cljs | 4 + .../app/main/data/workspace/libraries.cljs | 88 ++++++++++++++----- .../app/main/data/workspace/thumbnails.cljs | 2 +- .../workspace/sidebar/assets/components.cljs | 52 +++++++++-- 4 files changed, 115 insertions(+), 31 deletions(-) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 25ed07ac5..94baaaf30 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -225,6 +225,10 @@ (fn [{:keys [id data] :as file}] (->> (resolve-file-data id data) (rx/map (fn [data] (assoc file :data data)))))) + (rx/merge-map + (fn [{:keys [id] :as file}] + (->> (rp/cmd! :get-file-object-thumbnails {:file-id id}) + (rx/map #(assoc file :thumbnails %))))) (rx/reduce conj []) (rx/map libraries-fetched))) (rx/of (with-meta (workspace-initialized) {:file-id id}))) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 13a6f7483..ebfd1db86 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -33,6 +33,7 @@ [app.main.data.workspace.selection :as dws] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.state-helpers :as wsh] + [app.main.data.workspace.thumbnails :as dwt] [app.main.data.workspace.undo :as dwu] [app.main.features :as features] [app.main.refs :as refs] @@ -309,7 +310,10 @@ (when-not (empty? (:redo-changes changes)) (rx/of (dch/commit-changes changes) (dws/select-shapes (d/ordered-set (:id root))) - (ptk/data-event :layout/update parents))))))))) + (ptk/data-event :layout/update parents) + (dwt/update-thumbnail file-id page-id (:id root)))))))))) + + (defn add-component "Add a new component to current file library, from the currently selected shapes. @@ -444,14 +448,17 @@ (let [data (get state :workspace-data)] (if (features/active-feature? state :components-v2) (let [component (ctkl/get-component data id) - page (ctf/get-component-page data component) - shape (ctf/get-component-root data component)] - (rx/of (dwsh/delete-shapes (:id page) #{(:id shape)}))) ;; Deleting main root triggers component delete + page-id (:main-instance-page component) + root-id (:main-instance-id component)] + (rx/of + (dwt/clear-thumbnail (:current-file-id state) page-id root-id) + (dwsh/delete-shapes page-id #{root-id}))) ;; Deleting main root triggers component delete (let [changes (-> (pcb/empty-changes it) (pcb/with-library-data data) (pcb/delete-component id))] (rx/of (dch/commit-changes changes)))))))) + (defn restore-component "Restore a deleted component, with the given id, in the given file library." [library-id component-id] @@ -492,7 +499,7 @@ (let [page (wsh/lookup-page state) libraries (wsh/get-libraries state) - objects (:objects page) + objects (:objects page) changes (-> (pcb/empty-changes it (:id page)) (pcb/with-objects objects)) @@ -568,17 +575,24 @@ :query-params query-params})))))) (defn ext-library-changed - [file-id modified-at revn changes] - (dm/assert! (uuid? file-id)) + [library-id modified-at revn changes] + (dm/assert! (uuid? library-id)) (dm/assert! (ch/valid-changes? changes)) (ptk/reify ::ext-library-changed ptk/UpdateEvent (update [_ state] (-> state - (update-in [:workspace-libraries file-id] + (update-in [:workspace-libraries library-id] assoc :modified-at modified-at :revn revn) - (d/update-in-when [:workspace-libraries file-id :data] - cp/process-changes changes))))) + (d/update-in-when [:workspace-libraries library-id :data] + cp/process-changes changes))) + + ptk/WatchEvent + (watch [_ _ _] + (->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id}) + (rx/map (fn [thumbnails] + (fn [state] + (assoc-in state [:workspace-libraries library-id :thumbnails] thumbnails)))))))) (defn reset-component "Cancels all modifications in the shape with the given id, and all its children, in @@ -703,12 +717,29 @@ (watch [_ state _] (let [current-file-id (:current-file-id state) undo-id (js/Symbol)] - (rx/of - (dwu/start-undo-transaction undo-id) - (sync-file current-file-id file-id :components component-id undo-group) - (when (not= current-file-id file-id) - (sync-file file-id file-id :components component-id undo-group)) - (dwu/commit-undo-transaction undo-id))))))) + (rx/of + (dwu/start-undo-transaction undo-id) + (sync-file current-file-id file-id :components component-id undo-group) + (when (not= current-file-id file-id) + (sync-file file-id file-id :components component-id undo-group)) + (dwu/commit-undo-transaction undo-id))))))) + +(defn update-component-thumbnail + "Update the thumbnail of the component with the given id, in the + current file and in the imported libraries." + [component-id file-id] + (ptk/reify ::update-component-thumbnail + ptk/WatchEvent + (watch [_ state _] + (let [data (get state :workspace-data) + component (ctkl/get-component data component-id) + page-id (:main-instance-page component) + root-id (:main-instance-id component) + current-file-id (:current-file-id state)] + (rx/of + (dwt/update-thumbnail current-file-id page-id root-id) + (when (not= current-file-id file-id) + (dwt/update-thumbnail file-id page-id root-id))))))) (defn update-component-in-bulk [shapes file-id] @@ -717,9 +748,9 @@ (watch [_ _ _] (let [undo-id (js/Symbol)] (rx/concat - (rx/of (dwu/start-undo-transaction undo-id)) - (rx/map #(update-component-sync (:id %) file-id (uuid/next)) (rx/from shapes)) - (rx/of (dwu/commit-undo-transaction undo-id))))))) + (rx/of (dwu/start-undo-transaction undo-id)) + (rx/map #(update-component-sync (:id %) file-id (uuid/next)) (rx/from shapes)) + (rx/of (dwu/commit-undo-transaction undo-id))))))) (def valid-asset-types #{:colors :components :typographies}) @@ -866,6 +897,17 @@ :callback do-dismiss}] :tag :sync-dialog))))))) +(defn component-changed + "Notify that the component with the given id has changed, so it needs to be updated + in the current file and in the copies. And also update its thumbnails." + [component-id file-id undo-group] + (ptk/reify ::component-changed + ptk/WatchEvent + (watch [_ _ _] + (rx/of + (launch-component-sync component-id file-id undo-group) + (update-component-thumbnail component-id file-id))))) + (defn watch-component-changes "Watch the state for changes that affect to any main instance. If a change is detected will throw an update-component-sync, so changes are immediately propagated to the component and copies." @@ -912,7 +954,7 @@ :undo-group undo-group) (->> changed-components - (map #(launch-component-sync % (:id old-data) undo-group)) + (map #(component-changed % (:id old-data) undo-group)) (run! st/emit!))))))] (when components-v2? @@ -986,7 +1028,11 @@ (->> (rp/cmd! :get-file {:id library-id :features features}) (rx/map (fn [file] (fn [state] - (assoc-in state [:workspace-libraries library-id] file)))))))))) + (assoc-in state [:workspace-libraries library-id] file))))) + (->> (rp/cmd! :get-file-object-thumbnails {:file-id library-id}) + (rx/map (fn [thumbnails] + (fn [state] + (assoc-in state [:workspace-libraries library-id :thumbnails] thumbnails)))))))))) (defn unlink-file-from-library [file-id library-id] diff --git a/frontend/src/app/main/data/workspace/thumbnails.cljs b/frontend/src/app/main/data/workspace/thumbnails.cljs index d2a765050..67f908671 100644 --- a/frontend/src/app/main/data/workspace/thumbnails.cljs +++ b/frontend/src/app/main/data/workspace/thumbnails.cljs @@ -47,7 +47,7 @@ (rx/tap #(l/dbg :hint "thumbnail rendered" :elapsed (dm/str (tp) "ms")))))) -(defn- clear-thumbnail +(defn clear-thumbnail ([file-id page-id frame-id] (clear-thumbnail file-id (fmt-object-id file-id page-id frame-id))) ([file-id object-id] diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs index d3a819425..736b78d47 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/components.cljs @@ -17,6 +17,7 @@ [app.main.data.workspace :as dw] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.media :as dwm] + [app.main.data.workspace.thumbnails :as dwt] [app.main.data.workspace.undo :as dwu] [app.main.refs :as refs] [app.main.render :refer [component-svg]] @@ -45,11 +46,40 @@ (if components-v2 (ctf/get-component-page data component) component)]) - (let [data (dm/get-in @refs/workspace-libraries [file-id :data])] - [(ctf/get-component-root data component) - (if components-v2 - (ctf/get-component-page data component) - component)]))) + (let [data (dm/get-in @refs/workspace-libraries [file-id :data]) + root-shape (ctf/get-component-root data component) + container (if components-v2 + (ctf/get-component-page data component) + component)] + [root-shape container]))) + +(defn- get-component-thumbnail-uri + "Returns the component thumbnail uri" + [file-id component] + (let [page-id (:main-instance-page component) + root-id (:main-instance-id component) + object-id (dwt/fmt-object-id file-id page-id root-id)] + (if (= file-id (:id @refs/workspace-file)) + (mf/deref (refs/workspace-thumbnail-by-id object-id)) + (let [thumbnails (dm/get-in @refs/workspace-libraries [file-id :thumbnails (dm/str object-id)])] + thumbnails)))) + +(mf/defc component-item-thumbnail + "Component that renders the thumbnail image or the original SVG." + {::mf/wrap-props false} + [{:keys [file-id root-shape component container]}] + (let [retry (mf/use-state 0) + thumbnail-uri (get-component-thumbnail-uri file-id component)] + (if (some? thumbnail-uri) + [:img {:src thumbnail-uri + :on-error (fn [] + (when (@retry < 3) + (inc retry))) + :loading "lazy" + :decoding "async" + :class (dom/classnames (css :thumbnail) true)}] + [:& component-svg {:root-shape root-shape + :objects (:objects container)}]))) (mf/defc components-item {::mf/wrap-props false} @@ -144,8 +174,10 @@ (when (and (some? root-shape) (some? container)) [:* - [:& component-svg {:root-shape root-shape - :objects (:objects container)}] + [:& component-item-thumbnail {:file-id file-id + :root-shape root-shape + :component component + :container container}] (let [renaming? (= renaming (:id component))] [:* [:& editable-label @@ -184,8 +216,10 @@ (some? container)) [:* (when visible? - [:& component-svg {:root-shape root-shape - :objects (:objects container)}]) + [:& component-item-thumbnail {:file-id file-id + :root-shape root-shape + :component component + :container container}]) (let [renaming? (= renaming (:id component))] [:* [:& editable-label