diff --git a/backend/src/uxbox/media_loader.clj b/backend/src/uxbox/media_loader.clj index e8809981e..fe791cdf9 100644 --- a/backend/src/uxbox/media_loader.clj +++ b/backend/src/uxbox/media_loader.clj @@ -449,7 +449,7 @@ [path] (let [[basedir libraries] (read-file path)] (db/with-atomic [conn db/pool] - (let [project-id (create-project-if-not-exists conn {:name "Media loader"})] + (let [project-id (create-project-if-not-exists conn {:name "System libraries"})] (run! #(process-library conn basedir project-id %) libraries))))) (defn -main diff --git a/backend/src/uxbox/services/mutations/colors.clj b/backend/src/uxbox/services/mutations/colors.clj index 2d5329462..ee6143027 100644 --- a/backend/src/uxbox/services/mutations/colors.clj +++ b/backend/src/uxbox/services/mutations/colors.clj @@ -161,9 +161,10 @@ (def ^:private sql:select-color-for-update "select c.*, - lib.team_id as team_id + p.team_id as team_id from color as c - inner join color_library as lib on (lib.id = c.library_id) + inner join file as f on f.id = c.file_id + inner join project as p on p.id = f.project_id where c.id = ? for update of c") @@ -175,6 +176,26 @@ row)) +;; --- Mutation: Update Color + +(s/def ::update-color + (s/keys :req-un [::profile-id ::id ::content])) + +(sm/defmutation ::update-color + [{:keys [profile-id id content] :as params}] + (db/with-atomic [conn db/pool] + (let [clr (select-color-for-update conn id) + ;; IMPORTANT: if the previous name was equal to the hex content, + ;; we must rename it in addition to changing the value. + new-name (if (= (:name clr) (:content clr)) + content + (:name clr))] + (teams/check-edition-permissions! conn profile-id (:team-id clr)) + (db/update! conn :color + {:name new-name + :content content} + {:id id})))) + ;; --- Delete Color (declare delete-color) diff --git a/backend/src/uxbox/services/mutations/teams.clj b/backend/src/uxbox/services/mutations/teams.clj index 62c977a76..5867f90ee 100644 --- a/backend/src/uxbox/services/mutations/teams.clj +++ b/backend/src/uxbox/services/mutations/teams.clj @@ -71,7 +71,8 @@ (defn check-edition-permissions! [conn profile-id team-id] (let [row (db/exec-one! conn [sql:team-permissions profile-id team-id])] - (when-not (or (:can-edit row) + (when-not (or (= team-id uuid/zero) + (:can-edit row) (:is-admin row) (:is-owner row)) (ex/raise :type :validation diff --git a/backend/src/uxbox/services/queries/teams.clj b/backend/src/uxbox/services/queries/teams.clj index 43a2d4844..031b12e0f 100644 --- a/backend/src/uxbox/services/queries/teams.clj +++ b/backend/src/uxbox/services/queries/teams.clj @@ -30,7 +30,8 @@ (defn check-edition-permissions! [conn profile-id team-id] (let [row (db/exec-one! conn [sql:team-permissions profile-id team-id])] - (when-not (or (:can-edit row) + (when-not (or (= team-id uuid/zero) ;; We can write global-project owned items + (:can-edit row) (:is-admin row) (:is-owner row)) (ex/raise :type :validation @@ -39,10 +40,9 @@ (defn check-read-permissions! [conn profile-id team-id] (let [row (db/exec-one! conn [sql:team-permissions profile-id team-id])] - (when-not (or (:can-edit row) + (when-not (or (= team-id uuid/zero) ;; We can read global-project owned items + (:can-edit row) (:is-admin row) - (:is-owner row) - ;; We can read global-project owned items - (= team-id #uuid "00000000-0000-0000-0000-000000000000")) + (:is-owner row)) (ex/raise :type :validation :code :not-authorized)))) diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json index f8633e264..7fc274e08 100644 --- a/frontend/resources/locales.json +++ b/frontend/resources/locales.json @@ -522,7 +522,7 @@ } }, "ds.button.save" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:55" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:55", "src/uxbox/main/ui/workspace/sidebar/assets.cljs:69" ], "translations" : { "en" : "Save", "fr" : "Sauvegarder", @@ -657,7 +657,7 @@ } }, "errors.image-format-unsupported" : { - "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:370", "src/uxbox/main/data/users.cljs:177", "src/uxbox/main/data/images.cljs:376" ], + "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:390", "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).", "fr" : "Le format d'image n'est pas supporté (doit être svg, jpg ou png).", @@ -666,7 +666,7 @@ } }, "errors.image-too-large" : { - "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:368", "src/uxbox/main/data/users.cljs:175", "src/uxbox/main/data/images.cljs:374" ], + "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:388", "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).", "fr" : "L'image est trop grande (doit être inférieure à 5 Mo).", @@ -675,7 +675,7 @@ } }, "errors.image-type-mismatch" : { - "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:335", "src/uxbox/main/data/workspace/persistence.cljs:385", "src/uxbox/main/data/users.cljs:191", "src/uxbox/main/data/images.cljs:391" ], + "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:355", "src/uxbox/main/data/workspace/persistence.cljs:405", "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.", "fr" : "", @@ -684,7 +684,7 @@ } }, "errors.image-type-not-allowed" : { - "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:332", "src/uxbox/main/data/workspace/persistence.cljs:382", "src/uxbox/main/data/users.cljs:188", "src/uxbox/main/data/images.cljs:388" ], + "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:352", "src/uxbox/main/data/workspace/persistence.cljs:402", "src/uxbox/main/data/users.cljs:188", "src/uxbox/main/data/images.cljs:388" ], "translations" : { "en" : "Seems that this is not a valid image.", "fr" : "", @@ -729,7 +729,7 @@ } }, "errors.unexpected-error" : { - "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:338", "src/uxbox/main/data/workspace/persistence.cljs:388", "src/uxbox/main/data/users.cljs:194", "src/uxbox/main/data/images.cljs:394", "src/uxbox/main/ui/settings/change_email.cljs:51", "src/uxbox/main/ui/workspace/sidebar/options/exports.cljs:65", "src/uxbox/main/ui/auth/register.cljs:54" ], + "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:358", "src/uxbox/main/data/workspace/persistence.cljs:408", "src/uxbox/main/data/users.cljs:194", "src/uxbox/main/data/images.cljs:394", "src/uxbox/main/ui/settings/change_email.cljs:51", "src/uxbox/main/ui/workspace/sidebar/options/exports.cljs:65", "src/uxbox/main/ui/auth/register.cljs:54" ], "translations" : { "en" : "An unexpected error occurred.", "fr" : "Une erreur inattendue c'est produite", @@ -774,7 +774,7 @@ } }, "image.loading" : { - "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:346", "src/uxbox/main/data/workspace/persistence.cljs:397", "src/uxbox/main/data/users.cljs:201", "src/uxbox/main/data/images.cljs:403" ], + "used-in" : [ "src/uxbox/main/data/workspace/persistence.cljs:366", "src/uxbox/main/data/workspace/persistence.cljs:417", "src/uxbox/main/data/users.cljs:201", "src/uxbox/main/data/images.cljs:403" ], "translations" : { "en" : "Loading image...", "fr" : "Chargement de l'image...", @@ -783,7 +783,7 @@ } }, "modal.create-color.new-color" : { - "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:49" ], + "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:49", "src/uxbox/main/ui/workspace/sidebar/assets.cljs:62" ], "translations" : { "en" : "New Color", "fr" : "Nouvelle couleur", @@ -1359,7 +1359,7 @@ } }, "workspace.assets.assets" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:144" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:325" ], "translations" : { "en" : "Assets", "fr" : "", @@ -1368,7 +1368,7 @@ } }, "workspace.assets.box-filter-all" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:154" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:342" ], "translations" : { "en" : "All assets", "fr" : "", @@ -1377,7 +1377,7 @@ } }, "workspace.assets.box-filter-colors" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:156" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:344" ], "translations" : { "en" : "Colors", "fr" : "", @@ -1386,7 +1386,7 @@ } }, "workspace.assets.box-filter-graphics" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:155" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:343" ], "translations" : { "en" : "Graphics", "fr" : "", @@ -1395,7 +1395,7 @@ } }, "workspace.assets.colors" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:91" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:247" ], "translations" : { "en" : "Colors", "fr" : "", @@ -1404,7 +1404,7 @@ } }, "workspace.assets.delete" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:83" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:136", "src/uxbox/main/ui/workspace/sidebar/assets.cljs:231" ], "translations" : { "en" : "Delete", "fr" : "", @@ -1412,8 +1412,17 @@ "es" : "Borrar" } }, + "workspace.assets.edit" : { + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:230" ], + "translations" : { + "en" : "Edit", + "fr" : "", + "ru" : "", + "es" : "Editar" + } + }, "workspace.assets.file-library" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:104" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:271" ], "translations" : { "en" : "File library", "fr" : "", @@ -1422,7 +1431,7 @@ } }, "workspace.assets.graphics" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:68" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:113" ], "translations" : { "en" : "Graphics", "fr" : "", @@ -1430,8 +1439,26 @@ "es" : "Gráficos" } }, + "workspace.assets.not-found" : { + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:282" ], + "translations" : { + "en" : "No assets found", + "fr" : "", + "ru" : "", + "es" : "No se encontraron recursos" + } + }, + "workspace.assets.rename" : { + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:229" ], + "translations" : { + "en" : "Rename", + "fr" : "", + "ru" : "", + "es" : "Renombrar" + } + }, "workspace.assets.search" : { - "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:147" ], + "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/assets.cljs:329" ], "translations" : { "en" : "Search assets", "fr" : "", diff --git a/frontend/resources/styles/main/partials/sidebar-assets.scss b/frontend/resources/styles/main/partials/sidebar-assets.scss index bd9823d4c..713720ccd 100644 --- a/frontend/resources/styles/main/partials/sidebar-assets.scss +++ b/frontend/resources/styles/main/partials/sidebar-assets.scss @@ -15,16 +15,14 @@ margin: $small $small 0 $small; } - .search-input { - background-color: $color-gray-50; + .search-block { border: 1px solid $color-gray-30; - color: $color-gray-10; - font-size: $fs12; margin: $small $small 0 $small; padding: $x-small; + display: flex; + align-items: center; - &:focus { - color: lighten($color-gray-10, 8%); + &:focus-within { border-color: $color-primary !important; } @@ -32,6 +30,35 @@ border-color: $color-gray-20; } + & .search-input { + background-color: $color-gray-50; + border: none; + color: $color-gray-10; + font-size: $fs12; + margin: 0; + padding: 0; + flex-grow: 1; + + &:focus { + color: lighten($color-gray-10, 8%); + } + } + + & .search-icon { + display: flex; + align-items: center; + + svg { + fill: $color-gray-30; + height: 15px; + width: 15px; + } + + &.close { + transform: rotate(45deg); + cursor: pointer; + } + } } .input-select { @@ -104,6 +131,7 @@ align-items: center; justify-content: center; position: relative; + cursor: pointer; & img { max-height: 100%; @@ -136,6 +164,7 @@ } .group-list { + max-height: 30rem; overflow-y: scroll; } @@ -145,6 +174,7 @@ margin-top: $x-small; font-size: $fs11; color: $color-white; + cursor: pointer; & .color-block { width: 20px; diff --git a/frontend/src/uxbox/main/data/colors.cljs b/frontend/src/uxbox/main/data/colors.cljs index 0f80684df..1a34fc97d 100644 --- a/frontend/src/uxbox/main/data/colors.cljs +++ b/frontend/src/uxbox/main/data/colors.cljs @@ -10,6 +10,7 @@ [beicon.core :as rx] [clojure.set :as set] [potok.core :as ptk] + [uxbox.common.data :as d] [uxbox.common.spec :as us] [uxbox.main.repo :as rp] [uxbox.main.store :as st] @@ -249,21 +250,85 @@ (declare create-color-result) (defn create-color - [library-id color] - (s/assert (s/nilable uuid?) library-id) + [file-id color] + (s/assert (s/nilable uuid?) file-id) (ptk/reify ::create-color ptk/WatchEvent (watch [_ state s] - (->> (rp/mutation! :create-color {:library-id library-id + (->> (rp/mutation! :create-color {:file-id file-id :content color :name color}) - (rx/map (partial create-color-result library-id)))))) + (rx/map (partial create-color-result file-id)))))) (defn create-color-result - [library-id item] + [file-id color] (ptk/reify ::create-color-result ptk/UpdateEvent (update [_ state] (-> state - (update-in [:library-items :palettes library-id] #(into [item] %) ))))) + (assoc-in [:workspace-colors (:id color)] color) + (assoc-in [:workspace-local :color-for-rename] (:id color)))))) + +(def clear-color-for-rename + (ptk/reify ::clear-color-for-rename + ptk/UpdateEvent + (update [_ state] + (assoc-in state [:workspace-local :color-for-rename] nil)))) + +(declare rename-color-result) + +(defn rename-color + [file-id color-id name] + (ptk/reify ::rename-color + ptk/WatchEvent + (watch [_ state stream] + (->> (rp/mutation! :rename-color {:id color-id + :name name}) + (rx/map (partial rename-color-result file-id)))))) + +(defn rename-color-result + [file-id color] + (ptk/reify ::rename-color-result + ptk/UpdateEvent + (update [_ state] + (-> state + (assoc-in [:workspace-colors (:id color)] color))))) + +(declare update-color-result) + +(defn update-color + [file-id color-id content] + (ptk/reify ::update-color + ptk/WatchEvent + (watch [_ state stream] + (->> (rp/mutation! :update-color {:id color-id + :content content}) + (rx/map (partial update-color-result file-id)))))) + +(defn update-color-result + [file-id color] + (ptk/reify ::update-color-result + ptk/UpdateEvent + (update [_ state] + (-> state + (assoc-in [:workspace-colors (:id color)] color))))) + +(declare delete-color-result) + +(defn delete-color + [file-id color-id] + (ptk/reify ::delete-color + ptk/WatchEvent + (watch [_ state stream] + (->> (rp/mutation! :delete-color {:id color-id}) + (rx/map #(delete-color-result file-id color-id)))))) + +(defn delete-color-result + [file-id color-id] + (ptk/reify ::delete-color-result + ptk/UpdateEvent + (update [_ state] + (-> state + (d/dissoc-in [:workspace-colors color-id]))))) + diff --git a/frontend/src/uxbox/main/data/workspace/persistence.cljs b/frontend/src/uxbox/main/data/workspace/persistence.cljs index 6026d8dab..f0a72e8ed 100644 --- a/frontend/src/uxbox/main/data/workspace/persistence.cljs +++ b/frontend/src/uxbox/main/data/workspace/persistence.cljs @@ -324,7 +324,7 @@ ;; --- Upload Image (declare image-uploaded) -(def allowed-file-types #{"image/jpeg" "image/png" "image/webp"}) +(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 diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/assets.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/assets.cljs index c9e323767..1cf18c409 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/assets.cljs @@ -19,6 +19,7 @@ [uxbox.main.ui.icons :as i] [uxbox.main.data.workspace :as dw] [uxbox.main.data.images :as di] + [uxbox.main.data.colors :as dcol] [uxbox.main.refs :as refs] [uxbox.main.store :as st] [uxbox.main.ui.keyboard :as kbd] @@ -30,18 +31,46 @@ [uxbox.util.i18n :as i18n :refer [tr]] [uxbox.util.data :refer [classnames]] [uxbox.main.data.library :as dlib] + [uxbox.main.ui.modal :as modal] + [uxbox.main.ui.colorpicker :refer [colorpicker most-used-colors]] [uxbox.main.ui.components.tab-container :refer [tab-container tab-element]] [uxbox.main.ui.components.file-uploader :refer [file-uploader]] [uxbox.main.ui.components.context-menu :refer [context-menu]])) (defn matches-search [name search-term] - (if (empty? search-term) + (if (str/empty? search-term) true (let [st (str/trim (str/lower search-term)) nm (str/trim (str/lower name))] (str/includes? nm st)))) +(mf/defc modal-edit-color + [{:keys [color-value on-accept on-cancel] :as ctx}] + (let [state (mf/use-state {:current-color color-value})] + (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) + :disable-opacity true + :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]]))) + (mf/defc graphics-box [{:keys [library-id images] :as props}] (let [state (mf/use-state {:menu-open false @@ -104,25 +133,125 @@ :on-close #(swap! state assoc :menu-open false) :top (:top @state) :left (:left @state) - :options [[(tr "workspace.assets.delete") delete-graphic]]}]] - ])) + :options [[(tr "workspace.assets.delete") delete-graphic]]}]]])) + + +(mf/defc color-item + [{:keys [color library-id] :as props}] + (let [workspace-local @refs/workspace-local + color-for-rename (:color-for-rename workspace-local) + + edit-input-ref (mf/use-ref) + + state (mf/use-state {:menu-open false + :top nil + :left nil + :editing (= color-for-rename (:id color))}) + + rename-color + (fn [name] + (st/emit! (dcol/rename-color library-id (:id color) name))) + + edit-color + (fn [value opacity] + (st/emit! (dcol/update-color library-id (:id color) value))) + + delete-color + (fn [] + (st/emit! (dcol/delete-color library-id (:id color)))) + + rename-color-clicked + (fn [event] + (dom/prevent-default event) + (swap! state assoc :editing true)) + + input-blur + (fn [event] + (let [target (dom/event->target event) + name (dom/get-value target)] + (rename-color name) + (st/emit! dcol/clear-color-for-rename) + (swap! state assoc :editing false))) + + input-key-down + (fn [event] + (when (kbd/esc? event) + (st/emit! dcol/clear-color-for-rename) + (swap! state assoc :editing false)) + (when (kbd/enter? event) + (input-blur event))) + + edit-color-clicked + (fn [event] + (modal/show! modal-edit-color + {:color-value (:content color) + :on-accept edit-color})) + + on-context-menu + (fn [event] + (let [pos (dom/get-client-position event) + top (:y pos) + left (- (:x pos) 20)] + (dom/prevent-default event) + (swap! state assoc + :menu-open true + :top top + :left left)))] + + (mf/use-effect + (mf/deps (:editing @state)) + #(when (:editing @state) + (let [edit-input (mf/ref-val edit-input-ref)] + (dom/select-text! edit-input)) + nil)) + + [:div.group-list-item {:on-context-menu on-context-menu} + [:div.color-block {:style {:background-color (:content color)}}] + (if (:editing @state) + [:input.element-name + {:type "text" + :ref edit-input-ref + :on-blur input-blur + :on-key-down input-key-down + :auto-focus true + :default-value (:name color "")}] + [:div.name-block + {:on-double-click rename-color-clicked} + (:name color) + (when-not (= (:name color) (:content color)) + [:span (:content color)])]) + [:& 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.rename") rename-color-clicked] + [(tr "workspace.assets.edit") edit-color-clicked] + [(tr "workspace.assets.delete") delete-color]]}]])) (mf/defc colors-box - [{:keys [colors] :as props}] - (let [add-color #(println "añadir color")] + [{:keys [library-id colors] :as props}] + (let [add-color + (fn [value opacity] + (st/emit! (dcol/create-color library-id value))) + + add-color-clicked + (fn [event] + (modal/show! modal-edit-color + {:color-value "#406280" + :on-accept add-color}))] + [:div.asset-group [:div.group-title (tr "workspace.assets.colors") [:span (str "\u00A0(") (count colors) ")"] ;; Unicode 00A0 is non-breaking space - [:div.group-button {:on-click add-color} i/plus]] + [:div.group-button {:on-click add-color-clicked} i/plus]] [:div.group-list (for [color (sort-by :name colors)] - [:div.group-list-item {:key (:name color) - :on-context-menu #(println "context")} - [:div.color-block {:style {:background-color (:content color)}}] - (:name color) - (when-not (= (:name color) (:content color)) - [:span (:content color)])])]])) + [:& color-item {:key (:id color) + :color color + :library-id library-id}])]])) (mf/defc library-toolbox [{:keys [library-id @@ -141,11 +270,18 @@ i/arrow-slide] [:span (tr "workspace.assets.file-library")]] (when @open? - [:div.tool-window-content - (when (or (= box-filter :all) (= box-filter :graphics)) - [:& graphics-box {:library-id library-id :images images}]) - (when (or (= box-filter :all) (= box-filter :colors)) - [:& colors-box {:colors colors}])])])) + (let [show-graphics (and (or (= box-filter :all) (= box-filter :graphics)) + (or (> (count images) 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}]) + (when show-colors + [:& colors-box {:library-id library-id :colors colors}]) + (when (and (not show-graphics) (not show-colors)) + [:div.asset-group + [:div.group-title (tr "workspace.assets.not-found")]])]))])) (mf/defc assets-toolbox [] @@ -160,7 +296,8 @@ filtered-images (filter #(matches-search (:name %) (:search-term @state)) (vals file-images)) - filtered-colors (filter #(matches-search (:name %) (:search-term @state)) + filtered-colors (filter #(or (matches-search (:name %) (:search-term @state)) + (matches-search (:content %) (:search-term @state))) (vals file-colors)) on-search-term-change (fn [event] @@ -168,6 +305,9 @@ (dom/get-value))] (swap! state assoc :search-term value))) + on-search-clear-click (fn [event] + (swap! state assoc :search-term "")) + on-box-filter-change (fn [event] (let [value (-> (dom/get-target event) (dom/get-value) @@ -186,11 +326,18 @@ [:div.tool-window-content [:div.assets-bar-title (tr "workspace.assets.assets")] - [:input.search-input - {:placeholder (tr "workspace.assets.search") - :type "text" - :value (:search-term @state) - :on-change on-search-term-change}] + [:div.search-block + [:input.search-input + {:placeholder (tr "workspace.assets.search") + :type "text" + :value (:search-term @state) + :on-change on-search-term-change}] + (if (str/empty? (:search-term @state)) + [:div.search-icon + i/search] + [:div.search-icon.close + {:on-click on-search-clear-click} + i/close])] [:select.input-select {:value (:box-filter @state) :on-change on-box-filter-change} diff --git a/sample_media/config.edn b/sample_media/config.edn index c5512e976..3a68db24c 100644 --- a/sample_media/config.edn +++ b/sample_media/config.edn @@ -49,7 +49,17 @@ ;; Images {:name "Unsplash" :images {:path "./images/unsplash" - :regex #"^.*\.jpg$"}} + :regex #"^.*\.jpg$"} + :colors ["Chateau Green" "#419860" + "Toast" "#987567" + "Confetti" "#EAC75B" + "Thunderbird" "#C23D1F" + "Coffee Bean" "#331113" + "Lavender Magenta" "#EF88DF" + "Persian Rose" "#F536A6" + "Royal Blue" "#5C4AEE" + "Biscay" "#202362" + "Olivine" "#98C277"]} ;; Colors {:name "Flat design"