mirror of
https://github.com/penpot/penpot.git
synced 2025-07-30 21:28:30 +02:00
🎉 Add media-object lifecycle handling.
This commit is contained in:
parent
93aaa52e73
commit
c0cd0d4a23
39 changed files with 975 additions and 323 deletions
|
@ -23,4 +23,9 @@
|
|||
(def login-with-ldap lwl)
|
||||
(def worker-uri wuri)
|
||||
(def public-uri puri)
|
||||
(def media-uri (str puri "/media"))
|
||||
(def default-theme "default")))
|
||||
|
||||
(defn resolve-media-path
|
||||
[path]
|
||||
(str media-uri "/" path))
|
||||
|
|
|
@ -534,7 +534,8 @@
|
|||
shape (-> (cp/make-minimal-shape type)
|
||||
(merge data)
|
||||
(geom/resize width height)
|
||||
(geom/absolute-move (gpt/point x y)))]
|
||||
(geom/absolute-move (gpt/point x y))
|
||||
(geom/transform-shape))]
|
||||
|
||||
(rx/of (add-shape shape))))))
|
||||
|
||||
|
@ -1177,8 +1178,13 @@
|
|||
(ptk/reify ::paste-bin-impl
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [file-id (get-in state [:workspace-page :file-id])]
|
||||
(rx/of (dwp/upload-media-objects file-id true [image] image-uploaded))))))
|
||||
(let [file-id (get-in state [:workspace-page :file-id])
|
||||
params {:file-id file-id
|
||||
:local? true
|
||||
:js-files [image]}]
|
||||
(rx/of (dwp/upload-media-objects
|
||||
(with-meta params
|
||||
{:on-success image-uploaded})))))))
|
||||
|
||||
(def paste
|
||||
(ptk/reify ::paste
|
||||
|
@ -1436,7 +1442,6 @@
|
|||
(def fetch-shared-files dwp/fetch-shared-files)
|
||||
(def link-file-to-library dwp/link-file-to-library)
|
||||
(def unlink-file-from-library dwp/unlink-file-from-library)
|
||||
(def add-media-object-from-url dwp/add-media-object-from-url)
|
||||
(def upload-media-objects dwp/upload-media-objects)
|
||||
(def delete-media-object dwp/delete-media-object)
|
||||
(def rename-page dwp/rename-page)
|
||||
|
|
|
@ -434,92 +434,83 @@
|
|||
|
||||
;; --- Upload local media objects
|
||||
|
||||
(declare upload-media-objects-result)
|
||||
(s/def ::local? ::us/boolean)
|
||||
(s/def ::uri ::us/string)
|
||||
|
||||
(defn add-media-object-from-url
|
||||
([file-id is-local url] (add-media-object-from-url file-id is-local url identity))
|
||||
([file-id is-local url on-added]
|
||||
(us/verify ::us/url url)
|
||||
(us/verify fn? on-added)
|
||||
(us/verify ::us/boolean is-local)
|
||||
(ptk/reify ::add-media-object-from-url
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [on-success #(do (di/notify-finished-loading)
|
||||
(on-added %))
|
||||
|
||||
on-error #(do (di/notify-finished-loading)
|
||||
(di/process-error %))
|
||||
|
||||
is-library (not= file-id (:id (:workspace-file state)))
|
||||
|
||||
prepare
|
||||
(fn [url]
|
||||
{:file-id file-id
|
||||
:is-local is-local
|
||||
:url url})]
|
||||
|
||||
(di/notify-start-loading)
|
||||
|
||||
(->> (rx/of url)
|
||||
(rx/map prepare)
|
||||
(rx/mapcat #(rp/mutation! :add-media-object-from-url %))
|
||||
(rx/do on-success)
|
||||
(rx/map (partial upload-media-objects-result file-id is-local is-library))
|
||||
(rx/catch on-error)))))))
|
||||
(s/def ::upload-media-objects-params
|
||||
(s/keys :req-un [::file-id ::local?]
|
||||
:opt-un [::uri ::di/js-files]))
|
||||
|
||||
(defn upload-media-objects
|
||||
([file-id is-local js-files] (upload-media-objects file-id is-local js-files identity))
|
||||
([file-id is-local js-files on-uploaded]
|
||||
(us/verify ::us/uuid file-id)
|
||||
(us/verify ::us/boolean is-local)
|
||||
(us/verify ::di/js-files js-files)
|
||||
(us/verify fn? on-uploaded)
|
||||
[{:keys [file-id local? js-files uri] :as params}]
|
||||
(us/assert ::upload-media-objects-params params)
|
||||
(ptk/reify ::upload-media-objects
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [on-success #(do (di/notify-finished-loading)
|
||||
(on-uploaded %))
|
||||
|
||||
on-error #(do (di/notify-finished-loading)
|
||||
(di/process-error %))
|
||||
(let [{:keys [on-success on-error]
|
||||
:or {on-success identity}} (meta params)
|
||||
|
||||
is-library (not= file-id (:id (:workspace-file state)))
|
||||
|
||||
prepare
|
||||
prepare-js-file
|
||||
(fn [js-file]
|
||||
{:name (.-name js-file)
|
||||
:file-id file-id
|
||||
:content js-file
|
||||
:is-local is-local})]
|
||||
:is-local local?})
|
||||
|
||||
(di/notify-start-loading)
|
||||
prepare-uri
|
||||
(fn [uri]
|
||||
{:file-id file-id
|
||||
:is-local local?
|
||||
:url uri})
|
||||
|
||||
(->> (rx/from js-files)
|
||||
(rx/map di/validate-file)
|
||||
(rx/map prepare)
|
||||
(rx/mapcat #(rp/mutation! :upload-media-object %))
|
||||
(rx/do on-success)
|
||||
(rx/map (partial upload-media-objects-result file-id is-local is-library))
|
||||
(rx/catch on-error)))))))
|
||||
assoc-to-library
|
||||
(fn [media-object state]
|
||||
(cond
|
||||
(true? local?)
|
||||
state
|
||||
|
||||
(defn upload-media-objects-result
|
||||
[file-id is-local is-library media-object]
|
||||
(us/verify ::us/uuid file-id)
|
||||
(us/verify ::us/boolean is-local)
|
||||
(us/verify ::cm/media-object media-object)
|
||||
(ptk/reify ::upload-media-objects-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(if is-local ;; the media-object is local to the file, not for its library
|
||||
state
|
||||
(if is-library ;; the file is not the currently editing one, but a linked shared file
|
||||
(update-in state
|
||||
[:workspace-libraries file-id :media-objects]
|
||||
#(conj % media-object))
|
||||
(update-in state
|
||||
[:workspace-file :media-objects]
|
||||
#(conj % media-object)))))))
|
||||
(true? is-library)
|
||||
(update-in state
|
||||
[:workspace-libraries file-id :media-objects]
|
||||
#(conj % media-object))
|
||||
|
||||
:else
|
||||
(update-in state
|
||||
[:workspace-file :media-objects]
|
||||
#(conj % media-object))))]
|
||||
|
||||
(rx/concat
|
||||
(rx/of (dm/show {:content (tr "media.loading")
|
||||
:type :info
|
||||
:timeout nil}))
|
||||
(->> (if (string? uri)
|
||||
(->> (rx/of uri)
|
||||
(rx/map prepare-uri)
|
||||
(rx/mapcat #(rp/mutation! :add-media-object-from-url %)))
|
||||
(->> (rx/from js-files)
|
||||
(rx/map di/validate-file)
|
||||
(rx/map prepare-js-file)
|
||||
(rx/mapcat #(rp/mutation! :upload-media-object %))))
|
||||
(rx/do on-success)
|
||||
(rx/map (fn [mobj] (partial assoc-to-library mobj)))
|
||||
(rx/catch (fn [error]
|
||||
(cond
|
||||
(= (:code error) :media-type-not-allowed)
|
||||
(rx/of (dm/error (tr "errors.media-type-not-allowed")))
|
||||
|
||||
(= (:code error) :media-type-mismatch)
|
||||
(rx/of (dm/error (tr "errors.media-type-mismatch")))
|
||||
|
||||
(fn? on-error)
|
||||
(do
|
||||
(on-error error)
|
||||
(rx/empty))
|
||||
|
||||
:else
|
||||
(rx/throw error))))
|
||||
(rx/finalize (fn []
|
||||
(st/emit! dm/hide)))))))))
|
||||
|
||||
|
||||
;; --- Delete media object
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
(ns uxbox.main.ui.shapes.image
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.common.geom.shapes :as geom]
|
||||
[uxbox.main.ui.shapes.attrs :as attrs]
|
||||
[uxbox.util.object :as obj]))
|
||||
|
@ -20,8 +21,7 @@
|
|||
(let [shape (unchecked-get props "shape")
|
||||
{:keys [id x y width height rotation metadata]} shape
|
||||
transform (geom/transform-matrix shape)
|
||||
uri (:uri metadata)
|
||||
|
||||
uri (cfg/resolve-media-path (:path metadata))
|
||||
props (-> (attrs/extract-style-attrs shape)
|
||||
(obj/merge!
|
||||
#js {:x x
|
||||
|
|
|
@ -36,15 +36,20 @@
|
|||
on-uploaded
|
||||
(fn [{:keys [id name] :as image}]
|
||||
(let [shape {:name name
|
||||
:metadata {:width (:width image)
|
||||
:metadata {:width (:width image)
|
||||
:height (:height image)
|
||||
:uri (:uri image)}}
|
||||
:id (:id image)
|
||||
:path (:path image)}}
|
||||
aspect-ratio (/ (:width image) (:height image))]
|
||||
(st/emit! (dw/create-and-add-shape :image shape aspect-ratio))))
|
||||
|
||||
on-files-selected
|
||||
(fn [js-files]
|
||||
(st/emit! (dw/upload-media-objects (:id file) true js-files on-uploaded)))]
|
||||
(st/emit! (dw/upload-media-objects
|
||||
(with-meta {:file-id (:id file)
|
||||
:local? true
|
||||
:js-files js-files}
|
||||
{:on-success on-uploaded}))))]
|
||||
|
||||
[:aside.left-toolbar
|
||||
[:div.left-toolbar-inside
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
[okulary.core :as l]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.config :as cfg]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.common.media :as cm]
|
||||
[uxbox.common.pages :as cp]
|
||||
|
@ -82,7 +83,10 @@
|
|||
|
||||
on-files-selected
|
||||
(fn [js-files]
|
||||
(st/emit! (dw/upload-media-objects file-id false js-files)))
|
||||
(let [params {:file-id file-id
|
||||
:local? false
|
||||
:js-files js-files}]
|
||||
(st/emit! (dw/upload-media-objects params))))
|
||||
|
||||
on-context-menu
|
||||
(fn [object-id]
|
||||
|
@ -98,10 +102,9 @@
|
|||
:object-id object-id)))))
|
||||
|
||||
on-drag-start
|
||||
(fn [uri]
|
||||
(fn [event]
|
||||
(dnd/set-data! event "text/uri-list" uri)
|
||||
(dnd/set-allowed-effect! event "move")))]
|
||||
(fn [path event]
|
||||
(dnd/set-data! event "text/uri-list" (cfg/resolve-media-path path))
|
||||
(dnd/set-allowed-effect! event "move"))]
|
||||
|
||||
[:div.asset-group
|
||||
[:div.group-title
|
||||
|
@ -115,22 +118,23 @@
|
|||
:input-ref file-input
|
||||
:on-selected on-files-selected}]])]
|
||||
[:div.group-grid
|
||||
(for [object media-objects]
|
||||
[:div.grid-cell {:key (:id object)
|
||||
:draggable true
|
||||
:on-context-menu (on-context-menu (:id object))
|
||||
:on-drag-start (on-drag-start (:uri object))}
|
||||
[:img {:src (:thumb-uri object)
|
||||
:draggable false}] ;; Also need to add css pointer-events: none
|
||||
[:div.cell-name (:name object)]])
|
||||
(when local-library?
|
||||
[:& context-menu
|
||||
{:selectable false
|
||||
:show (:menu-open @state)
|
||||
:on-close #(swap! state assoc :menu-open false)
|
||||
:top (:top @state)
|
||||
:left (:left @state)
|
||||
:options [[(tr "workspace.assets.delete") delete-graphic]]}])]]))
|
||||
(for [object media-objects]
|
||||
[:div.grid-cell {:key (:id object)
|
||||
:draggable true
|
||||
:on-context-menu (on-context-menu (:id object))
|
||||
:on-drag-start (partial on-drag-start (:path object))}
|
||||
[:img {:src (cfg/resolve-media-path (:thumb-path object))
|
||||
:draggable false}] ;; Also need to add css pointer-events: none
|
||||
[:div.cell-name (:name object)]])
|
||||
|
||||
(when local-library?
|
||||
[:& context-menu
|
||||
{:selectable false
|
||||
:show (:menu-open @state)
|
||||
:on-close #(swap! state assoc :menu-open false)
|
||||
:top (:top @state)
|
||||
:left (:left @state)
|
||||
:options [[(tr "workspace.assets.delete") delete-graphic]]}])]]))
|
||||
|
||||
|
||||
(mf/defc color-item
|
||||
|
@ -287,7 +291,7 @@
|
|||
[:a {:href (str "#" library-url) :target "_blank"} i/chain]]])]
|
||||
(when @open?
|
||||
(let [show-graphics (and (or (= box-filter :all) (= box-filter :graphics))
|
||||
(or (> (count media-objects) 0) (str/empty? search-term)))
|
||||
(or (> (count media-objects) 0) (str/empty? search-term)))
|
||||
show-colors (and (or (= box-filter :all) (= box-filter :colors))
|
||||
(or (> (count colors) 0) (str/empty? search-term)))]
|
||||
[:div.tool-window-content
|
||||
|
|
|
@ -349,12 +349,15 @@
|
|||
(dnd/has-type? e "text/uri-list"))
|
||||
(dom/prevent-default e)))
|
||||
|
||||
;; TODO: seems duplicated callback is the same as one located
|
||||
;; in left_toolbar
|
||||
on-uploaded
|
||||
(fn [{:keys [id name] :as image}]
|
||||
(let [shape {:name name
|
||||
:metadata {:width (:width image)
|
||||
:height (:height image)
|
||||
:uri (:uri image)}}
|
||||
:id (:id image)
|
||||
:path (:path image)}}
|
||||
aspect-ratio (/ (:width image) (:height image))]
|
||||
(st/emit! (dw/create-and-add-shape :image shape aspect-ratio))))
|
||||
|
||||
|
@ -379,11 +382,23 @@
|
|||
urls (filter #(and (not (str/blank? %))
|
||||
(not (str/starts-with? % "#")))
|
||||
lines)]
|
||||
(run! #(st/emit! (dw/add-media-object-from-url (:id file) true % on-uploaded)) urls))
|
||||
(->> urls
|
||||
(map (fn [uri]
|
||||
(with-meta {:file-id (:id file)
|
||||
:local? true
|
||||
:uri uri}
|
||||
{:on-success on-uploaded})))
|
||||
(map dw/upload-media-objects)
|
||||
(apply st/emit!)))
|
||||
|
||||
:else
|
||||
(let [js-files (dnd/get-files event)]
|
||||
(st/emit! (dw/upload-media-objects (:id file) true js-files on-uploaded)))))
|
||||
(let [js-files (dnd/get-files event)
|
||||
params {:file-id (:id file)
|
||||
:local? true
|
||||
:js-files js-files}]
|
||||
(st/emit! (dw/upload-media-objects
|
||||
(with-meta params
|
||||
{:on-success on-uploaded}))))))
|
||||
|
||||
on-resize
|
||||
(fn [event]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue