diff --git a/common/src/app/common/file_builder.cljc b/common/src/app/common/file_builder.cljc index 348c4fdd3..4a497cda5 100644 --- a/common/src/app/common/file_builder.cljc +++ b/common/src/app/common/file_builder.cljc @@ -319,7 +319,9 @@ create-child (fn [file child] (-> file - (create-svg-raw (assoc data :content child)) + (create-svg-raw (assoc data + :id (uuid/next) + :content child)) (close-svg-raw)))] ;; First :content is the the shape attribute, the other content is the diff --git a/frontend/resources/styles/main/partials/dashboard-grid.scss b/frontend/resources/styles/main/partials/dashboard-grid.scss index a491f9c7e..67aaa4ca5 100644 --- a/frontend/resources/styles/main/partials/dashboard-grid.scss +++ b/frontend/resources/styles/main/partials/dashboard-grid.scss @@ -6,6 +6,7 @@ .dashboard-grid { font-size: $fs14; + height: 100%; .grid-row { display: flex; diff --git a/frontend/src/app/main/exports.cljs b/frontend/src/app/main/exports.cljs index b6e6e9894..7dc497507 100644 --- a/frontend/src/app/main/exports.cljs +++ b/frontend/src/app/main/exports.cljs @@ -86,9 +86,9 @@ (mf/fnc svg-raw-wrapper [{:keys [shape frame] :as props}] (let [childs (mapv #(get objects %) (:shapes shape))] - (if (and (contains? shape :svg-attrs) - (map? (:content shape)) - (not= :svg (get-in shape [:content :tag]))) + (if (and (map? (:content shape)) + (or (= :svg (get-in shape [:content :tag])) + (contains? shape :svg-attrs))) [:> shape-container {:shape shape} [:& svg-raw-shape {:frame frame :shape shape diff --git a/frontend/src/app/main/ui/dashboard/file_menu.cljs b/frontend/src/app/main/ui/dashboard/file_menu.cljs index 8f73075b5..8a5556bb4 100644 --- a/frontend/src/app/main/ui/dashboard/file_menu.cljs +++ b/frontend/src/app/main/ui/dashboard/file_menu.cljs @@ -6,6 +6,7 @@ (ns app.main.ui.dashboard.file-menu (:require + [app.common.data :as d] [app.main.data.dashboard :as dd] [app.main.data.messages :as dm] [app.main.data.modal :as modal] @@ -155,12 +156,22 @@ :on-accept del-shared}))) on-export-files - (fn [_] - (st/emit! - (modal/show - {:type :export - :team-id current-team-id - :files (->> files (mapv :id))})))] + (mf/use-callback + (mf/deps files current-team-id) + (fn [_] + (->> (rx/from files) + (rx/flat-map + (fn [file] + (->> (rp/query :file-libraries {:file-id (:id file)}) + (rx/map #(assoc file :has-libraries? (d/not-empty? %)))))) + (rx/reduce conj []) + (rx/subs + (fn [files] + (st/emit! + (modal/show + {:type :export + :team-id current-team-id + :files (->> files (mapv :id))})))))))] (mf/use-effect (fn [] diff --git a/frontend/src/app/main/ui/dashboard/files.cljs b/frontend/src/app/main/ui/dashboard/files.cljs index 2ec487413..b982d8ced 100644 --- a/frontend/src/app/main/ui/dashboard/files.cljs +++ b/frontend/src/app/main/ui/dashboard/files.cljs @@ -44,7 +44,14 @@ (mf/deps project) (fn [event] (dom/prevent-default event) - (st/emit! (dd/create-file {:project-id (:id project)}))))] + (st/emit! (dd/create-file {:project-id (:id project)})))) + + on-import + (mf/use-callback + (mf/deps (:id project)) + (fn [] + (st/emit! (dd/fetch-files {:project-id (:id project)}) + (dd/clear-selected-files))))] [:header.dashboard-header @@ -65,7 +72,8 @@ :left (- (:x (:menu-pos @local)) 180) :top (:y (:menu-pos @local)) :on-edit on-edit - :on-menu-close on-menu-close}]])) + :on-menu-close on-menu-close + :on-import on-import}]])) [:div.dashboard-header-actions [:a.btn-secondary.btn-small {:on-click on-create-clicked} (tr "dashboard.new-file")] @@ -102,6 +110,6 @@ [:* [:& header {:team team :project project}] [:section.dashboard-container - [:& grid {:id (:id project) + [:& grid {:project-id (:id project) :files files}]]])) diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index c15b2e664..3bd48a1ce 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -13,6 +13,7 @@ [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.dashboard.file-menu :refer [file-menu]] + [app.main.ui.dashboard.import :refer [use-import-file]] [app.main.ui.dashboard.inline-edition :refer [inline-edition]] [app.main.ui.icons :as i] [app.main.worker :as wrk] @@ -210,22 +211,68 @@ [:div.text (tr "dashboard.loading-files")]]) (mf/defc grid - [{:keys [files] :as props}] - [:section.dashboard-grid - (cond - (nil? files) - [:& loading-placeholder] + [{:keys [files project-id] :as props}] + (let [dragging? (mf/use-state false) - (seq files) - [:div.grid-row - (for [item files] - [:& grid-item - {:file item - :key (:id item) - :navigate? true}])] + on-finish-import + (mf/use-callback + (fn [] + (st/emit! (dd/fetch-files {:project-id project-id}) + (dd/clear-selected-files)))) - :else - [:& empty-placeholder])]) + import-files (use-import-file project-id on-finish-import) + + on-drag-enter + (mf/use-callback + (fn [e] + (when (or (dnd/has-type? e "Files") + (dnd/has-type? e "application/x-moz-file")) + (dom/prevent-default e) + (reset! dragging? true)))) + + on-drag-over + (mf/use-callback + (fn [e] + (when (or (dnd/has-type? e "Files") + (dnd/has-type? e "application/x-moz-file")) + (dom/prevent-default e)))) + + on-drag-leave + (mf/use-callback + (fn [e] + (when-not (dnd/from-child? e) + (reset! dragging? false)))) + + + on-drop + (mf/use-callback + (fn [e] + (when (or (dnd/has-type? e "Files") + (dnd/has-type? e "application/x-moz-file")) + (dom/prevent-default e) + (reset! dragging? false) + (import-files (.-files (.-dataTransfer e))))))] + + [:section.dashboard-grid {:on-drag-enter on-drag-enter + :on-drag-over on-drag-over + :on-drag-leave on-drag-leave + :on-drop on-drop} + (cond + (nil? files) + [:& loading-placeholder] + + (seq files) + [:div.grid-row + (when @dragging? + [:div.grid-item]) + (for [item files] + [:& grid-item + {:file item + :key (:id item) + :navigate? true}])] + + :else + [:& empty-placeholder])])) (mf/defc line-grid-row [{:keys [files selected-files on-load-more dragging?] :as props}] @@ -285,10 +332,17 @@ (mf/defc line-grid [{:keys [project-id team-id files on-load-more] :as props}] (let [dragging? (mf/use-state false) - selected-files (mf/deref refs/dashboard-selected-files) selected-project (mf/deref refs/dashboard-selected-project) + on-finish-import + (mf/use-callback + (fn [] + (st/emit! (dd/fetch-recent-files) + (dd/clear-selected-files)))) + + import-files (use-import-file project-id on-finish-import) + on-drag-enter (mf/use-callback (mf/deps selected-project) @@ -298,13 +352,20 @@ (when-not (or (dnd/from-child? e) (dnd/broken-event? e)) (when (not= selected-project project-id) - (reset! dragging? true)))))) + (reset! dragging? true)))) + + (when (or (dnd/has-type? e "Files") + (dnd/has-type? e "application/x-moz-file")) + (dom/prevent-default e) + (reset! dragging? true)))) on-drag-over (mf/use-callback - (fn [e] - (when (dnd/has-type? e "penpot/files") - (dom/prevent-default e)))) + (fn [e] + (when (or (dnd/has-type? e "penpot/files") + (dnd/has-type? e "Files") + (dnd/has-type? e "application/x-moz-file")) + (dom/prevent-default e)))) on-drag-leave (mf/use-callback @@ -321,13 +382,20 @@ on-drop (mf/use-callback (mf/deps files selected-files) - (fn [_] - (reset! dragging? false) - (when (not= selected-project project-id) - (let [data {:ids (into #{} (keys selected-files)) - :project-id project-id} - mdata {:on-success on-drop-success}] - (st/emit! (dd/move-files (with-meta data mdata)))))))] + (fn [e] + (when (or (dnd/has-type? e "Files") + (dnd/has-type? e "application/x-moz-file")) + (dom/prevent-default e) + (reset! dragging? false) + (import-files (.-files (.-dataTransfer e)))) + + (when (dnd/has-type? e "penpot/files") + (reset! dragging? false) + (when (not= selected-project project-id) + (let [data {:ids (into #{} (keys selected-files)) + :project-id project-id} + mdata {:on-success on-drop-success}] + (st/emit! (dd/move-files (with-meta data mdata))))))))] [:section.dashboard-grid {:on-drag-enter on-drag-enter :on-drag-over on-drag-over diff --git a/frontend/src/app/main/ui/dashboard/project_menu.cljs b/frontend/src/app/main/ui/dashboard/project_menu.cljs index 8967e8a0c..f6923cc78 100644 --- a/frontend/src/app/main/ui/dashboard/project_menu.cljs +++ b/frontend/src/app/main/ui/dashboard/project_menu.cljs @@ -20,7 +20,7 @@ [rumext.alpha :as mf])) (mf/defc project-menu - [{:keys [project show? on-edit on-menu-close top left] :as props}] + [{:keys [project show? on-edit on-menu-close top left on-import] :as props}] (assert (some? project) "missing `project` prop") (assert (boolean? show?) "missing `show?` prop") (assert (fn? on-edit) "missing `on-edit` prop") @@ -84,8 +84,7 @@ on-finish-import (mf/use-callback (fn [] - (st/emit! (dd/fetch-recent-files) - (dd/clear-selected-files))))] + (when (some? on-import) (on-import))))] [:* [:& udi/import-form {:ref file-input @@ -106,7 +105,8 @@ [(tr "dashboard.move-to") nil (for [team teams] [(:name team) (on-move (:id team))])]) - [(tr "dashboard.import") on-import-files] + (when (some? on-import) + [(tr "dashboard.import") on-import-files]) [:separator] [(tr "labels.delete") on-delete]]}]])) diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index 66e12999a..768599da7 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -93,7 +93,13 @@ (fn [] (let [mdata {:on-success on-file-created} params {:project-id (:id project)}] - (st/emit! (dd/create-file (with-meta params mdata))))))] + (st/emit! (dd/create-file (with-meta params mdata)))))) + + on-import + (mf/use-callback + (fn [] + (st/emit! (dd/fetch-recent-files) + (dd/clear-selected-files))))] [:div.dashboard-project-row {:class (when first? "first")} [:div.project @@ -111,7 +117,8 @@ :left (:x (:menu-pos @local)) :top (:y (:menu-pos @local)) :on-edit on-edit-open - :on-menu-close on-menu-close}] + :on-menu-close on-menu-close + :on-import on-import}] [:span.info (str file-count " files")] (when (> file-count 0) diff --git a/frontend/src/app/main/ui/workspace/header.cljs b/frontend/src/app/main/ui/workspace/header.cljs index 18c51d3ec..ac9a6fd5f 100644 --- a/frontend/src/app/main/ui/workspace/header.cljs +++ b/frontend/src/app/main/ui/workspace/header.cljs @@ -6,12 +6,14 @@ (ns app.main.ui.workspace.header (:require + [app.common.data :as d] [app.common.math :as mth] [app.config :as cfg] [app.main.data.modal :as modal] [app.main.data.workspace :as dw] [app.main.data.workspace.shortcuts :as sc] [app.main.refs :as refs] + [app.main.repo :as rp] [app.main.store :as st] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.icons :as i] @@ -20,6 +22,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.router :as rt] + [beicon.core :as rx] [okulary.core :as l] [rumext.alpha :as mf])) @@ -135,12 +138,23 @@ (reset! editing? true)) on-export-files - (fn [_] - (st/emit! - (modal/show - {:type :export - :team-id team-id - :files [(:id file)]})))] + (mf/use-callback + (mf/deps file team-id) + (fn [_] + (->> (rx/of file) + (rx/flat-map + (fn [file] + (->> (rp/query :file-libraries {:file-id (:id file)}) + (rx/map #(assoc file :has-libraries? (d/not-empty? %)))))) + (rx/reduce conj []) + (rx/subs + (fn [files] + (st/emit! + (modal/show + {:type :export + :team-id team-id + :files (->> files (mapv :id))})))))))] + (mf/use-effect (mf/deps @editing?) #(when @editing? diff --git a/frontend/src/app/util/import/parser.cljs b/frontend/src/app/util/import/parser.cljs index 3c46a9218..8de2abf37 100644 --- a/frontend/src/app/util/import/parser.cljs +++ b/frontend/src/app/util/import/parser.cljs @@ -201,7 +201,13 @@ (merge (add-attrs {} (:attrs svg-node)) node-attrs)) (= type :svg-raw) - (->> node :content last) + (let [svg-content (get-data node :penpot:svg-content) + tag (-> svg-content :attrs :penpot:tag keyword) + + svg-node (if (= :svg tag) + (->> node :content last :content last) + (->> node :content last))] + (merge (add-attrs {} (:attrs svg-node)) node-attrs)) :else node-attrs)))