mirror of
https://github.com/penpot/penpot.git
synced 2025-01-25 07:58:49 -05:00
🎉 Allow to rename a component in the library
This commit is contained in:
parent
fd1f42dc94
commit
1823ecda40
5 changed files with 104 additions and 23 deletions
|
@ -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]}]
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}]
|
||||
|
|
|
@ -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])))
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue