From 1823ecda400707e9d2c68f251cbde82ab07044e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Fri, 2 Oct 2020 10:26:36 +0200 Subject: [PATCH] :tada: Allow to rename a component in the library --- common/app/common/pages.cljc | 12 +++-- .../styles/main/partials/sidebar-assets.scss | 19 ++++++++ .../app/main/data/workspace/libraries.cljs | 21 ++++++++- .../main/ui/components/editable_label.cljs | 28 +++++++---- .../app/main/ui/workspace/sidebar/assets.cljs | 47 +++++++++++++++---- 5 files changed, 104 insertions(+), 23 deletions(-) diff --git a/common/app/common/pages.cljc b/common/app/common/pages.cljc index 348d98b47..c92015a04 100644 --- a/common/app/common/pages.cljc +++ b/common/app/common/pages.cljc @@ -523,7 +523,8 @@ (s/keys :req-un [::id ::name :internal.changes.add-component/shapes])) (defmethod change-spec :mod-component [_] - (s/keys :req-un [::id ::name :internal.changes.add-component/shapes])) + (s/keys :req-un [::id] + :opt-un [::name :internal.changes.add-component/shapes])) (defmethod change-spec :del-component [_] (s/keys :req-un [::id])) @@ -964,9 +965,12 @@ (defmethod process-change :mod-component [data {:keys [id name shapes]}] (update-in data [:components id] - #(assoc % - :name name - :objects (d/index-by :id shapes)))) + #(cond-> % + (some? name) + (assoc :name name) + + (some? shapes) + (assoc :objects (d/index-by :id shapes))))) (defmethod process-change :del-component [data {:keys [id]}] diff --git a/frontend/resources/styles/main/partials/sidebar-assets.scss b/frontend/resources/styles/main/partials/sidebar-assets.scss index 0b4df5b66..29938b238 100644 --- a/frontend/resources/styles/main/partials/sidebar-assets.scss +++ b/frontend/resources/styles/main/partials/sidebar-assets.scss @@ -213,9 +213,28 @@ left: 0; bottom: 0; width: 100%; + padding: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + + &.editing { + display: block; + } + + .editable-label-input { + border: 1px solid $color-gray-20; + border-radius: 3px; + font-size: $fs11; + padding: 2px; + margin: 0; + height: unset; + width: 100%; + } + + .editable-label-close { + display: none; + } } .grid-cell:hover { diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index bc864b7c0..7809f40fa 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -253,6 +253,25 @@ (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}) (dws/select-shapes (d/ordered-set (:id group)))))))))) +(defn rename-component + [id new-name] + (us/assert ::us/uuid id) + (us/assert ::us/string new-name) + (ptk/reify ::rename-component + ptk/WatchEvent + (watch [_ state stream] + (let [component (get-in state [:workspace-data :components id]) + + rchanges [{:type :mod-component + :id id + :name new-name}] + + uchanges [{:type :mod-component + :id id + :name (:name component)}]] + + (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) + (defn duplicate-component "Create a new component copied from the one with the given id." [{:keys [id] :as params}] @@ -279,7 +298,7 @@ :id (:id new-shape)}]] (rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))) - + (defn delete-component "Delete the component with the given id, from the current file library." [{:keys [id] :as params}] diff --git a/frontend/src/app/main/ui/components/editable_label.cljs b/frontend/src/app/main/ui/components/editable_label.cljs index fa2de3487..6fac66f56 100644 --- a/frontend/src/app/main/ui/components/editable_label.cljs +++ b/frontend/src/app/main/ui/components/editable_label.cljs @@ -17,35 +17,43 @@ [app.util.data :refer [classnames]])) (mf/defc editable-label - [{:keys [ value on-change on-cancel edit readonly class-name]}] + [{:keys [value on-change on-cancel editing? disable-dbl-click? class-name]}] (let [input (mf/use-ref nil) state (mf/use-state (:editing false)) - is-editing (or edit (:editing @state)) + is-editing (:editing @state) start-editing (fn [] (swap! state assoc :editing true) (timers/schedule 100 #(dom/focus! (mf/ref-val input)))) stop-editing (fn [] (swap! state assoc :editing false)) + accept-editing (fn [] + (when (:editing @state) + (let [value (-> (mf/ref-val input) dom/get-value)] + (on-change value) + (stop-editing)))) cancel-editing (fn [] (stop-editing) (when on-cancel (on-cancel))) - on-dbl-click (fn [e] (when (not readonly) (start-editing))) + on-dbl-click (fn [e] (when (not disable-dbl-click?) (start-editing))) on-key-up (fn [e] (cond (kbd/esc? e) (cancel-editing) (kbd/enter? e) - (let [value (-> e dom/get-target dom/get-value)] - (on-change value) - (stop-editing)))) - ] + (accept-editing)))] + + (mf/use-effect + (mf/deps editing?) + (fn [] + (when (and editing? (not (:editing @state))) + (start-editing)))) (if is-editing [:div.editable-label {:class class-name} [:input.editable-label-input {:ref input :default-value value - :on-key-down on-key-up}] + :on-key-up on-key-up + :on-blur cancel-editing}] [:span.editable-label-close {:on-click cancel-editing} i/close]] [:span.editable-label {:class class-name - :on-double-click on-dbl-click} value] - ))) + :on-double-click on-dbl-click} value]))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index 2eed058aa..ae5dd213b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -29,6 +29,7 @@ [app.main.ui.components.context-menu :refer [context-menu]] [app.main.ui.components.file-uploader :refer [file-uploader]] [app.main.ui.components.tab-container :refer [tab-container tab-element]] + [app.main.ui.components.editable-label :refer [editable-label]] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] [app.main.ui.keyboard :as kbd] @@ -47,6 +48,7 @@ (mf/defc components-box [{:keys [file-id local? components open? on-open on-close] :as props}] (let [state (mf/use-state {:menu-open false + :renaming nil :top nil :left nil :component-id nil}) @@ -62,6 +64,25 @@ (st/emit! (dwl/delete-component {:id (:component-id @state)})) (st/emit! (dwl/sync-file nil)))) + on-rename + (mf/use-callback + (mf/deps state) + (fn [] + (swap! state assoc :renaming (:component-id @state)))) + + do-rename + (mf/use-callback + (mf/deps state) + (fn [new-name] + (st/emit! (dwl/rename-component (:renaming @state) new-name)) + (swap! state assoc :renaming nil))) + + cancel-rename + (mf/use-callback + (mf/deps state) + (fn [] + (swap! state assoc :renaming nil))) + on-context-menu (mf/use-callback (fn [component-id] @@ -90,13 +111,22 @@ (when open? [:div.group-grid.big (for [component components] - [:div.grid-cell {:key (:id component) - :draggable true - :on-context-menu (on-context-menu (:id component)) - :on-drag-start (partial on-drag-start component)} - [:& exports/component-svg {:group (get-in component [:objects (:id component)]) - :objects (:objects component)}] - [:div.cell-name (:name component)]])]) + (let [renaming? (= (:renaming @state)(:id component))] + [:div.grid-cell {:key (:id component) + :draggable true + :on-context-menu (on-context-menu (:id component)) + :on-drag-start (partial on-drag-start component)} + [:& exports/component-svg {:group (get-in component [:objects (:id component)]) + :objects (:objects component)}] + [:& editable-label + {:class-name (dom/classnames + :cell-name true + :editing renaming?) + :value (:name component) + :editing? renaming? + :disable-dbl-click? true + :on-change do-rename + :on-cancel cancel-rename}]]))]) (when local? [:& context-menu @@ -105,7 +135,8 @@ :on-close #(swap! state assoc :menu-open false) :top (:top @state) :left (:left @state) - :options [[(tr "workspace.assets.duplicate") on-duplicate] + :options [[(tr "workspace.assets.rename") on-rename] + [(tr "workspace.assets.duplicate") on-duplicate] [(tr "workspace.assets.delete") on-delete]]}])])) (mf/defc graphics-box