Set an artboard as the file thumbnail

This commit is contained in:
Pablo Alba 2022-03-04 15:36:17 +01:00
parent a588267fc2
commit 0a04a856da
11 changed files with 150 additions and 26 deletions

View file

@ -1061,6 +1061,36 @@
(let [selected (wsh/lookup-selected state)]
(rx/of (dch/update-shapes selected #(update % :blocked not)))))))
(defn extract-file-thumbnails-from-page
[state selected page]
(let [extract-frames (fn [page-id]
(let [objects (wsh/lookup-page-objects state page-id)]
(cph/get-frames objects)))
page-id (key page)
frames-with-thumbnail (->> (extract-frames page-id)
(filter (comp true? :file-thumbnail))
(map :id)
(remove #(some #{%} selected))
(map #(into {} {:id % :page-id page-id})))]
(when frames-with-thumbnail frames-with-thumbnail)))
(defn toggle-file-thumbnail-selected
[]
(ptk/reify ::toggle-file-thumbnail-selected
ptk/WatchEvent
(watch [_ state _]
(let [selected (wsh/lookup-selected state)
pages (get-in state [:workspace-data
:pages-index])
file-thumbnails (->> pages
(mapcat #(extract-file-thumbnails-from-page state selected %)))]
(rx/concat
(rx/from
(for [ft file-thumbnails]
(dch/update-shapes [(:id ft)] #(update % :file-thumbnail not) (:page-id ft) nil)))
(rx/of (dch/update-shapes selected #(update % :file-thumbnail not))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Navigation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -71,9 +71,10 @@
(update :undo-changes conj (assoc change :operations uops)))))
(defn update-shapes
([ids f] (update-shapes ids f nil))
([ids f {:keys [reg-objects? save-undo? attrs ignore-tree]
:or {reg-objects? false save-undo? true attrs nil}}]
([ids f] (update-shapes ids f nil nil))
([ids f keys] (update-shapes ids f nil keys))
([ids f page-id {:keys [reg-objects? save-undo? attrs ignore-tree]
:or {reg-objects? false save-undo? true attrs nil}}]
(us/assert ::coll-of-uuid ids)
(us/assert fn? f)
@ -81,8 +82,8 @@
(ptk/reify ::update-shapes
ptk/WatchEvent
(watch [it state _]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state)
(let [page-id (or page-id (:current-page-id state))
objects (wsh/lookup-page-objects state page-id)
changes {:redo-changes []
:undo-changes []
:origin it
@ -91,8 +92,8 @@
ids (into [] (filter some?) ids)
changes (reduce
#(update-shape-changes %1 page-id objects f attrs %2 (get ignore-tree %2))
changes ids)]
#(update-shape-changes %1 page-id objects f attrs %2 (get ignore-tree %2))
changes ids)]
(when-not (empty? (:redo-changes changes))
(let [reg-objs {:type :reg-objects

View file

@ -358,7 +358,12 @@
:toggle-focus-mode {:command "f"
:tooltip "F"
:fn #(st/emit! (dw/toggle-focus-mode))}})
:fn #(st/emit! (dw/toggle-focus-mode))}
:thumbnail-set {:tooltip (ds/shift "T")
:command "shift+t"
:fn #(st/emit! (dw/toggle-file-thumbnail-selected))}})
(def opacity-shortcuts
(into {} (->>

View file

@ -215,6 +215,31 @@
[:& shape-wrapper {:shape item
:key (:id item)}])))]]]))
(mf/defc file-thumbnail-svg
{::mf/wrap [mf/memo]}
[{:keys [data embed? include-metadata?] :as props
:or {embed? false include-metadata? false}}]
(let [data (assoc data :x 0 :y 0)
vbox (format-viewbox {:width (:width data 0) :height (:height data 0)})
background-color (get-in data [:options :background] default-color)]
[:& (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")
:style {:width "100%"
:height "100%"
:background background-color}}
(when include-metadata?
[:& export/export-page {:options (:options data)}])
[:> shape-container {:shape data}
[:& frame/frame-thumbnail {:shape data}]]]]]))
(mf/defc frame-svg
{::mf/wrap [mf/memo]}
[{:keys [objects frame zoom] :or {zoom 1} :as props}]

View file

@ -38,12 +38,12 @@
(def ^:const CACHE-NAME "penpot")
(def ^:const CACHE-URL "https://penpot.app/cache/")
(defn use-thumbnail-cache
"Creates some hooks to handle the files thumbnails cache"
[file]
(let [cache-url (str CACHE-URL (:id file) "/" (:revn file) ".svg")
get-thumbnail
(mf/use-callback
(mf/deps cache-url)
@ -83,14 +83,12 @@
(if (some? thumb-data)
(rx/of thumb-data)
(->> (wrk/ask! {:cmd :thumbnails/generate
:file-id (:id file)
:page-id (get-in file [:data :pages 0])})
:file-id (:id file)})
(rx/tap cache-thumbnail)))))
;; If we have a problem we delegate to the thumbnail generation
(rx/catch #(wrk/ask! {:cmd :thumbnails/generate
:file-id (:id file)
:page-id (get-in file [:data :pages 0])})))))))
:file-id (:id file)})))))))
(mf/defc grid-item-thumbnail
{::mf/wrap [mf/memo]}

View file

@ -164,6 +164,22 @@
:on-click do-flip-horizontal}]
[:& menu-separator]]))
(mf/defc context-menu-thumbnail
[{:keys [shapes]}]
(let [single? (= (count shapes) 1)
has-frame? (->> shapes (d/seek #(= :frame (:type %))))
is-frame? (and single? has-frame?)
do-toggle-thumbnail (st/emitf (dw/toggle-file-thumbnail-selected))]
(when is-frame?
[:*
(if (every? :file-thumbnail shapes)
[:& menu-entry {:title (tr "workspace.shape.menu.thumbnail-remove")
:on-click do-toggle-thumbnail}]
[:& menu-entry {:title (tr "workspace.shape.menu.thumbnail-set")
:shortcut (sc/get-tooltip :thumbnail-set)
:on-click do-toggle-thumbnail}])
[:& menu-separator]])))
(mf/defc context-menu-group
[{:keys [shapes]}]
@ -436,6 +452,7 @@
[:> context-menu-edit props]
[:> context-menu-layer-position props]
[:> context-menu-flip props]
[:> context-menu-thumbnail props]
[:> context-menu-group props]
[:> context-focus-mode-menu props]
[:> context-menu-path props]

View file

@ -29,11 +29,10 @@
(rx/throw {:type :unexpected
:code (:error response)})))
(defn- request-page
[file-id page-id]
(let [uri (u/join (cfg/get-public-uri) "api/rpc/query/page")
(defn- request-thumbnail
[file-id]
(let [uri (u/join (cfg/get-public-uri) "api/rpc/query/file-data-for-thumbnail")
params {:file-id file-id
:id page-id
:strip-frames-with-thumbnails true}]
(->> (http/send!
{:method :get
@ -45,20 +44,23 @@
(defonce cache (atom {}))
(defn render-page
(defn render-frame
[data ckey]
(let [prev (get @cache ckey)]
(if (= (:data prev) data)
(:result prev)
(let [elem (mf/element render/page-svg #js {:data data :width "290" :height "150" :thumbnails? true})
(let [file-thumbnail (:file-thumbnail data)
elem (if file-thumbnail
(mf/element render/file-thumbnail-svg #js {:data file-thumbnail :width "290" :height "150"})
(mf/element render/page-svg #js {:data data :width "290" :height "150" :thumbnails? true}))
result (rds/renderToStaticMarkup elem)]
(swap! cache assoc ckey {:data data :result result})
result))))
(defmethod impl/handler :thumbnails/generate
[{:keys [file-id page-id] :as message}]
(->> (request-page file-id page-id)
[{:keys [file-id] :as message}]
(->> (request-thumbnail file-id)
(rx/map
(fn [data]
{:svg (render-page data #{file-id page-id})
{:svg (render-frame data #{file-id})
:fonts @fonts/loaded}))))