diff --git a/backend/src/uxbox/media.clj b/backend/src/uxbox/media.clj index e277c7499..ba58d3574 100644 --- a/backend/src/uxbox/media.clj +++ b/backend/src/uxbox/media.clj @@ -140,7 +140,7 @@ (when (and (string? mtype) (not= mtype mtype')) (ex/raise :type :validation - :code :image-type-mismatch + :code :media-type-mismatch :hint "Seems like you are uploading a file whose content does not match the extension.")) {:width (.getImageWidth instance) :height (.getImageHeight instance) diff --git a/backend/src/uxbox/services/mutations/files.clj b/backend/src/uxbox/services/mutations/files.clj index ec611a42d..974261309 100644 --- a/backend/src/uxbox/services/mutations/files.clj +++ b/backend/src/uxbox/services/mutations/files.clj @@ -42,7 +42,7 @@ (declare create-file) (declare create-page) -(s/def ::is-shared boolean?) +(s/def ::is-shared ::us/boolean) (s/def ::create-file (s/keys :req-un [::profile-id ::name ::project-id ::is-shared] :opt-un [::id])) @@ -188,7 +188,7 @@ ;; [conn {:keys [content file-id name] :as params}] ;; (when-not (imgs/valid-image-types? (:content-type content)) ;; (ex/raise :type :validation -;; :code :image-type-not-allowed +;; :code :media-type-not-allowed ;; :hint "Seems like you are uploading an invalid image.")) ;; ;; (let [info (images/run {:cmd :info :input {:path (:tempfile content) diff --git a/backend/src/uxbox/services/mutations/media.clj b/backend/src/uxbox/services/mutations/media.clj index 942a334ff..88eba0f8c 100644 --- a/backend/src/uxbox/services/mutations/media.clj +++ b/backend/src/uxbox/services/mutations/media.clj @@ -25,8 +25,8 @@ [uxbox.util.time :as dt])) (def thumbnail-options - {:width 800 - :height 800 + {:width 100 + :height 100 :quality 85 :format :jpeg}) @@ -122,7 +122,7 @@ (s/def ::content ::upload) -(s/def ::is-local boolean?) +(s/def ::is-local ::us/boolean) (s/def ::add-media-object-from-url (s/keys :req-un [::profile-id ::file-id ::url ::is-local] @@ -179,18 +179,18 @@ :width (:width info) :height (:height info) :mtype (:mtype info)}) - (media/resolve-urls :path :uri) - (media/resolve-urls :thumb-path :thumb-uri)) + (media/resolve-urls :path :uri)) - media-thumbnail (db/insert! conn :media-thumbnail - {:id (uuid/next) - :media-object-id media-object-id - :path (str (:path thumb)) - :width (:width thumb) - :height (:height thumb) - :quality (:quality thumb) - :mtype (:mtype thumb)})] - media-object)) + media-thumbnail (-> (db/insert! conn :media-thumbnail + {:id (uuid/next) + :media-object-id media-object-id + :path (str (:path thumb)) + :width (:width thumb) + :height (:height thumb) + :quality (:quality thumb) + :mtype (:mtype thumb)}) + (media/resolve-urls :path :uri))] + (assoc media-object :thumb-uri (:uri media-thumbnail)))) (def ^:private sql:select-file-for-update "select file.*, diff --git a/backend/src/uxbox/services/queries/media.clj b/backend/src/uxbox/services/queries/media.clj index 2f220758b..4bb8dede0 100644 --- a/backend/src/uxbox/services/queries/media.clj +++ b/backend/src/uxbox/services/queries/media.clj @@ -77,7 +77,7 @@ (declare retrieve-media-objects) (declare retrieve-file) -(s/def ::is-local boolean?) +(s/def ::is-local ::us/boolean) (s/def ::media-objects (s/keys :req-un [::profile-id ::file-id ::is-local])) @@ -90,15 +90,18 @@ (let [file (retrieve-file conn file-id)] (teams/check-read-permissions! conn profile-id (:team-id file)) (->> (retrieve-media-objects conn file-id is-local) - (mapv #(media/resolve-urls % :path :uri)))))) + (mapv #(media/resolve-urls % :path :uri)) + (mapv #(media/resolve-urls % :thumb-path :thumb-uri)))))) (def ^:private sql:media-objects - "select * - from media_object - where deleted_at is null - and file_id = ? - and is_local = ? - order by created_at desc") + "select obj.*, + thumb.path as thumb_path + from media_object as obj + inner join media_thumbnail as thumb on obj.id = thumb.media_object_id + where obj.deleted_at is null + and obj.file_id = ? + and obj.is_local = ? + order by obj.created_at desc") (defn retrieve-media-objects [conn file-id is-local] diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json index 895ae0439..00c7b3e43 100644 --- a/frontend/resources/locales.json +++ b/frontend/resources/locales.json @@ -737,7 +737,7 @@ "es" : "Ha ocurrido algún error." } }, - "errors.image-format-unsupported" : { + "errors.media-format-unsupported" : { "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:406", "src/uxbox/main/data/users.cljs:177", "src/uxbox/main/data/images.cljs:376" ], "translations" : { "en" : "The image format is not supported (must be svg, jpg or png).", @@ -746,7 +746,7 @@ "es" : "No se reconoce el formato de imagen (debe ser svg, jpg o png)." } }, - "errors.image-too-large" : { + "errors.media-too-large" : { "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:404", "src/uxbox/main/data/users.cljs:175", "src/uxbox/main/data/images.cljs:374" ], "translations" : { "en" : "The image is too large to be inserted (must be under 5mb).", @@ -755,7 +755,7 @@ "es" : "La imagen es demasiado grande (debe tener menos de 5mb)." } }, - "errors.image-type-mismatch" : { + "errors.media-type-mismatch" : { "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:371", "src/uxbox/main/data/workspace/persistence.cljs:421", "src/uxbox/main/data/users.cljs:191", "src/uxbox/main/data/images.cljs:391" ], "translations" : { "en" : "Seems that the contents of the image does not match the file extension.", @@ -764,7 +764,7 @@ "es" : "Parece que el contenido de la imagen no coincide con la etensión del archivo." } }, - "errors.image-type-not-allowed" : { + "errors.media-type-not-allowed" : { "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:368", "src/uxbox/main/data/workspace/persistence.cljs:418", "src/uxbox/main/data/users.cljs:188", "src/uxbox/main/data/images.cljs:388" ], "translations" : { "en" : "Seems that this is not a valid image.", @@ -854,7 +854,7 @@ "es" : "Estás viendo la versión %s" } }, - "image.loading" : { + "media.loading" : { "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:382", "src/uxbox/main/data/workspace/persistence.cljs:433", "src/uxbox/main/data/users.cljs:201", "src/uxbox/main/data/images.cljs:403" ], "translations" : { "en" : "Loading image...", diff --git a/frontend/src/uxbox/main/data/images.cljs b/frontend/src/uxbox/main/data/media.cljs similarity index 56% rename from frontend/src/uxbox/main/data/images.cljs rename to frontend/src/uxbox/main/data/media.cljs index 33e00d05a..d360d30dd 100644 --- a/frontend/src/uxbox/main/data/images.cljs +++ b/frontend/src/uxbox/main/data/media.cljs @@ -4,7 +4,7 @@ ;; ;; Copyright (c) 2016 Andrey Antukh -(ns uxbox.main.data.images +(ns uxbox.main.data.media (:require [cljs.spec.alpha :as s] [cuerdas.core :as str] @@ -30,35 +30,34 @@ (s/def ::modified-at inst?) (s/def ::created-at inst?) (s/def ::mtype string?) -(s/def ::thumbnail string?) +;; (s/def ::thumbnail string?) (s/def ::id uuid?) -(s/def ::url string?) -(s/def ::collection-id uuid?) +(s/def ::uri string?) +;; (s/def ::collection-id uuid?) (s/def ::user-id uuid?) -(s/def ::collection - (s/keys :req-un [::id - ::name - ::created-at - ::modified-at - ::user-id])) +;; (s/def ::collection +;; (s/keys :req-un [::id +;; ::name +;; ::created-at +;; ::modified-at +;; ::user-id])) -(s/def ::image +(s/def ::media-object (s/keys :req-un [::id ::name ::width ::height ::mtype - ::collection-id ::created-at ::modified-at ::uri - ::thumb-uri + ;; ::thumb-uri ::user-id])) ;; ;; --- Initialize Collection Page ;; -;; (declare fetch-images) +;; (declare fetch-media-objects) ;; ;; (defn initialize ;; [collection-id] @@ -66,11 +65,11 @@ ;; (ptk/reify ::initialize ;; ptk/UpdateEvent ;; (update [_ state] -;; (assoc-in state [:dashboard-images :selected] #{})) +;; (assoc-in state [:dashboard-media-objects :selected] #{})) ;; ;; ptk/WatchEvent ;; (watch [_ state stream] -;; (rx/of (fetch-images collection-id))))) +;; (rx/of (fetch-media-objects collection-id))))) ;; ;; ;; --- Fetch Collections ;; @@ -80,7 +79,7 @@ ;; (ptk/reify ::fetch-collections ;; ptk/WatchEvent ;; (watch [_ state s] -;; (->> (rp/query! :image-collections) +;; (->> (rp/query! :media-object-collections) ;; (rx/map collections-fetched))))) ;; ;; @@ -95,7 +94,7 @@ ;; (reduce (fn [state {:keys [id user] :as item}] ;; (let [type (if (uuid/zero? (:user-id item)) :builtin :own) ;; item (assoc item :type type)] -;; (assoc-in state [:images-collections id] item))) +;; (assoc-in state [:media-objects-collections id] item))) ;; state ;; items)))) ;; @@ -109,7 +108,7 @@ ;; ptk/WatchEvent ;; (watch [_ state s] ;; (let [data {:name (tr "ds.default-library-title" (gensym "c"))}] -;; (->> (rp/mutation! :create-image-collection data) +;; (->> (rp/mutation! :create-media-object-collection data) ;; (rx/map collection-created)))))) ;; ;; ;; --- Collection Created @@ -121,7 +120,7 @@ ;; ptk/UpdateEvent ;; (update [_ state] ;; (let [{:keys [id] :as item} (assoc item :type :own)] -;; (update state :images-collections assoc id item))))) +;; (update state :media-objects-collections assoc id item))))) ;; ;; ;; --- Rename Collection ;; @@ -130,12 +129,12 @@ ;; (ptk/reify ::rename-collection ;; ptk/UpdateEvent ;; (update [_ state] -;; (assoc-in state [:images-collections id :name] name)) +;; (assoc-in state [:media-objects-collections id :name] name)) ;; ;; ptk/WatchEvent ;; (watch [_ state s] ;; (let [params {:id id :name name}] -;; (->> (rp/mutation! :rename-image-collection params) +;; (->> (rp/mutation! :rename-media-object-collection params) ;; (rx/ignore)))))) ;; ;; ;; --- Delete Collection @@ -145,141 +144,141 @@ ;; (ptk/reify ::delete-collection ;; ptk/UpdateEvent ;; (update [_ state] -;; (update state :images-collections dissoc id)) +;; (update state :media-objects-collections dissoc id)) ;; ;; ptk/WatchEvent ;; (watch [_ state s] -;; (->> (rp/mutation! :delete-image-collection {:id id}) +;; (->> (rp/mutation! :delete-media-object-collection {:id id}) ;; (rx/tap on-success) ;; (rx/ignore))))) ;; -;; ;; --- Update Image +;; ;; --- Update Media object ;; -;; (defn persist-image +;; (defn persist-media-object ;; [id] ;; (us/verify ::us/uuid id) -;; (ptk/reify ::persist-image +;; (ptk/reify ::persist-media-object ;; ptk/WatchEvent ;; (watch [_ state stream] -;; (let [data (get-in state [:images id])] -;; (->> (rp/mutation! :update-image data) +;; (let [data (get-in state [:media-objects id])] +;; (->> (rp/mutation! :update-media-object data) ;; (rx/ignore)))))) ;; -;; ;; --- Fetch Images +;; ;; --- Fetch Media objects ;; -;; (declare images-fetched) +;; (declare media-objects-fetched) ;; -;; (defn fetch-images -;; "Fetch a list of images of the selected collection" +;; (defn fetch-media-objects +;; "Fetch a list of media-objects of the selected collection" ;; [id] ;; (us/verify ::us/uuid id) -;; (ptk/reify ::fetch-images +;; (ptk/reify ::fetch-media-objects ;; ptk/WatchEvent ;; (watch [_ state s] ;; (let [params {:collection-id id}] -;; (->> (rp/query! :images-by-collection params) -;; (rx/map (partial images-fetched id))))))) +;; (->> (rp/query! :media-objects-by-collection params) +;; (rx/map (partial media-objects-fetched id))))))) ;; -;; ;; --- Images Fetched +;; ;; --- Media objects Fetched ;; -;; (s/def ::images (s/every ::image)) +;; (s/def ::media-objects (s/every ::media-object)) ;; -;; (defn images-fetched +;; (defn media-objects-fetched ;; [collection-id items] ;; (us/verify ::us/uuid collection-id) -;; (us/verify ::images items) -;; (ptk/reify ::images-fetched +;; (us/verify ::media-objects items) +;; (ptk/reify ::media-objects-fetched ;; ptk/UpdateEvent ;; (update [_ state] -;; (let [images (d/index-by :id items)] -;; (assoc state :images images))))) +;; (let [media-objects (d/index-by :id items)] +;; (assoc state :media-objects media-objects))))) ;; -;; ;; --- Fetch Image +;; ;; --- Fetch Media object ;; -;; (declare image-fetched) +;; (declare media-object-fetched) ;; -;; (defrecord FetchImage [id] +;; (defrecord FetchMediaObject [id] ;; ptk/WatchEvent ;; (watch [_ state stream] -;; (let [existing (get-in state [:images id])] +;; (let [existing (get-in state [:media-objects id])] ;; (if existing ;; (rx/empty) -;; (->> (rp/query! :image-by-id {:id id}) -;; (rx/map image-fetched) +;; (->> (rp/query! :media-object-by-id {:id id}) +;; (rx/map media-object-fetched) ;; (rx/catch rp/client-error? #(rx/empty))))))) ;; -;; (defn fetch-image -;; "Conditionally fetch image by its id. If image +;; (defn fetch-media-object +;; "Conditionally fetch media-object by its id. If media-object ;; is already loaded, this event is noop." ;; [id] ;; {:pre [(uuid? id)]} -;; (FetchImage. id)) +;; (FetchMediaObject. id)) ;; -;; ;; --- Image Fetched +;; ;; --- MediaObject Fetched ;; -;; (defrecord ImageFetched [image] +;; (defrecord MediaObjectFetched [media-object] ;; ptk/UpdateEvent ;; (update [_ state] -;; (let [id (:id image)] -;; (update state :images assoc id image)))) +;; (let [id (:id media-object)] +;; (update state :media-objects assoc id media-object)))) ;; -;; (defn image-fetched -;; [image] -;; {:pre [(map? image)]} -;; (ImageFetched. image)) +;; (defn media-object-fetched +;; [media-object] +;; {:pre [(map? media-object)]} +;; (MediaObjectFetched. media-object)) ;; -;; ;; --- Rename Image +;; ;; --- Rename MediaObject ;; -;; (defn rename-image +;; (defn rename-media-object ;; [id name] ;; (us/verify ::us/uuid id) ;; (us/verify ::us/string name) -;; (ptk/reify ::rename-image +;; (ptk/reify ::rename-media-object ;; ptk/UpdateEvent ;; (update [_ state] -;; (assoc-in state [:images id :name] name)) +;; (assoc-in state [:media-objects id :name] name)) ;; ;; ptk/WatchEvent ;; (watch [_ state stream] -;; (rx/of (persist-image id))))) +;; (rx/of (persist-media-object id))))) ;; -;; ;; --- Image Selection +;; ;; --- MediaObject Selection ;; -;; (defn select-image +;; (defn select-media-object ;; [id] -;; (ptk/reify ::select-image +;; (ptk/reify ::select-media-object ;; ptk/UpdateEvent ;; (update [_ state] -;; (update-in state [:dashboard-images :selected] (fnil conj #{}) id)))) +;; (update-in state [:dashboard-media-objects :selected] (fnil conj #{}) id)))) ;; -;; (defn deselect-image +;; (defn deselect-media-object ;; [id] -;; (ptk/reify ::deselect-image +;; (ptk/reify ::deselect-media-object ;; ptk/UpdateEvent ;; (update [_ state] -;; (update-in state [:dashboard-images :selected] (fnil disj #{}) id)))) +;; (update-in state [:dashboard-media-objects :selected] (fnil disj #{}) id)))) ;; -;; (def deselect-all-images -;; (ptk/reify ::deselect-all-images +;; (def deselect-all-media-objects +;; (ptk/reify ::deselect-all-media-objects ;; ptk/UpdateEvent ;; (update [_ state] -;; (assoc-in state [:dashboard-images :selected] #{})))) +;; (assoc-in state [:dashboard-media-objects :selected] #{})))) ;; -;; ;; --- Delete Images +;; ;; --- Delete MediaObjects ;; -;; (defn delete-image +;; (defn delete-media-object ;; [id] ;; (us/verify ::us/uuid id) -;; (ptk/reify ::delete-image +;; (ptk/reify ::delete-media-object ;; ptk/UpdateEvent ;; (update [_ state] -;; (update state :images dissoc id)) +;; (update state :media-objects dissoc id)) ;; ;; ptk/WatchEvent ;; (watch [_ state s] ;; (rx/merge -;; (rx/of deselect-all-images) -;; (->> (rp/mutation! :delete-image {:id id}) +;; (rx/of deselect-all-media-objects) +;; (->> (rp/mutation! :delete-media-object {:id id}) ;; (rx/ignore)))))) ;; ;; ;; --- Delete Selected @@ -288,9 +287,9 @@ ;; (ptk/reify ::delete-selected ;; ptk/WatchEvent ;; (watch [_ state stream] -;; (let [selected (get-in state [:dashboard-images :selected])] +;; (let [selected (get-in state [:dashboard-media-objects :selected])] ;; (->> (rx/from selected) -;; (rx/map delete-image)))))) +;; (rx/map delete-media-object)))))) ;; ;; ;; --- Update Opts (Filtering & Ordering) ;; @@ -300,48 +299,48 @@ ;; (ptk/reify ::update-opts ;; ptk/UpdateEvent ;; (update [_ state] -;; (update state :dashboard-images merge +;; (update state :dashboard-media-objects merge ;; {:edition edition} ;; (when order {:order order}) ;; (when filter {:filter filter}))))) -;; --- Copy Selected Image +;; --- Copy Selected MediaObject ;; (defrecord CopySelected [id] ;; ptk/WatchEvent ;; (watch [_ state stream] -;; (let [selected (get-in state [:dashboard-images :selected])] +;; (let [selected (get-in state [:dashboard-media-objects :selected])] ;; (rx/merge ;; (->> (rx/from selected) -;; (rx/flat-map #(rp/mutation! :copy-image {:id % :collection-id id})) -;; (rx/map image-created)) +;; (rx/flat-map #(rp/mutation! :copy-media-object {:id % :collection-id id})) +;; (rx/map media-object-created)) ;; (->> (rx/from selected) -;; (rx/map deselect-image)))))) +;; (rx/map deselect-media-object)))))) ;; (defn copy-selected ;; [id] ;; {:pre [(or (uuid? id) (nil? id))]} ;; (CopySelected. id)) -;; --- Move Selected Image +;; --- Move Selected MediaObject ;; (defrecord MoveSelected [id] ;; ptk/UpdateEvent ;; (update [_ state] -;; (let [selected (get-in state [:dashboard-images :selected])] -;; (reduce (fn [state image] -;; (assoc-in state [:images image :collection] id)) +;; (let [selected (get-in state [:dashboard-media-objects :selected])] +;; (reduce (fn [state media-object] +;; (assoc-in state [:media-objects media-object :collection] id)) ;; state ;; selected))) ;; ptk/WatchEvent ;; (watch [_ state stream] -;; (let [selected (get-in state [:dashboard-images :selected])] +;; (let [selected (get-in state [:dashboard-media-objects :selected])] ;; (rx/merge ;; (->> (rx/from selected) -;; (rx/map persist-image)) +;; (rx/map persist-media-object)) ;; (->> (rx/from selected) -;; (rx/map deselect-image)))))) +;; (rx/map deselect-media-object)))))) ;; (defn move-selected ;; [id] @@ -351,29 +350,30 @@ ;;;;;;; NEW -;; --- Create Image -(declare create-images-result) +;; --- Create library Media Objects + +(declare create-media-objects-result) (def allowed-file-types #{"image/jpeg" "image/png" "image/webp" "image/svg+xml"}) (def max-file-size (* 5 1024 1024)) -;; TODO: unify with upload-image at main/data/workspace/persistence.cljs +;; TODO: unify with upload-media-object at main/data/workspace/persistence.cljs ;; and update-photo at main/data/users.cljs ;; https://tree.taiga.io/project/uxboxproject/us/440 -(defn create-images - ([file-id files] (create-images file-id files identity)) +(defn create-media-objects + ([file-id files] (create-media-objects file-id files identity)) ([file-id files on-uploaded] (us/verify (s/nilable ::us/uuid) file-id) (us/verify fn? on-uploaded) - (ptk/reify ::create-images + (ptk/reify ::create-media-objects ptk/WatchEvent (watch [_ state stream] (let [check-file (fn [file] (when (> (.-size file) max-file-size) - (throw (ex-info (tr "errors.image-too-large") {}))) + (throw (ex-info (tr "errors.media-too-large") {}))) (when-not (contains? allowed-file-types (.-type file)) - (throw (ex-info (tr "errors.image-format-unsupported") {}))) + (throw (ex-info (tr "errors.media-format-unsupported") {}))) file) on-success #(do (st/emit! dm/hide) @@ -384,11 +384,11 @@ (.-message %) (.-message %) - (= (:code %) :image-type-not-allowed) - (tr "errors.image-type-not-allowed") + (= (:code %) :media-type-not-allowed) + (tr "errors.media-type-not-allowed") - (= (:code %) :image-type-mismatch) - (tr "errors.image-type-mismatch") + (= (:code %) :media-type-mismatch) + (tr "errors.media-type-mismatch") :else (tr "errors.unexpected-error"))] @@ -398,30 +398,31 @@ (fn [file] {:name (.-name file) :file-id file-id - :content file})] + :content file + :is-local false})] - (st/emit! (dm/show {:content (tr "image.loading") + (st/emit! (dm/show {:content (tr "media.loading") :type :info :timeout nil})) (->> (rx/from files) (rx/map check-file) (rx/map prepare) - (rx/mapcat #(rp/mutation! :upload-image %)) + (rx/mapcat #(rp/mutation! :upload-media-object %)) (rx/reduce conj []) (rx/do on-success) (rx/mapcat identity) - (rx/map (partial create-images-result file-id)) + (rx/map (partial create-media-objects-result file-id)) (rx/catch on-error))))))) -;; --- Image Created +;; --- Media object Created -(defn create-images-result - [file-id image] - #_(us/verify ::image image) - (ptk/reify ::create-images-result +(defn create-media-objects-result + [file-id media-object] + #_(us/verify ::media-object media-object) + (ptk/reify ::create-media-objects-result ptk/UpdateEvent (update [_ state] (-> state - (assoc-in [:workspace-images (:id image)] image))))) + (assoc-in [:workspace-media (:id media-object)] media-object))))) diff --git a/frontend/src/uxbox/main/data/users.cljs b/frontend/src/uxbox/main/data/users.cljs index 1279b8eeb..ac6271830 100644 --- a/frontend/src/uxbox/main/data/users.cljs +++ b/frontend/src/uxbox/main/data/users.cljs @@ -159,8 +159,8 @@ (def allowed-file-types #{"image/jpeg" "image/png" "image/webp"}) (def max-file-size (* 5 1024 1024)) -;; TODO: unify with create-images at main/data/images.cljs -;; and upload-image at main/data/workspace/persistence.cljs +;; TODO: unify with create-media-objects at main/data/media.cljs +;; and upload-media-object at main/data/workspace/persistence.cljs ;; https://tree.taiga.io/project/uxboxproject/us/440 (defn update-photo @@ -172,9 +172,9 @@ (let [check-file (fn [file] (when (> (.-size file) max-file-size) - (throw (ex-info (tr "errors.image-too-large") {}))) + (throw (ex-info (tr "errors.media-too-large") {}))) (when-not (contains? allowed-file-types (.-type file)) - (throw (ex-info (tr "errors.image-format-unsupported") {}))) + (throw (ex-info (tr "errors.media-format-unsupported") {}))) file) on-success #(do (st/emit! dm/hide)) @@ -184,11 +184,11 @@ (.-message %) (.-message %) - (= (:code %) :image-type-not-allowed) - (tr "errors.image-type-not-allowed") + (= (:code %) :media-type-not-allowed) + (tr "errors.media-type-not-allowed") - (= (:code %) :image-type-mismatch) - (tr "errors.image-type-mismatch") + (= (:code %) :media-type-mismatch) + (tr "errors.media-type-mismatch") :else (tr "errors.unexpected-error"))] @@ -198,7 +198,7 @@ (fn [file] {:file file})] - (st/emit! (dm/show {:content (tr "image.loading") + (st/emit! (dm/show {:content (tr "media.loading") :type :info :timeout nil})) diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 0c5466d97..92d5ee57d 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -1166,14 +1166,14 @@ (dws/select-shapes selected)))))) (defn- image-uploaded - [{:keys [id name] :as image}] - (let [shape {:name name + [image] + (let [shape {:name (:name image) :metadata {:width (:width image) :height (:height image) - :uri (:uri image) - :thumb-width (:thumb-width image) - :thumb-height (:thumb-height image) - :thumb-uri (:thumb-uri image)}} + :uri (:uri image)}} + ;; :thumb-width (:thumb-width image) + ;; :thumb-height (:thumb-height image) + ;; :thumb-uri (:thumb-uri image)}} aspect-ratio (/ (:width image) (:height image))] (st/emit! (create-and-add-shape :image shape aspect-ratio)))) @@ -1182,7 +1182,7 @@ (ptk/reify ::paste-bin-impl ptk/WatchEvent (watch [_ state stream] - (rx/of (dwp/upload-image image image-uploaded))))) + (rx/of (dwp/upload-media-object image image-uploaded))))) (def paste (ptk/reify ::paste @@ -1437,10 +1437,10 @@ ;; Persistence (def set-file-shared dwp/set-file-shared) -(def fetch-images dwp/fetch-images) -(def add-image-from-url dwp/add-image-from-url) -(def upload-image dwp/upload-image) -(def delete-file-image dwp/delete-file-image) +(def fetch-media-objects dwp/fetch-media-objects) +(def add-media-object-from-url dwp/add-media-object-from-url) +(def upload-media-object dwp/upload-media-object) +(def delete-media-object dwp/delete-media-object) (def fetch-colors dwp/fetch-colors) (def rename-page dwp/rename-page) (def delete-page dwp/delete-page) diff --git a/frontend/src/uxbox/main/data/workspace/persistence.cljs b/frontend/src/uxbox/main/data/workspace/persistence.cljs index 85c260936..10b6e97b1 100644 --- a/frontend/src/uxbox/main/data/workspace/persistence.cljs +++ b/frontend/src/uxbox/main/data/workspace/persistence.cljs @@ -298,23 +298,23 @@ ;; --- Fetch Workspace Images -(declare images-fetched) +(declare media-objects-fetched) -(defn fetch-images +(defn fetch-media-objects [file-id] - (ptk/reify ::fetch-images + (ptk/reify ::fetch-media-objects ptk/WatchEvent (watch [_ state stream] - (->> (rp/query :images {:file-id file-id}) - (rx/map images-fetched))))) + (->> (rp/query :media-objects {:file-id file-id :is-local false}) + (rx/map media-objects-fetched))))) -(defn images-fetched - [images] - (ptk/reify ::images-fetched +(defn media-objects-fetched + [media-objects] + (ptk/reify ::media-objects-fetched ptk/UpdateEvent (update [_ state] - (let [images (d/index-by :id images)] - (assoc state :workspace-images images))))) + (let [media-objects (d/index-by :id media-objects)] + (assoc state :workspace-media media-objects))))) ;; --- Fetch Workspace Colors @@ -337,21 +337,21 @@ (assoc state :workspace-colors colors))))) -;; --- Upload Image +;; --- Upload local media objects -(declare image-uploaded) +(declare media-object-uploaded) (def allowed-file-types #{"image/jpeg" "image/png" "image/webp" "image/svg+xml"}) (def max-file-size (* 5 1024 1024)) -;; TODO: unify with create-images at main/data/images.cljs +;; TODO: unify with create-media-objects at main/data/media.cljs ;; and update-photo at main/data/users.cljs ;; https://tree.taiga.io/project/uxboxproject/us/440 -(defn add-image-from-url - ([url] (add-image-from-url url identity)) +(defn add-media-object-from-url + ([url] (add-media-object-from-url url identity)) ([url on-added] (us/verify fn? on-added) - (ptk/reify ::add-image-from-url + (ptk/reify ::add-media-object-from-url ptk/WatchEvent (watch [_ state stream] (let [file-id (get-in state [:workspace-page :file-id]) @@ -364,11 +364,11 @@ (.-message %) (.-message %) - (= (:code %) :image-type-not-allowed) - (tr "errors.image-type-not-allowed") + (= (:code %) :media-type-not-allowed) + (tr "errors.media-type-not-allowed") - (= (:code %) :image-type-mismatch) - (tr "errors.image-type-mismatch") + (= (:code %) :media-type-mismatch) + (tr "errors.media-type-mismatch") :else (tr "errors.unexpected-error"))] @@ -377,23 +377,24 @@ prepare (fn [url] {:file-id file-id - :url url})] + :url url + :is-local true})] - (st/emit! (dm/show {:content (tr "image.loading") + (st/emit! (dm/show {:content (tr "media.loading") :type :info :timeout nil})) (->> (rx/of url) (rx/map prepare) - (rx/mapcat #(rp/mutation! :add-file-image-from-url %)) + (rx/mapcat #(rp/mutation! :add-media-object-from-url %)) (rx/do on-success) - (rx/map image-uploaded) + (rx/map media-object-uploaded) (rx/catch on-error))))))) -(defn upload-image - ([file] (upload-image file identity)) +(defn upload-media-object + ([file] (upload-media-object file identity)) ([file on-uploaded] (us/verify fn? on-uploaded) - (ptk/reify ::upload-image + (ptk/reify ::upload-media-object ptk/WatchEvent (watch [_ state stream] (let [file-id (get-in state [:workspace-page :file-id]) @@ -401,9 +402,9 @@ check-file (fn [file] (when (> (.-size file) max-file-size) - (throw (ex-info (tr "errors.image-too-large") {}))) + (throw (ex-info (tr "errors.media-too-large") {}))) (when-not (contains? allowed-file-types (.-type file)) - (throw (ex-info (tr "errors.image-format-unsupported") {}))) + (throw (ex-info (tr "errors.media-format-unsupported") {}))) file) on-success #(do (st/emit! dm/hide) @@ -414,11 +415,11 @@ (.-message %) (.-message %) - (= (:code %) :image-type-not-allowed) - (tr "errors.image-type-not-allowed") + (= (:code %) :media-type-not-allowed) + (tr "errors.media-type-not-allowed") - (= (:code %) :image-type-mismatch) - (tr "errors.image-type-mismatch") + (= (:code %) :media-type-mismatch) + (tr "errors.media-type-mismatch") :else (tr "errors.unexpected-error"))] @@ -428,17 +429,18 @@ (fn [file] {:name (.-name file) :file-id file-id - :content file})] + :content file + :is-local true})] - (st/emit! (dm/show {:content (tr "image.loading") + (st/emit! (dm/show {:content (tr "media.loading") :type :info :timeout nil})) (->> (rx/of file) (rx/map check-file) (rx/map prepare) - (rx/mapcat #(rp/mutation! :upload-file-image %)) + (rx/mapcat #(rp/mutation! :upload-media-object %)) (rx/do on-success) - (rx/map image-uploaded) + (rx/map media-object-uploaded) (rx/catch on-error))))))) @@ -448,40 +450,39 @@ (s/def ::height ::us/number) (s/def ::mtype ::us/string) (s/def ::uri ::us/string) -(s/def ::thumb-uri ::us/string) +;; (s/def ::thumb-uri ::us/string) -(s/def ::image +(s/def ::media-object (s/keys :req-un [::id ::name ::width ::height - ::uri - ::thumb-uri])) + ::uri])) + ;; ::thumb-uri])) -(defn image-uploaded +(defn media-object-uploaded [item] - (us/verify ::image item) - (ptk/reify ::image-created + (us/verify ::media-object item) + (ptk/reify ::media-object-uploaded ptk/UpdateEvent (update [_ state] state))) - ;; (update state :workspace-images assoc (:id item) item)))) + ;; (update state :workspace-media assoc (:id item) item)))) -;; --- Delete image +;; --- Delete media object -(defn delete-file-image - [file-id image-id] - (ptk/reify ::delete-file-image +(defn delete-media-object + [id] + (ptk/reify ::delete-media-object ptk/UpdateEvent (update [_ state] - (update state :workspace-images dissoc image-id)) + (update state :workspace-media dissoc id)) ptk/WatchEvent (watch [_ state stream] - (let [params {:file-id file-id - :image-id image-id}] - (rp/mutation :delete-file-image params))))) + (let [params {:id id}] + (rp/mutation :delete-media-object params))))) ;; --- Helpers diff --git a/frontend/src/uxbox/main/refs.cljs b/frontend/src/uxbox/main/refs.cljs index edff25f5b..28646c175 100644 --- a/frontend/src/uxbox/main/refs.cljs +++ b/frontend/src/uxbox/main/refs.cljs @@ -57,8 +57,8 @@ (def workspace-project (l/derived :workspace-project st/state)) -(def workspace-images - (l/derived :workspace-images st/state)) +(def workspace-media + (l/derived :workspace-media st/state)) (def workspace-colors (l/derived :workspace-colors st/state)) diff --git a/frontend/src/uxbox/main/repo.cljs b/frontend/src/uxbox/main/repo.cljs index 19718ce76..5574fb4fa 100644 --- a/frontend/src/uxbox/main/repo.cljs +++ b/frontend/src/uxbox/main/repo.cljs @@ -68,7 +68,7 @@ (->> (http/send! {:method :post :uri uri}) (rx/mapcat handle-response)))) -(defmethod mutation :upload-image +(defmethod mutation :upload-media-object [id params] (let [form (js/FormData.)] (run! (fn [[key val]] @@ -76,13 +76,13 @@ (seq params)) (send-mutation! id form))) -(defmethod mutation :upload-file-image - [id params] - (let [form (js/FormData.)] - (run! (fn [[key val]] - (.append form (name key) val)) - (seq params)) - (send-mutation! id form))) +;; (defmethod mutation :upload-file-image +;; [id params] +;; (let [form (js/FormData.)] +;; (run! (fn [[key val]] +;; (.append form (name key) val)) +;; (seq params)) +;; (send-mutation! id form))) (defmethod mutation :update-profile-photo [id params] diff --git a/frontend/src/uxbox/main/ui/dashboard/library.cljs b/frontend/src/uxbox/main/ui/dashboard/library.cljs index ad12a80e2..9812c5c44 100644 --- a/frontend/src/uxbox/main/ui/dashboard/library.cljs +++ b/frontend/src/uxbox/main/ui/dashboard/library.cljs @@ -8,384 +8,384 @@ ;; Copyright (c) 2015-2020 Andrey Antukh ;; Copyright (c) 2015-2020 Juan de la Cruz -(ns uxbox.main.ui.dashboard.library - (:require - [okulary.core :as l] - [rumext.alpha :as mf] - [cuerdas.core :as str] - [uxbox.util.router :as rt] - [uxbox.util.i18n :as i18n :refer [t tr]] - [uxbox.util.color :as uc] - [uxbox.util.dom :as dom] - [uxbox.util.time :as dt] - [uxbox.main.data.library :as dlib] - [uxbox.main.data.icons :as dico] - [uxbox.main.data.images :as dimg] - [uxbox.main.data.colors :as dcol] - [uxbox.main.ui.icons :as i] - [uxbox.main.store :as st] - [uxbox.main.refs :as refs] - [uxbox.main.ui.components.context-menu :refer [context-menu]] - [uxbox.main.ui.components.file-uploader :refer [file-uploader]] - [uxbox.main.ui.modal :as modal] - [uxbox.main.ui.confirm :refer [confirm-dialog]] - [uxbox.main.ui.colorpicker :refer [colorpicker most-used-colors]] - [uxbox.main.ui.components.editable-label :refer [editable-label]] - )) - -(mf/defc modal-create-color - [{:keys [on-accept on-cancel] :as ctx}] - (let [state (mf/use-state { :current-color "#406280" })] - (letfn [(accept [event] - (dom/prevent-default event) - (modal/hide!) - (when on-accept (on-accept (:current-color @state)))) - - (cancel [event] - (dom/prevent-default event) - (modal/hide!) - (when on-cancel (on-cancel)))] - [:div.modal-create-color - [:h3.modal-create-color-title (tr "modal.create-color.new-color")] - [:& colorpicker {:value (:current-color @state) - :colors (into-array @most-used-colors) - :on-change #(swap! state assoc :current-color %)}] - - [:input.btn-primary {:type "button" - :value (tr "ds.button.save") - :on-click accept}] - - [:a.close {:href "#" :on-click cancel} i/close]]))) - -(defn create-library [section team-id] - (let [name (str (str (str/title (name section)) " " (gensym "Library ")))] - (st/emit! (dlib/create-library section team-id name)))) - -(defmulti create-item (fn [x _ _] x)) - -(defmethod create-item :icons [_ library-id files] - (st/emit! (dico/create-icons library-id files))) - -(defmethod create-item :images [_ library-id files] - (st/emit! (dimg/create-images library-id files))) - -(defmethod create-item :palettes [_ library-id] - (letfn [(dispatch-color [color] - (st/emit! (dcol/create-color library-id color)))] - (modal/show! modal-create-color {:on-accept dispatch-color}))) - -(mf/defc library-header - [{:keys [section team-id] :as props}] - (let [icons? (= section :icons) - images? (= section :images) - palettes? (= section :palettes) - locale (i18n/use-locale)] - [:header#main-bar.main-bar - [:h1.dashboard-title "Libraries"] - [:nav.library-header-navigation - [:a.library-header-navigation-item - {:class-name (when icons? "current") - :on-click #(st/emit! (rt/nav :dashboard-library-icons-index {:team-id team-id}))} - (t locale "dashboard.library.menu.icons")] - [:a.library-header-navigation-item - {:class-name (when images? "current") - :on-click #(st/emit! (rt/nav :dashboard-library-images-index {:team-id team-id}))} - (t locale "dashboard.library.menu.images")] - [:a.library-header-navigation-item - {:class-name (when palettes? "current") - :on-click #(st/emit! (rt/nav :dashboard-library-palettes-index {:team-id team-id}))} - (t locale "dashboard.library.menu.palettes")]]])) - -(mf/defc library-sidebar - [{:keys [section items team-id library-id]}] - (let [locale (i18n/use-locale)] - [:aside.library-sidebar - [:button.btn-primary.btn-small - {:type "button" - :on-click #(create-library section team-id)} - (t locale (str "dashboard.library.add-library." (name section)))] - [:ul.library-sidebar-list - (for [item items] - [:li.library-sidebar-list-element - {:key (:id item) - :class-name (when (= library-id (:id item)) "current") - :on-click - (fn [] - (let [path (keyword (str "dashboard-library-" (name section)))] - (dlib/retrieve-libraries :icons (:id item)) - (st/emit! (rt/nav path {:team-id team-id :library-id (:id item)}))))} - [:& editable-label {:value (:name item) - :on-change #(st/emit! (dlib/rename-library section team-id library-id %))}] - ])]])) - -(mf/defc library-top-menu - [{:keys [selected section library-id team-id on-delete-selected]}] - (let [state (mf/use-state {:is-open false - :editing-name false}) - locale (i18n/use-locale) - stop-editing #(swap! state assoc :editing-name false)] - [:header.library-top-menu - [:div.library-top-menu-current-element - [:& editable-label {:edit (:editing-name @state) - :on-change #(do - (stop-editing) - (st/emit! (dlib/rename-library section team-id library-id %))) - :on-cancel #(swap! state assoc :editing-name false) - :class-name "library-top-menu-current-element-name" - :value (:name selected)}] - [:a.library-top-menu-current-action - { :on-click #(swap! state update :is-open not)} - [:span i/arrow-down]] - [:& context-menu - {:show (:is-open @state) - :on-close #(swap! state update :is-open not) - :options [[(t locale "ds.button.rename") - #(swap! state assoc :editing-name true)] - - [(t locale "ds.button.delete") - (fn [] - (let [path (keyword (str "dashboard-library-" (name section) "-index"))] - (modal/show! - confirm-dialog - {:on-accept #(do - (st/emit! (dlib/delete-library section team-id library-id)) - (st/emit! (rt/nav path {:team-id team-id}))) - :message "Are you sure you want to delete this library?" - :accept-text "Delete"})))]]}]] - - [:div.library-top-menu-actions - (when on-delete-selected - [:a.library-top-menu-actions-delete - {:on-click on-delete-selected} - i/trash]) - - (if (= section :palettes) - [:button.btn-secondary.btn-small - {:on-click #(create-item section library-id)} - (t locale (str "dashboard.library.add-item." (name section)))] - - [:& file-uploader {:accept (case section - :images "image/jpeg,image/png,image/webp" - :icons "image/svg+xml" - "") - :multi true - :label-text (t locale (str "dashboard.library.add-item." (name section))) - :label-class "btn-secondary btn-small" - :input-id "file-upload" - :on-selected #(create-item section library-id %)}])]])) - -(mf/defc library-icon-card - [{:keys [item on-select on-unselect on-delete]}] - (let [{:keys [id name url content metadata library-id modified-at]} item - locale (i18n/use-locale) - state (mf/use-state {:is-open false :selected false}) - time (dt/timeago modified-at {:locale locale}) - handle-change (fn [] - (swap! state update :selected not) - (if (:selected @state) - (when on-unselect (on-unselect id)) - (when on-select (on-select id))))] - [:div.library-card.library-icon - [:div.input-checkbox.check-primary - [:input {:type "checkbox" - :id (str "icon-" id) - :on-change handle-change - :value (:selected @state)}] - [:label {:for (str "icon-" id)}]] - [:div.library-card-image - [:svg {:view-box (->> metadata :view-box (str/join " ")) - :width (:width metadata) - :height (:height metadata) - :dangerouslySetInnerHTML {:__html content}}]] - - [:div.library-card-footer - [:div.library-card-footer-name name] - [:div.library-card-footer-timestamp time] - [:div.library-card-footer-menu - { :on-click #(swap! state update :is-open not) } - i/actions] - [:& context-menu - {:show (:is-open @state) - :on-close #(swap! state update :is-open not) - :options [[(t locale "ds.button.delete") - (fn [] - (modal/show! - confirm-dialog - {:on-accept #(do - (st/emit! (dlib/delete-item :icons library-id id)) - (on-delete id)) - :message "Are you sure you want to delete this icon?" - :accept-text "Delete"}))]]}]]])) - -(mf/defc library-image-card - [{:keys [item on-select on-unselect on-delete]}] - (let [{:keys [id name thumb-uri library-id modified-at]} item - locale (i18n/use-locale) - state (mf/use-state {:is-open false :selected false}) - time (dt/timeago modified-at {:locale locale}) - handle-change (fn [] - (swap! state update :selected not) - (if (:selected @state) - (when on-unselect (on-unselect id)) - (when on-select (on-select id))))] - [:div.library-card.library-image - [:div.input-checkbox.check-primary - [:input {:type "checkbox" - :id (str "image-" id) - :on-change handle-change - :value (:selected @state)}] - [:label {:for (str "image-" id)}]] - [:div.library-card-image - [:img {:src thumb-uri}]] - [:div.library-card-footer - [:div.library-card-footer-name name] - [:div.library-card-footer-timestamp time] - [:div.library-card-footer-menu - { :on-click #(swap! state update :is-open not) } - i/actions] - [:& context-menu - {:show (:is-open @state) - :on-close #(swap! state update :is-open not) - :options [[(t locale "ds.button.delete") - (fn [] - (modal/show! - confirm-dialog - {:on-accept #(do - (st/emit! (dlib/delete-item :images library-id id)) - (on-delete id)) - :message "Are you sure you want to delete this image?" - :accept-text "Delete"}))]]}]]])) - -(mf/defc library-color-card - [{:keys [item on-select on-unselect on-delete]}] - (let [{:keys [id content library-id modified-at]} item - locale (i18n/use-locale) - state (mf/use-state {:is-open false :selected false}) - handle-change (fn [] - (swap! state update :selected not) - (if (:selected @state) - (when on-unselect (on-unselect id)) - (when on-select (on-select id))))] - (when content - [:div.library-card.library-color - [:div.input-checkbox.check-primary - [:input {:type "checkbox" - :id (str "color-" id) - :on-change handle-change - :value (:selected @state)}] - [:label {:for (str "color-" id)}]] - [:div.library-card-image - { :style { :background-color content }}] - [:div.library-card-footer - [:div.library-card-footer-name content ] - [:div.library-card-footer-color - [:span.library-card-footer-color-label "RGB"] - [:span.library-card-footer-color-rgb (str/join " " (uc/hex->rgb content))]] - [:div.library-card-footer-menu - { :on-click #(swap! state update :is-open not) } - i/actions] - [:& context-menu - {:show (:is-open @state) - :on-close #(swap! state update :is-open not) - :options [[(t locale "ds.button.delete") - (fn [] - (modal/show! - confirm-dialog - {:on-accept #(do - (st/emit! (dlib/delete-item :palettes library-id id)) - (on-delete id)) - :message "Are you sure you want to delete this color?" - :accept-text "Delete"}))]]}]]]))) - -(defn- make-libraries-ref - [section team-id] - #(-> (l/in [:library section team-id]) - (l/derived st/state =))) - -(defn- make-library-items-ref - [section library-id] - #(-> (l/in [:library-items section library-id]) - (l/derived st/state =))) - -(def last-deleted-library-ref - (-> (l/in [:library :last-deleted-library]) - (l/derived st/state =))) - -(mf/defc library-page - [{:keys [team-id library-id section]}] - (let [state (mf/use-state {:selected #{}}) - libs-ref (mf/use-memo - (mf/deps section team-id) - (make-libraries-ref section team-id)) - - libraries (mf/deref libs-ref) - items-ref (mf/use-memo - (mf/deps section library-id) - (make-library-items-ref section library-id)) - - items (mf/deref items-ref) - - last-deleted-library (mf/deref last-deleted-library-ref) - selected-library (first (filter #(= (:id %) library-id) libraries)) - ] - - (mf/use-effect - (mf/deps libraries) - #(if (and (nil? library-id) (> (count libraries) 0)) - (let [path (keyword (str "dashboard-library-" (name section)))] - (st/emit! (rt/nav path {:team-id team-id :library-id (:id (first libraries))}))))) - - (mf/use-effect - (mf/deps libraries) - #(if (and library-id (not (some (fn [{id :id}] (= library-id id)) libraries))) - (let [path (keyword (str "dashboard-library-" (name section) "-index"))] - (st/emit! (rt/nav path {:team-id team-id}))))) - - (mf/use-effect - (mf/deps section team-id) - #(st/emit! (dlib/retrieve-libraries section team-id))) - - (mf/use-effect - (mf/deps library-id last-deleted-library) - #(when (and library-id (not= last-deleted-library library-id)) - (st/emit! (dlib/retrieve-library-data section library-id)))) - - [:div.library-page - [:& library-header {:section section :team-id team-id}] - [:& library-sidebar {:items libraries :team-id team-id :library-id library-id :section section}] - - (if library-id - [:section.library-content - [:& library-top-menu - {:selected selected-library - :section section - :library-id library-id - :team-id team-id - :on-delete-selected - (when-not (empty? (:selected @state)) - (fn [] - (modal/show! - confirm-dialog - {:on-accept #(do (st/emit! (dlib/batch-delete-item section library-id (:selected @state))) - (swap! state assoc :selected #{})) - :message (str "Are you sure you want to delete " (-> @state :selected count) " items?") - :accept-text "Delete"})))}] - [:* - (if (> (count items) 0) - [:div.library-page-cards-container - (for [item items] - (let [item (assoc item :key (:id item)) - props {:item item - :key (:id item) - :on-select #(swap! state update :selected conj %) - :on-unselect #(swap! state update :selected disj %) - :on-delete #(swap! state update :selected disj %)}] - (case section - :icons [:& library-icon-card props] - :images [:& library-image-card props] - :palettes [:& library-color-card props])))] - [:div.library-content-empty - [:p.library-content-empty-text "You still have no elements in this library"]])]] - - [:div.library-content-empty - [:p.library-content-empty-text "You still have no image libraries."]])])) +;; (ns uxbox.main.ui.dashboard.library +;; (:require +;; [okulary.core :as l] +;; [rumext.alpha :as mf] +;; [cuerdas.core :as str] +;; [uxbox.util.router :as rt] +;; [uxbox.util.i18n :as i18n :refer [t tr]] +;; [uxbox.util.color :as uc] +;; [uxbox.util.dom :as dom] +;; [uxbox.util.time :as dt] +;; [uxbox.main.data.library :as dlib] +;; [uxbox.main.data.icons :as dico] +;; [uxbox.main.data.images :as dimg] +;; [uxbox.main.data.colors :as dcol] +;; [uxbox.main.ui.icons :as i] +;; [uxbox.main.store :as st] +;; [uxbox.main.refs :as refs] +;; [uxbox.main.ui.components.context-menu :refer [context-menu]] +;; [uxbox.main.ui.components.file-uploader :refer [file-uploader]] +;; [uxbox.main.ui.modal :as modal] +;; [uxbox.main.ui.confirm :refer [confirm-dialog]] +;; [uxbox.main.ui.colorpicker :refer [colorpicker most-used-colors]] +;; [uxbox.main.ui.components.editable-label :refer [editable-label]] +;; )) +;; +;; (mf/defc modal-create-color +;; [{:keys [on-accept on-cancel] :as ctx}] +;; (let [state (mf/use-state { :current-color "#406280" })] +;; (letfn [(accept [event] +;; (dom/prevent-default event) +;; (modal/hide!) +;; (when on-accept (on-accept (:current-color @state)))) +;; +;; (cancel [event] +;; (dom/prevent-default event) +;; (modal/hide!) +;; (when on-cancel (on-cancel)))] +;; [:div.modal-create-color +;; [:h3.modal-create-color-title (tr "modal.create-color.new-color")] +;; [:& colorpicker {:value (:current-color @state) +;; :colors (into-array @most-used-colors) +;; :on-change #(swap! state assoc :current-color %)}] +;; +;; [:input.btn-primary {:type "button" +;; :value (tr "ds.button.save") +;; :on-click accept}] +;; +;; [:a.close {:href "#" :on-click cancel} i/close]]))) +;; +;; (defn create-library [section team-id] +;; (let [name (str (str (str/title (name section)) " " (gensym "Library ")))] +;; (st/emit! (dlib/create-library section team-id name)))) +;; +;; (defmulti create-item (fn [x _ _] x)) +;; +;; (defmethod create-item :icons [_ library-id files] +;; (st/emit! (dico/create-icons library-id files))) +;; +;; (defmethod create-item :images [_ library-id files] +;; (st/emit! (dimg/create-images library-id files))) +;; +;; (defmethod create-item :palettes [_ library-id] +;; (letfn [(dispatch-color [color] +;; (st/emit! (dcol/create-color library-id color)))] +;; (modal/show! modal-create-color {:on-accept dispatch-color}))) +;; +;; (mf/defc library-header +;; [{:keys [section team-id] :as props}] +;; (let [icons? (= section :icons) +;; images? (= section :images) +;; palettes? (= section :palettes) +;; locale (i18n/use-locale)] +;; [:header#main-bar.main-bar +;; [:h1.dashboard-title "Libraries"] +;; [:nav.library-header-navigation +;; [:a.library-header-navigation-item +;; {:class-name (when icons? "current") +;; :on-click #(st/emit! (rt/nav :dashboard-library-icons-index {:team-id team-id}))} +;; (t locale "dashboard.library.menu.icons")] +;; [:a.library-header-navigation-item +;; {:class-name (when images? "current") +;; :on-click #(st/emit! (rt/nav :dashboard-library-images-index {:team-id team-id}))} +;; (t locale "dashboard.library.menu.images")] +;; [:a.library-header-navigation-item +;; {:class-name (when palettes? "current") +;; :on-click #(st/emit! (rt/nav :dashboard-library-palettes-index {:team-id team-id}))} +;; (t locale "dashboard.library.menu.palettes")]]])) +;; +;; (mf/defc library-sidebar +;; [{:keys [section items team-id library-id]}] +;; (let [locale (i18n/use-locale)] +;; [:aside.library-sidebar +;; [:button.btn-primary.btn-small +;; {:type "button" +;; :on-click #(create-library section team-id)} +;; (t locale (str "dashboard.library.add-library." (name section)))] +;; [:ul.library-sidebar-list +;; (for [item items] +;; [:li.library-sidebar-list-element +;; {:key (:id item) +;; :class-name (when (= library-id (:id item)) "current") +;; :on-click +;; (fn [] +;; (let [path (keyword (str "dashboard-library-" (name section)))] +;; (dlib/retrieve-libraries :icons (:id item)) +;; (st/emit! (rt/nav path {:team-id team-id :library-id (:id item)}))))} +;; [:& editable-label {:value (:name item) +;; :on-change #(st/emit! (dlib/rename-library section team-id library-id %))}] +;; ])]])) +;; +;; (mf/defc library-top-menu +;; [{:keys [selected section library-id team-id on-delete-selected]}] +;; (let [state (mf/use-state {:is-open false +;; :editing-name false}) +;; locale (i18n/use-locale) +;; stop-editing #(swap! state assoc :editing-name false)] +;; [:header.library-top-menu +;; [:div.library-top-menu-current-element +;; [:& editable-label {:edit (:editing-name @state) +;; :on-change #(do +;; (stop-editing) +;; (st/emit! (dlib/rename-library section team-id library-id %))) +;; :on-cancel #(swap! state assoc :editing-name false) +;; :class-name "library-top-menu-current-element-name" +;; :value (:name selected)}] +;; [:a.library-top-menu-current-action +;; { :on-click #(swap! state update :is-open not)} +;; [:span i/arrow-down]] +;; [:& context-menu +;; {:show (:is-open @state) +;; :on-close #(swap! state update :is-open not) +;; :options [[(t locale "ds.button.rename") +;; #(swap! state assoc :editing-name true)] +;; +;; [(t locale "ds.button.delete") +;; (fn [] +;; (let [path (keyword (str "dashboard-library-" (name section) "-index"))] +;; (modal/show! +;; confirm-dialog +;; {:on-accept #(do +;; (st/emit! (dlib/delete-library section team-id library-id)) +;; (st/emit! (rt/nav path {:team-id team-id}))) +;; :message "Are you sure you want to delete this library?" +;; :accept-text "Delete"})))]]}]] +;; +;; [:div.library-top-menu-actions +;; (when on-delete-selected +;; [:a.library-top-menu-actions-delete +;; {:on-click on-delete-selected} +;; i/trash]) +;; +;; (if (= section :palettes) +;; [:button.btn-secondary.btn-small +;; {:on-click #(create-item section library-id)} +;; (t locale (str "dashboard.library.add-item." (name section)))] +;; +;; [:& file-uploader {:accept (case section +;; :images "image/jpeg,image/png,image/webp" +;; :icons "image/svg+xml" +;; "") +;; :multi true +;; :label-text (t locale (str "dashboard.library.add-item." (name section))) +;; :label-class "btn-secondary btn-small" +;; :input-id "file-upload" +;; :on-selected #(create-item section library-id %)}])]])) +;; +;; (mf/defc library-icon-card +;; [{:keys [item on-select on-unselect on-delete]}] +;; (let [{:keys [id name url content metadata library-id modified-at]} item +;; locale (i18n/use-locale) +;; state (mf/use-state {:is-open false :selected false}) +;; time (dt/timeago modified-at {:locale locale}) +;; handle-change (fn [] +;; (swap! state update :selected not) +;; (if (:selected @state) +;; (when on-unselect (on-unselect id)) +;; (when on-select (on-select id))))] +;; [:div.library-card.library-icon +;; [:div.input-checkbox.check-primary +;; [:input {:type "checkbox" +;; :id (str "icon-" id) +;; :on-change handle-change +;; :value (:selected @state)}] +;; [:label {:for (str "icon-" id)}]] +;; [:div.library-card-image +;; [:svg {:view-box (->> metadata :view-box (str/join " ")) +;; :width (:width metadata) +;; :height (:height metadata) +;; :dangerouslySetInnerHTML {:__html content}}]] +;; +;; [:div.library-card-footer +;; [:div.library-card-footer-name name] +;; [:div.library-card-footer-timestamp time] +;; [:div.library-card-footer-menu +;; { :on-click #(swap! state update :is-open not) } +;; i/actions] +;; [:& context-menu +;; {:show (:is-open @state) +;; :on-close #(swap! state update :is-open not) +;; :options [[(t locale "ds.button.delete") +;; (fn [] +;; (modal/show! +;; confirm-dialog +;; {:on-accept #(do +;; (st/emit! (dlib/delete-item :icons library-id id)) +;; (on-delete id)) +;; :message "Are you sure you want to delete this icon?" +;; :accept-text "Delete"}))]]}]]])) +;; +;; (mf/defc library-image-card +;; [{:keys [item on-select on-unselect on-delete]}] +;; (let [{:keys [id name thumb-uri library-id modified-at]} item +;; locale (i18n/use-locale) +;; state (mf/use-state {:is-open false :selected false}) +;; time (dt/timeago modified-at {:locale locale}) +;; handle-change (fn [] +;; (swap! state update :selected not) +;; (if (:selected @state) +;; (when on-unselect (on-unselect id)) +;; (when on-select (on-select id))))] +;; [:div.library-card.library-image +;; [:div.input-checkbox.check-primary +;; [:input {:type "checkbox" +;; :id (str "image-" id) +;; :on-change handle-change +;; :value (:selected @state)}] +;; [:label {:for (str "image-" id)}]] +;; [:div.library-card-image +;; [:img {:src thumb-uri}]] +;; [:div.library-card-footer +;; [:div.library-card-footer-name name] +;; [:div.library-card-footer-timestamp time] +;; [:div.library-card-footer-menu +;; { :on-click #(swap! state update :is-open not) } +;; i/actions] +;; [:& context-menu +;; {:show (:is-open @state) +;; :on-close #(swap! state update :is-open not) +;; :options [[(t locale "ds.button.delete") +;; (fn [] +;; (modal/show! +;; confirm-dialog +;; {:on-accept #(do +;; (st/emit! (dlib/delete-item :images library-id id)) +;; (on-delete id)) +;; :message "Are you sure you want to delete this image?" +;; :accept-text "Delete"}))]]}]]])) +;; +;; (mf/defc library-color-card +;; [{:keys [item on-select on-unselect on-delete]}] +;; (let [{:keys [id content library-id modified-at]} item +;; locale (i18n/use-locale) +;; state (mf/use-state {:is-open false :selected false}) +;; handle-change (fn [] +;; (swap! state update :selected not) +;; (if (:selected @state) +;; (when on-unselect (on-unselect id)) +;; (when on-select (on-select id))))] +;; (when content +;; [:div.library-card.library-color +;; [:div.input-checkbox.check-primary +;; [:input {:type "checkbox" +;; :id (str "color-" id) +;; :on-change handle-change +;; :value (:selected @state)}] +;; [:label {:for (str "color-" id)}]] +;; [:div.library-card-image +;; { :style { :background-color content }}] +;; [:div.library-card-footer +;; [:div.library-card-footer-name content ] +;; [:div.library-card-footer-color +;; [:span.library-card-footer-color-label "RGB"] +;; [:span.library-card-footer-color-rgb (str/join " " (uc/hex->rgb content))]] +;; [:div.library-card-footer-menu +;; { :on-click #(swap! state update :is-open not) } +;; i/actions] +;; [:& context-menu +;; {:show (:is-open @state) +;; :on-close #(swap! state update :is-open not) +;; :options [[(t locale "ds.button.delete") +;; (fn [] +;; (modal/show! +;; confirm-dialog +;; {:on-accept #(do +;; (st/emit! (dlib/delete-item :palettes library-id id)) +;; (on-delete id)) +;; :message "Are you sure you want to delete this color?" +;; :accept-text "Delete"}))]]}]]]))) +;; +;; (defn- make-libraries-ref +;; [section team-id] +;; #(-> (l/in [:library section team-id]) +;; (l/derived st/state =))) +;; +;; (defn- make-library-items-ref +;; [section library-id] +;; #(-> (l/in [:library-items section library-id]) +;; (l/derived st/state =))) +;; +;; (def last-deleted-library-ref +;; (-> (l/in [:library :last-deleted-library]) +;; (l/derived st/state =))) +;; +;; (mf/defc library-page +;; [{:keys [team-id library-id section]}] +;; (let [state (mf/use-state {:selected #{}}) +;; libs-ref (mf/use-memo +;; (mf/deps section team-id) +;; (make-libraries-ref section team-id)) +;; +;; libraries (mf/deref libs-ref) +;; items-ref (mf/use-memo +;; (mf/deps section library-id) +;; (make-library-items-ref section library-id)) +;; +;; items (mf/deref items-ref) +;; +;; last-deleted-library (mf/deref last-deleted-library-ref) +;; selected-library (first (filter #(= (:id %) library-id) libraries)) +;; ] +;; +;; (mf/use-effect +;; (mf/deps libraries) +;; #(if (and (nil? library-id) (> (count libraries) 0)) +;; (let [path (keyword (str "dashboard-library-" (name section)))] +;; (st/emit! (rt/nav path {:team-id team-id :library-id (:id (first libraries))}))))) +;; +;; (mf/use-effect +;; (mf/deps libraries) +;; #(if (and library-id (not (some (fn [{id :id}] (= library-id id)) libraries))) +;; (let [path (keyword (str "dashboard-library-" (name section) "-index"))] +;; (st/emit! (rt/nav path {:team-id team-id}))))) +;; +;; (mf/use-effect +;; (mf/deps section team-id) +;; #(st/emit! (dlib/retrieve-libraries section team-id))) +;; +;; (mf/use-effect +;; (mf/deps library-id last-deleted-library) +;; #(when (and library-id (not= last-deleted-library library-id)) +;; (st/emit! (dlib/retrieve-library-data section library-id)))) +;; +;; [:div.library-page +;; [:& library-header {:section section :team-id team-id}] +;; [:& library-sidebar {:items libraries :team-id team-id :library-id library-id :section section}] +;; +;; (if library-id +;; [:section.library-content +;; [:& library-top-menu +;; {:selected selected-library +;; :section section +;; :library-id library-id +;; :team-id team-id +;; :on-delete-selected +;; (when-not (empty? (:selected @state)) +;; (fn [] +;; (modal/show! +;; confirm-dialog +;; {:on-accept #(do (st/emit! (dlib/batch-delete-item section library-id (:selected @state))) +;; (swap! state assoc :selected #{})) +;; :message (str "Are you sure you want to delete " (-> @state :selected count) " items?") +;; :accept-text "Delete"})))}] +;; [:* +;; (if (> (count items) 0) +;; [:div.library-page-cards-container +;; (for [item items] +;; (let [item (assoc item :key (:id item)) +;; props {:item item +;; :key (:id item) +;; :on-select #(swap! state update :selected conj %) +;; :on-unselect #(swap! state update :selected disj %) +;; :on-delete #(swap! state update :selected disj %)}] +;; (case section +;; :icons [:& library-icon-card props] +;; :images [:& library-image-card props] +;; :palettes [:& library-color-card props])))] +;; [:div.library-content-empty +;; [:p.library-content-empty-text "You still have no elements in this library"]])]] +;; +;; [:div.library-content-empty +;; [:p.library-content-empty-text "You still have no image libraries."]])])) diff --git a/frontend/src/uxbox/main/ui/shapes/image.cljs b/frontend/src/uxbox/main/ui/shapes/image.cljs index 45102ed44..cead0e8a3 100644 --- a/frontend/src/uxbox/main/ui/shapes/image.cljs +++ b/frontend/src/uxbox/main/ui/shapes/image.cljs @@ -20,10 +20,11 @@ (let [shape (unchecked-get props "shape") {:keys [id x y width height rotation metadata]} shape transform (geom/transform-matrix shape) - uri (if (or (> (:thumb-width metadata) width) - (> (:thumb-height metadata) height)) - (:thumb-uri metadata) - (:uri metadata)) + uri (:uri metadata) + ;; uri (if (or (> (:thumb-width metadata) width) + ;; (> (:thumb-height metadata) height)) + ;; (:thumb-uri metadata) + ;; (:uri metadata)) props (-> (attrs/extract-style-attrs shape) (obj/merge! diff --git a/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs b/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs index a97a059d4..65078ec06 100644 --- a/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs +++ b/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs @@ -36,16 +36,16 @@ (let [shape {:name name :metadata {:width (:width image) :height (:height image) - :uri (:uri image) - :thumb-width (:thumb-width image) - :thumb-height (:thumb-height image) - :thumb-uri (:thumb-uri image)}} + :uri (:uri image)}} + ;; :thumb-width (:thumb-width image) + ;; :thumb-height (:thumb-height image) + ;; :thumb-uri (:thumb-uri image)}} aspect-ratio (/ (:width image) (:height image))] (st/emit! (dw/create-and-add-shape :image shape aspect-ratio)))) on-files-selected (fn [files] - (run! #(st/emit! (dw/upload-image % on-uploaded)) files))] + (run! #(st/emit! (dw/upload-media-object % on-uploaded)) files))] [:aside.left-toolbar [:div.left-toolbar-inside diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/assets.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/assets.cljs index 5513ebdea..b8b1aa7fc 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/assets.cljs @@ -18,7 +18,7 @@ [uxbox.common.geom.point :as gpt] [uxbox.main.ui.icons :as i] [uxbox.main.data.workspace :as dw] - [uxbox.main.data.images :as di] + [uxbox.main.data.media :as di] [uxbox.main.data.colors :as dcol] [uxbox.main.refs :as refs] [uxbox.main.store :as st] @@ -72,11 +72,11 @@ [:a.close {:href "#" :on-click cancel} i/close]]))) (mf/defc graphics-box - [{:keys [library-id images] :as props}] + [{:keys [library-id media-objects] :as props}] (let [state (mf/use-state {:menu-open false :top nil :left nil - :image-id nil}) + :object-id nil}) file-input (mf/use-ref nil) @@ -84,14 +84,14 @@ #(dom/click (mf/ref-val file-input)) delete-graphic - #(st/emit! (dw/delete-file-image library-id (:image-id @state))) + #(st/emit! (dw/delete-media-object (:object-id @state))) on-files-selected (fn [files] - (st/emit! (di/create-images library-id files))) + (st/emit! (di/create-media-objects library-id files))) on-context-menu - (fn [image-id] + (fn [object-id] (fn [event] (let [pos (dom/get-client-position event) top (:y pos) @@ -100,7 +100,7 @@ (swap! state assoc :menu-open true :top top :left left - :image-id image-id)))) + :object-id object-id)))) on-drag-start (fn [uri] @@ -111,7 +111,7 @@ [:div.asset-group [:div.group-title (tr "workspace.assets.graphics") - [:span (str "\u00A0(") (count images) ")"] ;; Unicode 00A0 is non-breaking space + [:span (str "\u00A0(") (count media-objects) ")"] ;; Unicode 00A0 is non-breaking space [:div.group-button {:on-click add-graphic} i/plus [:& file-uploader {:accept "image/jpeg,image/png,image/webp,image/svg+xml" @@ -119,14 +119,14 @@ :input-ref file-input :on-selected on-files-selected}]]] [:div.group-grid - (for [image (sort-by :name images)] - [:div.grid-cell {:key (:id image) + (for [object (sort-by :name media-objects)] + [:div.grid-cell {:key (:id object) :draggable true - :on-context-menu (on-context-menu (:id image)) - :on-drag-start (on-drag-start (:uri image))} - [:img {:src (:thumb-uri image) + :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 image)]]) + [:div.cell-name (:name object)]]) [:& context-menu {:selectable false :show (:menu-open @state) @@ -256,7 +256,7 @@ (mf/defc library-toolbox [{:keys [library-id shared? - images + media-objects colors initial-open? search-term @@ -274,12 +274,12 @@ [:span.tool-badge (tr "workspace.assets.shared")])] (when @open? (let [show-graphics (and (or (= box-filter :all) (= box-filter :graphics)) - (or (> (count images) 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 (when show-graphics - [:& graphics-box {:library-id library-id :images images}]) + [:& graphics-box {:library-id library-id :media-objects media-objects}]) (when show-colors [:& colors-box {:library-id library-id :colors colors}]) (when (and (not show-graphics) (not show-colors)) @@ -291,14 +291,14 @@ (let [team-id (-> refs/workspace-project mf/deref :team-id) file (mf/deref refs/workspace-file) file-id (:id file) - file-images (mf/deref refs/workspace-images) + file-media (mf/deref refs/workspace-media) file-colors (mf/deref refs/workspace-colors) state (mf/use-state {:search-term "" :box-filter :all}) - filtered-images (filter #(matches-search (:name %) (:search-term @state)) - (vals file-images)) + filtered-media-objects (filter #(matches-search (:name %) (:search-term @state)) + (vals file-media)) filtered-colors (filter #(or (matches-search (:name %) (:search-term @state)) (matches-search (:content %) (:search-term @state))) @@ -321,7 +321,7 @@ (mf/use-effect (mf/deps file-id) #(when file-id - (st/emit! (dw/fetch-images file-id)) + (st/emit! (dw/fetch-media-objects file-id)) (st/emit! (dw/fetch-colors file-id)))) [:div.assets-bar @@ -352,7 +352,7 @@ [:& library-toolbox {:library-id file-id :shared? (:is-shared file) - :images filtered-images + :media-objects filtered-media-objects :colors filtered-colors :initial-open? true :search-term (:search-term @state) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs index 4f6f607d0..f0cf7a893 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs @@ -7,181 +7,181 @@ ;; ;; Copyright (c) 2020 UXBOX Labs SL -(ns uxbox.main.ui.workspace.sidebar.libraries - (:require - [okulary.core :as l] - [cuerdas.core :as str] - [rumext.alpha :as mf] - [uxbox.common.data :as d] - [uxbox.common.pages :as cp] - [uxbox.common.geom.shapes :as geom] - [uxbox.common.geom.point :as gpt] - [uxbox.main.ui.icons :as i] - [uxbox.main.data.workspace :as dw] - [uxbox.main.refs :as refs] - [uxbox.main.store :as st] - [uxbox.main.ui.keyboard :as kbd] - [uxbox.main.ui.shapes.icon :as icon] - [uxbox.util.dom :as dom] - [uxbox.util.dom.dnd :as dnd] - [uxbox.util.timers :as timers] - [uxbox.common.uuid :as uuid] - [uxbox.util.i18n :as i18n :refer [tr]] - [uxbox.util.data :refer [classnames]] - [uxbox.main.ui.components.tab-container :refer [tab-container tab-element]] - [uxbox.main.data.library :as dlib] - [uxbox.main.ui.components.context-menu :refer [context-menu]])) - -;; --- Refs - -(defn libraries-ref [section] - (-> (l/in [:library section]) - (l/derived st/state))) - -(defn selected-items-ref [section library-id] - (-> (l/in [:library-items section library-id]) - (l/derived st/state))) - -(defn selected-library-ref [section] - (-> (l/in [:library-selected section]) - (l/derived st/state))) - -(defn selected-filter-ref [section] - (-> (l/in [:library-filter section]) - (l/derived st/state))) - -(defmulti shape-from-item (fn [type _] type)) - -(defmethod shape-from-item :icons [_ item] - (-> (cp/make-minimal-shape :icon) - (merge item) - (geom/resize (-> item :metadata :width) (-> item :metadata :height)) - (geom/absolute-move (gpt/point 0 0)))) - -(defmethod shape-from-item :images [_ item] - (let [metadata (select-keys item [:width :height :thumb-width - :thumb-height :thumb-uri :uri])] - (-> (cp/make-minimal-shape :image) - (merge item) - (assoc :metadata metadata) - (geom/resize (-> item :width) (-> item :height)) - (geom/absolute-move (gpt/point 0 0))))) - -;; --- Components - -(mf/defc library-tab [{:keys [libraries section]}] - (when (and libraries (-> libraries count (> 0))) - (let [state (mf/use-state {:drag-style false}) - first-id (-> libraries first :id) - current-selection (or (mf/deref (selected-library-ref section)) first-id)] - - ;; Check if the current selection is in the list of libraries - (mf/use-effect - (mf/deps libraries) - #(when (not (some (fn [it] (= current-selection (-> it :id))) libraries)) - (st/emit! (dlib/select-library section first-id)))) - - ;; Retrieve the library data given the current selected library - (mf/use-effect - (mf/deps current-selection) - #(st/emit! (dlib/retrieve-library-data section current-selection))) - - [:div.library-tab - {:class (classnames :icons-tab (= section :icons) - :images-tab (= section :images))} - [:select.input-select.library-tab-libraries - {:value current-selection - :on-change #(st/emit! (dlib/select-library section (-> % dom/get-target dom/get-value uuid)))} - (for [library libraries] - [:option.library-tab-libraries-item - {:key (:id library) - :value (:id library)} - (:name library)])] - [:div.library-tab-content - (let [items (mf/deref (selected-items-ref section current-selection))] - (for [item items] - [:div.library-tab-element - {:draggable true - :class (classnames :is-dragging (:drag-style @state)) - :key (str (:id item)) - :on-drag-start (fn [event] - (swap! state assoc :drag-style true) - (dnd/set-data! event "uxbox/shape" (shape-from-item section item)) - (dnd/set-allowed-effect! event "move") - ;; This state is so we can give custom css to the dragging - (timers/schedule #(swap! state assoc :drag-style false)))} - (if (= section :icons) - [:svg {:view-box (->> item :metadata :view-box (str/join " ")) - :width (-> item :metadata :width) - :height (-> item :metadata :height) - :dangerouslySetInnerHTML {:__html (:content item)}}] - [:img {:draggable false - :src (:thumb-uri item)}]) - [:span.library-tab-element-name (:name item)]]))]]))) - -(mf/defc libraries-toolbox - [{:keys [key]}] - (let [state (mf/use-state {:menu-open false}) - selected-filter (fn [section] (or (mf/deref (selected-filter-ref section)) :all)) - team-id (-> refs/workspace-project mf/deref :team-id) - - filter-to-str {:all (tr "workspace.library.all") - :own (tr "workspace.library.own") - :store (tr "workspace.library.store")} - - select-option - (fn [option] - (st/emit! - (dlib/change-library-filter :icons option) - (dlib/change-library-filter :images option))) - - filter-libraries - (fn [section libraries] - (case (selected-filter section) - :all (-> libraries vals flatten) - :own (libraries team-id) - :store (libraries uuid/zero))) - - get-libraries - (fn [section] (->> (libraries-ref section) - mf/deref - (filter-libraries section)))] - - (mf/use-effect - (mf/deps team-id) - #(when team-id - (st/emit! (dlib/retrieve-libraries :icons) - (dlib/retrieve-libraries :images) - (dlib/retrieve-libraries :icons team-id) - (dlib/retrieve-libraries :images team-id)))) - - [:div#libraries.tool-window - [:div.libraries-window-bar - [:div.libraries-window-bar-title (tr "workspace.library.libraries")] - [:div.libraries-window-bar-options - {:on-click #(swap! state assoc :menu-open true)} - (filter-to-str (selected-filter :icons)) - [:button - { - :type "button"} - i/arrow-slide - [:& context-menu - {:selectable true - :show (:menu-open @state) - :selected (filter-to-str (selected-filter :icons)) - :on-close #(swap! state assoc :menu-open false) - :options (mapv (fn [[key val]] [val #(select-option key)]) filter-to-str)}]]]] - - [:div.tool-window-content - [:& tab-container {} - [:& tab-element - {:id :icons :title (tr "workspace.library.icons")} - [:& library-tab {:section :icons - :libraries (get-libraries :icons) }]] - - [:& tab-element - {:id :images :title (tr "workspace.library.images")} - [:& library-tab {:section :images - :libraries (get-libraries :images)}]]]]])) - - +;; (ns uxbox.main.ui.workspace.sidebar.libraries +;; (:require +;; [okulary.core :as l] +;; [cuerdas.core :as str] +;; [rumext.alpha :as mf] +;; [uxbox.common.data :as d] +;; [uxbox.common.pages :as cp] +;; [uxbox.common.geom.shapes :as geom] +;; [uxbox.common.geom.point :as gpt] +;; [uxbox.main.ui.icons :as i] +;; [uxbox.main.data.workspace :as dw] +;; [uxbox.main.refs :as refs] +;; [uxbox.main.store :as st] +;; [uxbox.main.ui.keyboard :as kbd] +;; [uxbox.main.ui.shapes.icon :as icon] +;; [uxbox.util.dom :as dom] +;; [uxbox.util.dom.dnd :as dnd] +;; [uxbox.util.timers :as timers] +;; [uxbox.common.uuid :as uuid] +;; [uxbox.util.i18n :as i18n :refer [tr]] +;; [uxbox.util.data :refer [classnames]] +;; [uxbox.main.ui.components.tab-container :refer [tab-container tab-element]] +;; [uxbox.main.data.library :as dlib] +;; [uxbox.main.ui.components.context-menu :refer [context-menu]])) +;; +;; ;; --- Refs +;; +;; (defn libraries-ref [section] +;; (-> (l/in [:library section]) +;; (l/derived st/state))) +;; +;; (defn selected-items-ref [section library-id] +;; (-> (l/in [:library-items section library-id]) +;; (l/derived st/state))) +;; +;; (defn selected-library-ref [section] +;; (-> (l/in [:library-selected section]) +;; (l/derived st/state))) +;; +;; (defn selected-filter-ref [section] +;; (-> (l/in [:library-filter section]) +;; (l/derived st/state))) +;; +;; (defmulti shape-from-item (fn [type _] type)) +;; +;; (defmethod shape-from-item :icons [_ item] +;; (-> (cp/make-minimal-shape :icon) +;; (merge item) +;; (geom/resize (-> item :metadata :width) (-> item :metadata :height)) +;; (geom/absolute-move (gpt/point 0 0)))) +;; +;; (defmethod shape-from-item :images [_ item] +;; (let [metadata (select-keys item [:width :height :thumb-width +;; :thumb-height :thumb-uri :uri])] +;; (-> (cp/make-minimal-shape :image) +;; (merge item) +;; (assoc :metadata metadata) +;; (geom/resize (-> item :width) (-> item :height)) +;; (geom/absolute-move (gpt/point 0 0))))) +;; +;; ;; --- Components +;; +;; (mf/defc library-tab [{:keys [libraries section]}] +;; (when (and libraries (-> libraries count (> 0))) +;; (let [state (mf/use-state {:drag-style false}) +;; first-id (-> libraries first :id) +;; current-selection (or (mf/deref (selected-library-ref section)) first-id)] +;; +;; ;; Check if the current selection is in the list of libraries +;; (mf/use-effect +;; (mf/deps libraries) +;; #(when (not (some (fn [it] (= current-selection (-> it :id))) libraries)) +;; (st/emit! (dlib/select-library section first-id)))) +;; +;; ;; Retrieve the library data given the current selected library +;; (mf/use-effect +;; (mf/deps current-selection) +;; #(st/emit! (dlib/retrieve-library-data section current-selection))) +;; +;; [:div.library-tab +;; {:class (classnames :icons-tab (= section :icons) +;; :images-tab (= section :images))} +;; [:select.input-select.library-tab-libraries +;; {:value current-selection +;; :on-change #(st/emit! (dlib/select-library section (-> % dom/get-target dom/get-value uuid)))} +;; (for [library libraries] +;; [:option.library-tab-libraries-item +;; {:key (:id library) +;; :value (:id library)} +;; (:name library)])] +;; [:div.library-tab-content +;; (let [items (mf/deref (selected-items-ref section current-selection))] +;; (for [item items] +;; [:div.library-tab-element +;; {:draggable true +;; :class (classnames :is-dragging (:drag-style @state)) +;; :key (str (:id item)) +;; :on-drag-start (fn [event] +;; (swap! state assoc :drag-style true) +;; (dnd/set-data! event "uxbox/shape" (shape-from-item section item)) +;; (dnd/set-allowed-effect! event "move") +;; ;; This state is so we can give custom css to the dragging +;; (timers/schedule #(swap! state assoc :drag-style false)))} +;; (if (= section :icons) +;; [:svg {:view-box (->> item :metadata :view-box (str/join " ")) +;; :width (-> item :metadata :width) +;; :height (-> item :metadata :height) +;; :dangerouslySetInnerHTML {:__html (:content item)}}] +;; [:img {:draggable false +;; :src (:thumb-uri item)}]) +;; [:span.library-tab-element-name (:name item)]]))]]))) +;; +;; (mf/defc libraries-toolbox +;; [{:keys [key]}] +;; (let [state (mf/use-state {:menu-open false}) +;; selected-filter (fn [section] (or (mf/deref (selected-filter-ref section)) :all)) +;; team-id (-> refs/workspace-project mf/deref :team-id) +;; +;; filter-to-str {:all (tr "workspace.library.all") +;; :own (tr "workspace.library.own") +;; :store (tr "workspace.library.store")} +;; +;; select-option +;; (fn [option] +;; (st/emit! +;; (dlib/change-library-filter :icons option) +;; (dlib/change-library-filter :images option))) +;; +;; filter-libraries +;; (fn [section libraries] +;; (case (selected-filter section) +;; :all (-> libraries vals flatten) +;; :own (libraries team-id) +;; :store (libraries uuid/zero))) +;; +;; get-libraries +;; (fn [section] (->> (libraries-ref section) +;; mf/deref +;; (filter-libraries section)))] +;; +;; (mf/use-effect +;; (mf/deps team-id) +;; #(when team-id +;; (st/emit! (dlib/retrieve-libraries :icons) +;; (dlib/retrieve-libraries :images) +;; (dlib/retrieve-libraries :icons team-id) +;; (dlib/retrieve-libraries :images team-id)))) +;; +;; [:div#libraries.tool-window +;; [:div.libraries-window-bar +;; [:div.libraries-window-bar-title (tr "workspace.library.libraries")] +;; [:div.libraries-window-bar-options +;; {:on-click #(swap! state assoc :menu-open true)} +;; (filter-to-str (selected-filter :icons)) +;; [:button +;; { +;; :type "button"} +;; i/arrow-slide +;; [:& context-menu +;; {:selectable true +;; :show (:menu-open @state) +;; :selected (filter-to-str (selected-filter :icons)) +;; :on-close #(swap! state assoc :menu-open false) +;; :options (mapv (fn [[key val]] [val #(select-option key)]) filter-to-str)}]]]] +;; +;; [:div.tool-window-content +;; [:& tab-container {} +;; [:& tab-element +;; {:id :icons :title (tr "workspace.library.icons")} +;; [:& library-tab {:section :icons +;; :libraries (get-libraries :icons) }]] +;; +;; [:& tab-element +;; {:id :images :title (tr "workspace.library.images")} +;; [:& library-tab {:section :images +;; :libraries (get-libraries :images)}]]]]])) +;; +;; diff --git a/frontend/src/uxbox/main/ui/workspace/viewport.cljs b/frontend/src/uxbox/main/ui/workspace/viewport.cljs index 3bf481f48..df1e6e4d5 100644 --- a/frontend/src/uxbox/main/ui/workspace/viewport.cljs +++ b/frontend/src/uxbox/main/ui/workspace/viewport.cljs @@ -353,10 +353,10 @@ (let [shape {:name name :metadata {:width (:width image) :height (:height image) - :uri (:uri image) - :thumb-width (:thumb-width image) - :thumb-height (:thumb-height image) - :thumb-uri (:thumb-uri image)}} + :uri (:uri image)}} + ;; :thumb-width (:thumb-width image) + ;; :thumb-height (:thumb-height image) + ;; :thumb-uri (:thumb-uri image)}} aspect-ratio (/ (:width image) (:height image))] (st/emit! (dw/create-and-add-shape :image shape aspect-ratio)))) @@ -381,11 +381,11 @@ urls (filter #(and (not (str/blank? %)) (not (str/starts-with? % "#"))) lines)] - (run! #(st/emit! (dw/add-image-from-url % on-uploaded)) urls)) + (run! #(st/emit! (dw/add-media-object-from-url % on-uploaded)) urls)) :else (let [files (dnd/get-files event)] - (run! #(st/emit! (dw/upload-image % on-uploaded)) files)))) + (run! #(st/emit! (dw/upload-media-object % on-uploaded)) files)))) on-resize (fn [event]