diff --git a/common/src/app/common/files/repair.cljc b/common/src/app/common/files/repair.cljc index 016e187691..65ee79da46 100644 --- a/common/src/app/common/files/repair.cljc +++ b/common/src/app/common/files/repair.cljc @@ -68,16 +68,10 @@ (defmethod repair-error :child-not-found [_ {:keys [shape page-id args] :as error} file-data _] - (let [repair-shape - (fn [parent-shape] - ; Remove child shape from children list - (log/debug :hint " -> Remove child " :child-id (:child-id args)) - (update parent-shape :shapes d/removev #(= % (:child-id args))))] - - (log/info :hint "Repairing shape :child-not-found" :id (:id shape) :name (:name shape) :page-id page-id) - (-> (pcb/empty-changes nil page-id) - (pcb/with-file-data file-data) - (pcb/update-shapes [(:id shape)] repair-shape)))) + (log/info :hint "Repairing shape :child-not-found" :id (:id shape) :name (:name shape) :page-id page-id) + (-> (pcb/empty-changes nil page-id) + (pcb/with-file-data file-data) + (pcb/change-parent (:parent-id args) [shape] nil {:component-swap true}))) (defmethod repair-error :frame-not-found [_ {:keys [shape page-id] :as error} file-data _] diff --git a/common/src/app/common/files/validate.cljc b/common/src/app/common/files/validate.cljc index 2d7b27b552..fb37824739 100644 --- a/common/src/app/common/files/validate.cljc +++ b/common/src/app/common/files/validate.cljc @@ -64,7 +64,7 @@ (def ^:dynamic *errors* nil) (defn report-error! - [code hint shape file page & args] + [code hint shape file page & {:as args}] (if (some? *errors*) (vswap! *errors* conj {:code code :hint hint @@ -122,11 +122,12 @@ shape file page))) (doseq [child-id (:shapes shape)] - (when (nil? (ctst/get-shape page child-id)) - (report-error! :child-not-found - (str/ffmt "Child % not found" child-id) - shape file page - :child-id child-id))))))) + (let [child (ctst/get-shape page child-id)] + (when (or (nil? child) (not= (:parent-id child) (:id shape))) + (report-error! :child-not-found + (str/ffmt "Child % not found" child-id) + child file page + :parent-id (:id shape))))))))) (defn validate-frame! "Validate that the frame-id shape exists and is indeed a frame. Also diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index 7c599a0f76..e99eb6d5d8 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -338,7 +338,7 @@ [new-shape new-shapes _] (ctst/clone-object component-shape - uuid/zero + frame-id (if components-v2 (:objects component-page) (:objects component)) update-new-shape (fn [object _] object) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 0a7d1159be..f4aba0d051 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1318,7 +1318,8 @@ (rx/of (go-to-page page-id)) (->> stream (rx/filter (ptk/type? ::initialize-page)) - (rx/take 1)) + (rx/take 1) + (rx/observe-on :async)) (select-and-zoom shape-id))) redirect-to-file diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 046bc6dfdb..e6770c448b 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -817,7 +817,12 @@ id-new-component position page - libraries) + libraries + nil + (:parent-id shape) + (:frame-id shape)) + + ;; We need to set the same index as the original shape changes (pcb/change-parent changes (:parent-id shape) [new-shape] index {:component-swap true})] (rx/of (dch/commit-changes changes) (ptk/data-event :layout/update [(:id new-shape)]) diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 7e78d314b0..b7aaa379e6 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -144,10 +144,11 @@ (defn generate-instantiate-component "Generate changes to create a new instance from a component." ([changes objects file-id component-id position page libraries] - (generate-instantiate-component changes objects file-id component-id position page libraries nil nil)) + (generate-instantiate-component changes objects file-id component-id position page libraries nil nil nil)) - ([changes objects file-id component-id position page libraries old-id parent-id] + ([changes objects file-id component-id position page libraries old-id parent-id frame-id] (let [component (ctf/get-component libraries file-id component-id) + parent (when parent-id (get objects parent-id)) library (get libraries file-id) components-v2 (dm/get-in library [:data :options :components-v2]) @@ -161,7 +162,15 @@ first-shape (cond-> (first new-shapes) (not (nil? parent-id)) - (assoc :parent-id parent-id)) + (assoc :parent-id parent-id) + (and (not (nil? parent)) (= :frame (:type parent))) + (assoc :frame-id (:id parent)) + (and (not (nil? parent)) (not= :frame (:type parent))) + (assoc :frame-id (:frame-id parent)) + (and (not (nil? parent)) (ctn/in-any-component? objects parent)) + (dissoc :component-root) + (and (nil? parent) (not (nil? frame-id))) + (assoc :frame-id frame-id)) ;; on copy/paste old id is used later to reorder the paster layers changes (cond-> (pcb/add-object changes first-shape {:ignore-touched true}) diff --git a/frontend/src/app/main/data/workspace/media.cljs b/frontend/src/app/main/data/workspace/media.cljs index c81ede28ac..5cc682dd4d 100644 --- a/frontend/src/app/main/data/workspace/media.cljs +++ b/frontend/src/app/main/data/workspace/media.cljs @@ -17,7 +17,6 @@ [app.common.svg.shapes-builder :as csvg.shapes-builder] [app.common.types.container :as ctn] [app.common.types.shape :as cts] - [app.common.types.shape-tree :as ctst] [app.common.uuid :as uuid] [app.config :as cf] [app.main.data.media :as dmm] @@ -315,9 +314,9 @@ (defn create-shapes-img "Convert a media object that contains a bitmap image into shapes, one shape of type :rect containing an image fill and one group that contains it." - [pos {:keys [name width height id mtype] :as media-obj} & {:keys [wrapper-type] :or {wrapper-type :group}}] - (let [group-shape (cts/setup-shape - {:type wrapper-type + [pos {:keys [name width height id mtype] :as media-obj}] + (let [frame-shape (cts/setup-shape + {:type :frame :x (:x pos) :y (:y pos) :width width @@ -339,24 +338,18 @@ :height height :mtype mtype}}] :name name - :frame-id uuid/zero - :parent-id (:id group-shape)})] - (rx/of [group-shape [img-shape]]))) + :frame-id (:id frame-shape) + :parent-id (:id frame-shape)})] + (rx/of [frame-shape [img-shape]]))) (defn- add-shapes-and-component [it file-data page name [shape children]] - (let [page' (reduce #(ctst/add-shape (:id %2) %2 %1 uuid/zero (:parent-id %2) nil false) - page - (cons shape children)) - - shape' (ctn/get-shape page' (:id shape)) - - [component-shape component-shapes updated-shapes] - (ctn/make-component-shape shape' (:objects page') (:id file-data) true) + (let [[component-shape component-shapes updated-shapes] + (ctn/convert-shape-in-component shape children (:id file-data)) changes (-> (pcb/empty-changes it) - (pcb/with-page page') - (pcb/with-objects (:objects page')) + (pcb/with-page page) + (pcb/with-objects (:objects page)) (pcb/with-library-data file-data) (pcb/add-objects (cons shape children)) (pcb/add-component (:id component-shape) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 42ec617c2b..1055985030 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -380,7 +380,7 @@ (prepare-duplicate-guides shapes page ids-map delta))))) (defn- prepare-duplicate-component-change - [changes objects page component-root parent-id delta libraries library-data it] + [changes objects page component-root parent-id frame-id delta libraries library-data it] (let [component-id (:component-id component-root) file-id (:component-file component-root) main-component (ctf/get-component libraries file-id component-id) @@ -396,7 +396,8 @@ page libraries (:id component-root) - parent-id) + parent-id + frame-id) restore-component #(let [restore (dwlh/prepare-restore-component changes library-data (:component-id component-root) it page delta (:id component-root) parent-id)] @@ -419,7 +420,7 @@ changes (ctf/is-known-component? obj libraries) - (prepare-duplicate-component-change changes objects page obj parent-id delta libraries library-data it) + (prepare-duplicate-component-change changes objects page obj parent-id frame-id delta libraries library-data it) :else (let [frame? (cfh/frame-shape? obj) diff --git a/frontend/src/app/main/ui/export.scss b/frontend/src/app/main/ui/export.scss index 785f42bde1..01a15889a3 100644 --- a/frontend/src/app/main/ui/export.scss +++ b/frontend/src/app/main/ui/export.scss @@ -201,6 +201,7 @@ img, svg { object-fit: contain; + max-height: $s-40; } } } diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs index 9a67ca6821..79f76d5c50 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar.cljs @@ -66,8 +66,8 @@ :id "left-sidebar-aside" :data-size size :class (stl/css-case new-css-system - :global/settings-bar true - :global/settings-bar-left true + :global/settings-bar (not new-css-system) + :global/settings-bar-left (not new-css-system) :left-settings-bar true :global/two-row (<= size 300) :global/three-row (and (> size 300) (<= size 400)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs index a80a6cee90..0fa947541d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs @@ -17,7 +17,6 @@ [app.main.data.workspace.specialized-panel :as dwsp] [app.main.refs :as refs] [app.main.store :as st] - [app.main.ui.components.context-menu :refer [context-menu]] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.radio-buttons :refer [radio-button radio-buttons]] [app.main.ui.components.search-bar :refer [search-bar]] @@ -161,6 +160,7 @@ visible? (h/use-visible item-ref :once? true)] [:div {:ref item-ref + :title (if is-search (:full-name item) (:name item)) :class (stl/css-case :component-item (not listing-thumbs) :grid-cell listing-thumbs :selected (= (:id item) component-id) @@ -182,7 +182,8 @@ path (cfh/butlast-path group-name) on-group-click #(on-enter-group group-name)] [:div {:class (stl/css :component-group) - :key (uuid/next) :on-click on-group-click} + :key (uuid/next) :on-click on-group-click + :title group-name} [:div (when-not (str/blank? path) [:span {:class (stl/css :component-group-path)} (str "\u00A0/\u00A0" path)]) @@ -195,10 +196,10 @@ (let [single? (= 1 (count shapes)) shape (first shapes) current-file-id (mf/use-ctx ctx/current-file-id) - workspace-file (deref refs/workspace-file) - workspace-data (deref refs/workspace-data) - workspace-libraries (deref refs/workspace-libraries) - objects (deref refs/workspace-page-objects) + workspace-file (mf/deref refs/workspace-file) + workspace-data (mf/deref refs/workspace-data) + workspace-libraries (mf/deref refs/workspace-libraries) + objects (mf/deref refs/workspace-page-objects) libraries (assoc workspace-libraries current-file-id (assoc workspace-file :data workspace-data)) every-same-file? (every? #(= (:component-file shape) (:component-file %)) shapes) current-comp-id (when (every? #(= (:component-id shape) (:component-id %)) shapes) @@ -233,8 +234,15 @@ filters (deref filters*) is-search? (not (str/blank? (:term filters))) + current-library-id (if (contains? libraries (:file-id filters)) + (:file-id filters) + current-file-id) - components (->> (get-in libraries [(:file-id filters) :data :components]) + current-library-name (if (= current-library-id current-file-id) + (str/upper (tr "workspace.assets.local-library")) + (get-in libraries [current-library-id :name])) + + components (->> (get-in libraries [current-library-id :data :components]) vals (remove #(true? (:deleted %))) (map #(assoc % :full-name (cfh/merge-path-item (:path %) (:name %))))) @@ -255,7 +263,7 @@ groups (when-not is-search? (->> (sort (sequence xform components)) - (map #(assoc {} :name %)))) + (map #(assoc {} :name %)))) components (if is-search? (filter #(str/includes? (str/lower (:full-name %)) (str/lower (:term filters))) components) @@ -283,11 +291,6 @@ libraries-options (map (fn [library] {:value (:id library) :label (:name library)}) (vals libraries)) - current-library-id (:file-id filters) - current-library-name (if (= current-library-id current-file-id) - (str/upper (tr "workspace.assets.local-library")) - (get-in libraries [current-library-id :name])) - on-library-change (mf/use-fn (fn [id] @@ -296,7 +299,7 @@ on-search-term-change (mf/use-fn (fn [term] - (swap! filters* assoc :term term))) + (swap! filters* assoc :term term))) on-search-clear-click @@ -323,13 +326,13 @@ [:& search-bar {:on-change on-search-term-change :clear-action on-search-clear-click :value (:term filters) - :placeholder (str (tr "labels.search") " " (get-in libraries [(:file-id filters) :name])) + :placeholder (str (tr "labels.search") " " (get-in libraries [current-library-id :name])) :icon (mf/html [:span {:class (stl/css :search-icon)} i/search-refactor])}]] [:div {:class (stl/css :select-field)} [:& select {:class (stl/css :select-library) - :default-value (:file-id filters) + :default-value current-library-id :options libraries-options :on-change on-library-change}]] @@ -351,7 +354,8 @@ (if (or is-search? (str/empty? (:path filters))) [:div {:class (stl/css :component-path-empty)}] [:button {:class (stl/css :component-path) - :on-click on-go-back} + :on-click on-go-back + :title (:path filters)} [:span i/arrow-slide] [:span (:path filters)]]) @@ -364,7 +368,7 @@ :component-list (not (:listing-thumbs? filters)))} (for [item items] (if (:id item) - (let [data (get-in libraries [(:file-id filters) :data]) + (let [data (get-in libraries [current-library-id :data]) container (ctf/get-component-page data item) root-shape (ctf/get-component-root data item) loop? (or (contains? parent-components (:main-instance-id item)) @@ -372,7 +376,7 @@ [:& component-swap-item {:item item :loop loop? :shapes shapes - :file-id (:file-id filters) + :file-id current-library-id :root-shape root-shape :container container :component-id current-comp-id @@ -381,23 +385,20 @@ [:& component-group-item {:item item :on-enter-group on-enter-group}]))]]])) (mf/defc component-ctx-menu - [{:keys [menu-entries on-close show type] :as props}] - (case type - :context-menu - [:& context-menu {:on-close on-close - :show show - :options - (vec (for [entry menu-entries :when (not (nil? entry))] - [(tr (:msg entry)) (:action entry)]))}] - :dropdown - [:& dropdown {:show show :on-close on-close} - [:ul {:class (stl/css :custom-select-dropdown)} - (for [entry menu-entries :when (not (nil? entry))] - [:li {:key (uuid/next) - :class (stl/css :dropdown-element) - :on-click (:action entry)} - [:span {:class (stl/css :dropdown-label)} - (tr (:msg entry))]])]])) + [{:keys [menu-entries on-close show] :as props}] + (let [do-action + (fn [action event] + (dom/stop-propagation event) + (action) + (on-close))] + [:& dropdown {:show show :on-close on-close} + [:ul {:class (stl/css :custom-select-dropdown)} + (for [entry menu-entries :when (not (nil? entry))] + [:li {:key (uuid/next) + :class (stl/css :dropdown-element) + :on-click (partial do-action (:action entry))} + [:span {:class (stl/css :dropdown-label)} + (tr (:msg entry))]])]])) (mf/defc component-menu @@ -486,8 +487,7 @@ [:& component-ctx-menu {:show menu-open? :on-close on-menu-close - :menu-entries menu-entries - :type :dropdown}]]) + :menu-entries menu-entries}]]) (when (and can-swap? (not multi)) [:div {:class (stl/css :component-parent-name)} (cfh/merge-path-item (:path component) (:name component))])]] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss index 0d8ad621bb..9ae617d328 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.scss @@ -230,6 +230,11 @@ background-color: var(--assets-item-background-color); color: var(--assets-item-name-foreground-color); + .component-name { + @include textEllipsis; + width: 80%; + } + svg, img { background-color: var(--assets-component-background-color);