0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-02-09 00:28:20 -05:00

Merge pull request #1672 from penpot/set-artboard-as-thumbnail

 Set an artboard as the file thumbnail
This commit is contained in:
Andrey Antukh 2022-03-10 09:27:20 +01:00 committed by GitHub
commit 636dbd4e57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 150 additions and 26 deletions

View file

@ -5,6 +5,7 @@
### :boom: Breaking changes
### :sparkles: New features
- Set an artboard as the file thumbnail [Taiga #1526](https://tree.taiga.io/project/penpot/us/1526)
- Add border radius to our artboars [Taiga #2056](https://tree.taiga.io/project/penpot/us/2056)
- Allow send multiple team invitations at once [Taiga #2798](https://tree.taiga.io/project/penpot/us/2798)
- Persist color palette and color picker across refresh [Taiga #1660](https://tree.taiga.io/project/penpot/issue/1660)

View file

@ -249,6 +249,8 @@
(update :data assoc :pages [page-id]))))
(declare strip-frames-with-thumbnails)
(declare extract-file-thumbnail)
(declare get-first-page-data)
(s/def ::strip-frames-with-thumbnails ::us/boolean)
@ -256,16 +258,37 @@
(s/keys :req-un [::profile-id ::file-id]
:opt-un [::strip-frames-with-thumbnails]))
(s/def ::file-data-for-thumbnail
(s/keys :req-un [::profile-id ::file-id]
:opt-un [::strip-frames-with-thumbnails]))
(sv/defmethod ::file-data-for-thumbnail
"Retrieves the data for generate the thumbnail of the file. Used mainly for render
thumbnails on dashboard."
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as props}]
(check-read-permissions! pool profile-id file-id)
(p/let [file (retrieve-file cfg file-id)
data (get-first-page-data file props)
file-thumbnail (extract-file-thumbnail (get-in file [:data :pages-index]))]
(assoc data :file-thumbnail file-thumbnail)))
(sv/defmethod ::page
"Retrieves the first page of the file. Used mainly for render
thumbnails on dashboard."
[{:keys [pool] :as cfg} {:keys [profile-id file-id] :as props}]
(check-read-permissions! pool profile-id file-id)
(p/let [file (retrieve-file cfg file-id)
page-id (get-in file [:data :pages 0])]
(cond-> (get-in file [:data :pages-index page-id])
(true? (:strip-frames-with-thumbnails props))
(strip-frames-with-thumbnails))))
data (get-first-page-data file props)]
data))
(defn get-first-page-data
[file props]
(let [page-id (get-in file [:data :pages 0])
data (cond-> (get-in file [:data :pages-index page-id])
(true? (:strip-frames-with-thumbnails props))
(strip-frames-with-thumbnails))]
data))
(defn strip-frames-with-thumbnails
"Remove unnecesary shapes from frames that have thumbnail."
@ -295,6 +318,16 @@
(update data :objects update-objects)))
(defn extract-file-thumbnail
"Extract the frame marked as file-thumbnail"
[pages]
(->> pages
vals
(mapcat :objects)
vals
(filter :file-thumbnail)
first))
;; --- Query: Shared Library Files
(def ^:private sql:team-shared-files

View file

@ -959,6 +959,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

@ -364,7 +364,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 show-thumbnails?] :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

@ -165,6 +165,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]}]
@ -437,6 +453,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}))))

View file

@ -3265,6 +3265,12 @@ msgstr "Flip horizontal"
msgid "workspace.shape.menu.flip-vertical"
msgstr "Flip vertical"
msgid "workspace.shape.menu.thumbnail-set"
msgstr "Set as thumbnail"
msgid "workspace.shape.menu.thumbnail-remove"
msgstr "Remove thumbnail"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.flow-start"
msgstr "Flow start"

View file

@ -3279,6 +3279,12 @@ msgstr "Voltear horizontal"
msgid "workspace.shape.menu.flip-vertical"
msgstr "Voltear vertical"
msgid "workspace.shape.menu.thumbnail-set"
msgstr "Poner como miniatura"
msgid "workspace.shape.menu.thumbnail-remove"
msgstr "Quitar miniatura"
#: src/app/main/ui/workspace/context_menu.cljs
msgid "workspace.shape.menu.flow-start"
msgstr "Inicio de flujo"