0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-09 08:20:45 -05:00

🎉 Add component thumbnails

This commit is contained in:
Aitor 2023-09-14 15:57:21 +02:00 committed by Andrés Moya
parent 77964604fd
commit f639c73d03
4 changed files with 115 additions and 31 deletions

View file

@ -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})))

View file

@ -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]

View file

@ -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]

View file

@ -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