0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-08 07:50:43 -05:00

Merge pull request #2561 from penpot/hiru-bulk-import-graphics

This commit is contained in:
Andrey Antukh 2022-11-20 20:24:55 +01:00 committed by GitHub
commit 9fd778f9c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 170 additions and 70 deletions

View file

@ -14,7 +14,6 @@
[app.common.geom.proportions :as gpr]
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.rect :as gpsr]
[app.common.logging :as log]
[app.common.pages.changes-builder :as pcb]
[app.common.pages.helpers :as cph]
[app.common.spec :as us]
@ -56,7 +55,6 @@
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.shapes-update-layout :as dwul]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.svg-upload :as svg]
[app.main.data.workspace.thumbnails :as dwth]
[app.main.data.workspace.transforms :as dwt]
[app.main.data.workspace.undo :as dwu]
@ -1604,58 +1602,6 @@
(update [_ state]
(dissoc state :remove-graphics))))
(defn- create-shapes-svg
[file-id objects pos media-obj]
(let [path (cfg/resolve-file-media media-obj)
upload-images
(fn [svg-data]
(->> (svg/upload-images svg-data file-id)
(rx/map #(assoc svg-data :image-data %))))
process-svg
(fn [svg-data]
(let [[shape children]
(svg/create-svg-shapes svg-data pos objects uuid/zero #{} false)]
[shape children]))]
(->> (http/send! {:method :get :uri path :mode :no-cors})
(rx/map :body)
(rx/map #(vector (:name media-obj) %))
(rx/merge-map dwm/svg->clj)
(rx/merge-map upload-images)
(rx/map process-svg)
(rx/catch ; When error downloading media-obj, skip it and continue with next one
#(log/error :hint "error downloading file"
:path path
:name (:name media-obj)
:cause %)))))
(defn- create-shapes-img
[pos {:keys [name width height id mtype] :as media-obj}]
(let [group-shape (cts/make-shape :group
{:x (:x pos)
:y (:y pos)
:width width
:height height}
{:name name
:frame-id uuid/zero
:parent-id uuid/zero})
img-shape (cts/make-shape :image
{:x (:x pos)
:y (:y pos)
:width width
:height height
:metadata {:id id
:width width
:height height
:mtype mtype}}
{:name name
:frame-id uuid/zero
:parent-id (:id group-shape)})]
(rx/of [group-shape [img-shape]])))
(defn- remove-graphic
[it file-data page [index [media-obj pos]]]
(let [process-shapes
@ -1689,8 +1635,9 @@
(dch/commit-changes changes)))
shapes (if (= (:mtype media-obj) "image/svg+xml")
(create-shapes-svg (:id file-data) (:objects page) pos media-obj)
(create-shapes-img pos media-obj))]
(->> (dwm/load-and-parse-svg media-obj)
(rx/mapcat (partial dwm/create-shapes-svg (:id file-data) (:objects page) pos)))
(dwm/create-shapes-img pos media-obj))]
(rx/concat
(rx/of (update-remove-graphics index))

View file

@ -7,11 +7,20 @@
(ns app.main.data.workspace.media
(:require
[app.common.exceptions :as ex]
[app.common.logging :as log]
[app.common.pages.changes-builder :as pcb]
[app.common.spec :as us]
[app.common.types.container :as ctn]
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
[app.common.uuid :as uuid]
[app.config :as cfg]
[app.main.data.media :as dmm]
[app.main.data.messages :as dm]
[app.main.data.workspace.changes :as dch]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.state-helpers :as wsh]
[app.main.data.workspace.svg-upload :as svg]
[app.main.repo :as rp]
[app.main.store :as st]
@ -202,7 +211,6 @@
:on-image #(st/emit! (dwl/add-media %)))]
(process-media-objects params)))
;; TODO: it is really need handle SVG here, looks like it already
;; handled separately
(defn upload-media-workspace
@ -216,6 +224,120 @@
;; --- Upload File Media objects
(defn load-and-parse-svg
"Load the contents of a media-obj of type svg, and parse it
into a clojure structure."
[media-obj]
(let [path (cfg/resolve-file-media media-obj)]
(->> (http/send! {:method :get :uri path :mode :no-cors})
(rx/map :body)
(rx/map #(vector (:name media-obj) %))
(rx/merge-map svg->clj)
(rx/catch ; When error downloading media-obj, skip it and continue with next one
#(log/error :msg (str "Error downloading " (:name media-obj) " from " path)
:hint (ex-message %)
:error %)))))
(defn create-shapes-svg
"Convert svg elements into penpot shapes."
[file-id objects pos svg-data]
(let [upload-images
(fn [svg-data]
(->> (svg/upload-images svg-data file-id)
(rx/map #(assoc svg-data :image-data %))))
process-svg
(fn [svg-data]
(let [[shape children]
(svg/create-svg-shapes svg-data pos objects uuid/zero #{} false)]
[shape children]))]
(->> (upload-images svg-data)
(rx/map process-svg))))
(defn create-shapes-img
"Convert a media object that contains a bitmap image into shapes,
one shape of type :image and one group that contains it."
[pos {:keys [name width height id mtype] :as media-obj}]
(let [group-shape (cts/make-shape :group
{:x (:x pos)
:y (:y pos)
:width width
:height height}
{:name name
:frame-id uuid/zero
:parent-id uuid/zero})
img-shape (cts/make-shape :image
{:x (:x pos)
:y (:y pos)
:width width
:height height
:metadata {:id id
:width width
:height height
:mtype mtype}}
{:name name
:frame-id uuid/zero
:parent-id (:id group-shape)})]
(rx/of [group-shape [img-shape]])))
(defn- add-shapes-and-component
[it file-data page name [shape children]]
(let [page' (reduce #(ctst/add-shape (:id %2) %2 %1 uuid/zero (:parent-id %2) nil false)
page
(cons shape children))
shape' (ctn/get-shape page' (:id shape))
[component-shape component-shapes updated-shapes]
(ctn/make-component-shape shape' (:objects page') (:id file-data) true)
changes (-> (pcb/empty-changes it)
(pcb/with-page page')
(pcb/with-objects (:objects page'))
(pcb/with-library-data file-data)
(pcb/add-objects (cons shape children))
(pcb/add-component (:id component-shape)
""
name
component-shapes
updated-shapes
(:id shape)
(:id page)))]
(dch/commit-changes changes)))
(defn- process-img-component
[media-obj]
(ptk/reify ::process-img-component
ptk/WatchEvent
(watch [it state _]
(let [file-data (wsh/get-local-file state)
page (wsh/lookup-page state)
pos (wsh/viewport-center state)]
(->> (create-shapes-img pos media-obj)
(rx/map (partial add-shapes-and-component it file-data page (:name media-obj))))))))
(defn- process-svg-component
[svg-data]
(ptk/reify ::process-svg-component
ptk/WatchEvent
(watch [it state _]
(let [file-data (wsh/get-local-file state)
page (wsh/lookup-page state)
pos (wsh/viewport-center state)]
(->> (create-shapes-svg (:id file-data) (:objects page) pos svg-data)
(rx/map (partial add-shapes-and-component it file-data page (:name svg-data))))))))
(defn upload-media-components
[params]
(let [params (assoc params
:local? false
:on-image #(st/emit! (process-img-component %))
:on-svg #(st/emit! (process-svg-component %)))]
(process-media-objects params)))
(s/def ::object-id ::us/uuid)
(s/def ::clone-media-objects-params

View file

@ -276,11 +276,6 @@
(dch/commit-changes changes)
(dwsul/update-layout-positions layout-ids)))))))
(defn- viewport-center
[state]
(let [{:keys [x y width height]} (get-in state [:workspace-local :vbox])]
[(+ x (/ width 2)) (+ y (/ height 2))]))
(defn create-and-add-shape
[type frame-x frame-y data]
(ptk/reify ::create-and-add-shape
@ -288,9 +283,9 @@
(watch [_ state _]
(let [{:keys [width height]} data
[vbc-x vbc-y] (viewport-center state)
x (:x data (- vbc-x (/ width 2)))
y (:y data (- vbc-y (/ height 2)))
vbc (wsh/viewport-center state)
x (:x data (- (:x vbc) (/ width 2)))
y (:y data (- (:y vbc) (/ height 2)))
page-id (:current-page-id state)
frame-id (-> (wsh/lookup-page-objects state page-id)
(ctst/top-nested-frame {:x frame-x :y frame-y}))

View file

@ -8,6 +8,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh]
[app.common.pages.helpers :as cph]
[app.common.path.commands :as upc]))
@ -139,3 +140,9 @@
(as-> children $
(d/mapm (set-content-modifiers state) $))))
(defn viewport-center
[state]
(let [{:keys [x y width height]} (get-in state [:workspace-local :vbox])]
(gpt/point (+ x (/ width 2)) (+ y (/ height 2)))))

View file

@ -552,8 +552,9 @@
(mf/defc components-box
[{:keys [file-id local? components listing-thumbs? open? reverse-sort? open-groups selected-assets
on-asset-click on-assets-delete on-clear-selection] :as props}]
(let [state (mf/use-state {:renaming nil
:component-id nil})
(let [input-ref (mf/use-ref nil)
state (mf/use-state {:renaming nil
:component-id nil})
menu-state (mf/use-state auto-pos-menu-state)
@ -566,6 +567,24 @@
groups (group-assets components reverse-sort?)
components-v2 (mf/use-ctx ctx/components-v2)
add-component
(mf/use-fn
(fn []
#(st/emit! (dwl/set-assets-box-open file-id :components true))
(dom/click (mf/ref-val input-ref))))
on-file-selected
(mf/use-fn
(mf/deps file-id)
(fn [blobs]
(let [params {:file-id file-id
:blobs (seq blobs)}]
(st/emit! (dwm/upload-media-components params)
(ptk/event ::ev/event {::ev/name "add-asset-to-library"
:asset-type "components"})))))
on-duplicate
(mf/use-fn
(mf/deps @state)
@ -694,6 +713,16 @@
:box :components
:assets-count (count components)
:open? open?}
(when local?
[:& asset-section-block {:role :title-button}
(when components-v2
[:div.assets-button {:on-click add-component}
i/plus
[:& file-uploader {:accept cm/str-image-types
:multi true
:ref input-ref
:on-selected on-file-selected}]])])
[:& asset-section-block {:role :content}
[:& components-group {:file-id file-id
:prefix ""
@ -899,9 +928,9 @@
(mf/defc graphics-box
[{:keys [file-id project-id local? objects listing-thumbs? open? open-groups selected-assets reverse-sort?
on-asset-click on-assets-delete on-clear-selection] :as props}]
(let [input-ref (mf/use-ref nil)
state (mf/use-state {:renaming nil
:object-id nil})
(let [input-ref (mf/use-ref nil)
state (mf/use-state {:renaming nil
:object-id nil})
menu-state (mf/use-state auto-pos-menu-state)