diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs index 3b7dfba2b..d4333d594 100644 --- a/frontend/src/app/main/data/comments.cljs +++ b/frontend/src/app/main/data/comments.cljs @@ -195,13 +195,16 @@ ptk/WatchEvent (watch [_ state _] (let [share-id (-> state :viewer-local :share-id)] - (->> (rp/cmd! :update-comment-thread {:id id :is-resolved is-resolved :share-id share-id}) - (rx/catch (fn [{:keys [type code] :as cause}] - (if (and (= type :restriction) - (= code :max-quote-reached)) - (rx/throw cause) - (rx/throw {:type :comment-error})))) - (rx/ignore)))))) + (rx/concat + (when is-resolved (rx/of + (ptk/event ::ev/event {::ev/name "resolve-comment-thread" :thread-id id}))) + (->> (rp/cmd! :update-comment-thread {:id id :is-resolved is-resolved :share-id share-id}) + (rx/catch (fn [{:keys [type code] :as cause}] + (if (and (= type :restriction) + (= code :max-quote-reached)) + (rx/throw cause) + (rx/throw {:type :comment-error})))) + (rx/ignore))))))) (defn add-comment [thread content] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index a64feda54..cf6092e03 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -2016,6 +2016,8 @@ (map :id) (pcb/resize-parents changes)) + orig-shapes (map (d/getf all-objects) selected) + selected (into (d/ordered-set) (comp (filter add-obj?) @@ -2028,13 +2030,22 @@ (some? drop-cell) (pcb/update-shapes [parent-id] #(ctl/add-children-to-cell % selected all-objects drop-cell))) + undo-id (js/Symbol)] - (rx/of (dwu/start-undo-transaction undo-id) - (dch/commit-changes changes) - (dws/select-shapes selected) - (ptk/data-event :layout/update {:ids [frame-id]}) - (dwu/commit-undo-transaction undo-id))))))) + (rx/concat + (->> (filter ctk/instance-head? orig-shapes) + (map (fn [{:keys [component-file]}] + (ptk/event ::ev/event + {::ev/name "use-library-component" + ::ev/origin "paste" + :external-library (not= file-id component-file)}))) + (rx/from)) + (rx/of (dwu/start-undo-transaction undo-id) + (dch/commit-changes changes) + (dws/select-shapes selected) + (ptk/data-event :layout/update {:ids [frame-id]}) + (dwu/commit-undo-transaction undo-id)))))))) (defn as-content [text] (let [paragraphs (->> (str/lines text) diff --git a/frontend/src/app/main/data/workspace/interactions.cljs b/frontend/src/app/main/data/workspace/interactions.cljs index b5ae5352d..5610f8a54 100644 --- a/frontend/src/app/main/data/workspace/interactions.cljs +++ b/frontend/src/app/main/data/workspace/interactions.cljs @@ -17,6 +17,7 @@ [app.common.types.shape.interactions :as ctsi] [app.common.uuid :as uuid] [app.main.data.changes :as dch] + [app.main.data.events :as ev] [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] @@ -168,6 +169,7 @@ objects (get page :objects) frame (cfh/get-root-frame objects (:id shape)) + first? (not-any? #(seq (:interactions %)) (vals objects)) flows (get page :flows) flow (ctp/get-frame-flow flows (:id frame))] (rx/concat @@ -184,7 +186,10 @@ (when (and (not (connected-frame? objects (:id frame))) (nil? flow)) - (rx/of (add-flow (:id frame)))))))))) + (rx/of (add-flow (:id frame)))) + (when first? + ;; When the first interaction of the page is created we emit the event "create-prototype" + (rx/of (ptk/event ::ev/event {::ev/name "create-prototype"}))))))))) (defn remove-interaction ([shape index] diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 982c56c9d..fa16fb9a8 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -586,7 +586,7 @@ in the given file library. Then selects the newly created instance." ([file-id component-id position] (instantiate-component file-id component-id position nil)) - ([file-id component-id position {:keys [start-move? initial-point id-ref]}] + ([file-id component-id position {:keys [start-move? initial-point id-ref origin]}] (dm/assert! (uuid? file-id)) (dm/assert! (uuid? component-id)) (dm/assert! (gpt/point? position)) @@ -600,6 +600,8 @@ changes (-> (pcb/empty-changes it (:id page)) (pcb/with-objects objects)) + current-file-id (:current-file-id state) + [new-shape changes] (cll/generate-instantiate-component changes objects @@ -608,12 +610,18 @@ position page libraries) + undo-id (js/Symbol)] (when id-ref (reset! id-ref (:id new-shape))) - (rx/of (dwu/start-undo-transaction undo-id) + (rx/of (ptk/event + ::ev/event + {::ev/name "use-library-component" + ::ev/origin origin + :external-library (not= file-id current-file-id)}) + (dwu/start-undo-transaction undo-id) (dch/commit-changes changes) (ptk/data-event :layout/update {:ids [(:id new-shape)]}) (dws/select-shapes (d/ordered-set (:id new-shape))) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 8150ea465..cc20ee803 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -456,22 +456,30 @@ id-duplicated (first new-ids) - frames (into #{} - (map #(get-in objects [% :frame-id])) - ids) - undo-id (js/Symbol)] - + frames (into #{} + (map #(get-in objects [% :frame-id])) + ids) + undo-id (js/Symbol)] + (rx/concat + (->> (map (d/getf objects) ids) + (filter ctk/instance-head?) + (map (fn [{:keys [component-file]}] + (ptk/event ::ev/event + {::ev/name "use-library-component" + ::ev/origin "duplicate" + :external-library (not= file-id component-file)}))) + (rx/from)) ;; Warning: This order is important for the focus mode. - (->> (rx/of - (dwu/start-undo-transaction undo-id) - (dch/commit-changes changes) - (when change-selection? - (select-shapes new-ids)) - (ptk/data-event :layout/update {:ids frames}) - (memorize-duplicated id-original id-duplicated) - (dwu/commit-undo-transaction undo-id)) - (rx/tap #(when (some? return-ref) - (reset! return-ref id-duplicated)))))))))) + (->> (rx/of + (dwu/start-undo-transaction undo-id) + (dch/commit-changes changes) + (when change-selection? + (select-shapes new-ids)) + (ptk/data-event :layout/update {:ids frames}) + (memorize-duplicated id-original id-duplicated) + (dwu/commit-undo-transaction undo-id)) + (rx/tap #(when (some? return-ref) + (reset! return-ref id-duplicated))))))))))) (defn duplicate-selected ([move-delta?] diff --git a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs index 839adf0bc..d3e5bd480 100644 --- a/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/inspect/right_sidebar.cljs @@ -9,7 +9,9 @@ (:require [app.common.data.macros :as dm] [app.common.types.component :as ctk] + [app.main.data.events :as ev] [app.main.refs :as refs] + [app.main.store :as st] [app.main.ui.components.shape-icon :as sir] [app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]] [app.main.ui.icons :as i] @@ -18,6 +20,7 @@ [app.main.ui.viewer.inspect.selection-feedback :refer [resolve-shapes]] [app.util.dom :as dom] [app.util.i18n :refer [tr]] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (defn- get-libraries @@ -63,7 +66,9 @@ (fn [new-section] (reset! section (keyword new-section)) (when on-change-section - (on-change-section (keyword new-section))))) + (on-change-section (keyword new-section)) + (st/emit! + (ptk/event ::ev/event {::ev/name "change-inspect-tab" :tab new-section}))))) handle-expand (mf/use-fn diff --git a/frontend/src/app/main/ui/workspace/color_palette.cljs b/frontend/src/app/main/ui/workspace/color_palette.cljs index 4ce8947e4..f1b0a2fb0 100644 --- a/frontend/src/app/main/ui/workspace/color_palette.cljs +++ b/frontend/src/app/main/ui/workspace/color_palette.cljs @@ -8,6 +8,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] + [app.main.data.events :as ev] [app.main.data.workspace.colors :as mdc] [app.main.data.workspace.libraries :as dwl] [app.main.refs :as refs] @@ -20,15 +21,22 @@ [app.util.i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.object :as obj] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc palette-item {::mf/wrap [mf/memo]} - [{:keys [color size]}] + [{:keys [color size selected]}] (letfn [(select-color [event] (st/emit! (dwl/add-recent-color color) - (mdc/apply-color-from-palette color (kbd/alt? event))))] + (mdc/apply-color-from-palette color (kbd/alt? event)) + (when (not= selected :recent) + (ptk/event + ::ev/event + {::ev/name "use-library-color" + ::ev/origin "color-palette" + :external-library (not= selected :file)}))))] [:div {:class (stl/css-case :color-cell true :is-not-library-color (nil? (:id color)) :no-text (<= size 64)) @@ -39,7 +47,7 @@ (mf/defc palette - [{:keys [current-colors size width]}] + [{:keys [current-colors size width selected]}] (let [;; We had to do this due to a bug that leave some bugged colors current-colors (h/use-equal-memo (filter #(or (:gradient %) (:color %) (:image %)) current-colors)) state (mf/use-state {:show-menu false}) @@ -132,7 +140,7 @@ :max-width (str width "px") :right (str (* offset-step offset) "px")}} (for [[idx item] (map-indexed vector current-colors)] - [:& palette-item {:color item :key idx :size size}])])] + [:& palette-item {:color item :key idx :size size :selected selected}])])] (when show-arrows? [:button {:class (stl/css :right-arrow) :disabled (= offset max-offset) @@ -170,4 +178,5 @@ [:& palette {:current-colors @colors :size size - :width width}])) + :width width + :selected selected}])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index 1c3ef0ed8..c38dbb19b 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -22,6 +22,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc libraries @@ -76,8 +77,14 @@ on-color-click (mf/use-fn - (mf/deps state) + (mf/deps state @selected) (fn [event] + (when-not (= :recent @selected) + (st/emit! (ptk/event + ::ev/event + {::ev/name "use-library-color" + ::ev/origin "colorpicker" + :external-library (not= :file @selected)}))) (on-select-color state event)))] ;; Load library colors when the select is changed diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 2cdc3eebb..dd33626c0 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -38,6 +38,7 @@ [app.util.i18n :refer [tr] :as i18n] [app.util.timers :as timers] [okulary.core :as l] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (def menu-ref @@ -532,7 +533,9 @@ :title (tr "modals.delete-page.title") :message (tr "modals.delete-page.body") :on-accept delete-fn})) - do-duplicate #(st/emit! (dw/duplicate-page id)) + do-duplicate #(st/emit! + (dw/duplicate-page id) + (ptk/event ::ev/event {::ev/name "duplicate-page"})) do-rename #(st/emit! (dw/start-rename-page-item id))] [:* diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs index 7f91cf495..3391e47d5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs @@ -70,7 +70,12 @@ (fn [event] (st/emit! (dwl/add-recent-color color) - (dc/apply-color-from-palette color (kbd/alt? event))))) + (dc/apply-color-from-palette color (kbd/alt? event)) + (ptk/event + ::ev/event + {::ev/name "use-library-color" + ::ev/origin "sidebar" + :external-library (not local?)})))) rename-color (mf/use-fn diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs index 052a7bbe5..88a548384 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/file_library.cljs @@ -9,6 +9,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.main.data.events :as ev] [app.main.data.workspace :as dw] [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.undo :as dwu] @@ -29,6 +30,7 @@ [app.util.router :as rt] [cuerdas.core :as str] [okulary.core :as l] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (def lens:open-status @@ -50,7 +52,15 @@ (mf/use-fn (mf/deps file-id open?) (fn [] - (st/emit! (dw/set-assets-section-open file-id :library (not open?)))))] + (st/emit! (dw/set-assets-section-open file-id :library (not open?))))) + + on-click + (mf/use-fn + (fn [ev] + (dom/stop-propagation ev) + (st/emit! + (ptk/event ::ev/event {::ev/name "navigate-to-library-file"}))))] + [:div {:class (stl/css-case :library-title true :open open?)} [:& title-bar {:collapsable true @@ -65,11 +75,11 @@ (mf/html [:div {:class (stl/css :special-title)} file-name]))} (when-not local? - [:span {:title "Open library file"} + [:span {:title (tr "workspace.assets.open-library")} [:a {:class (stl/css :file-link) :href (str "#" url) :target "_blank" - :on-click dom/stop-propagation} + :on-click on-click} i/open-link]])]])) (mf/defc file-library-content diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs index fe5d46a99..728c95814 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/typographies.cljs @@ -10,6 +10,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] + [app.main.data.events :as ev] [app.main.data.modal :as modal] [app.main.data.workspace :as dw] [app.main.data.workspace.libraries :as dwl] @@ -26,6 +27,7 @@ [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] [okulary.core :as l] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (def lens:typography-section-state @@ -97,7 +99,18 @@ on-asset-click (mf/use-fn (mf/deps typography apply-typography on-asset-click) - (partial on-asset-click typography-id apply-typography))] + (partial on-asset-click typography-id apply-typography)) + + on-click + (mf/use-fn + (mf/deps typography apply-typography on-asset-click) + (fn [ev] + (st/emit! (ptk/event + ::ev/event + {::ev/name "use-library-typography" + ::ev/origin "sidebar" + :external-library (not local?)})) + (on-asset-click ev)))] [:div {:class (stl/css :typography-item) :ref item-ref @@ -113,7 +126,7 @@ :typography typography :local? local? :selected? (contains? selected typography-id) - :on-click on-asset-click + :on-click on-click :on-change handle-change :on-context-menu on-context-menu :editing? editing? diff --git a/frontend/src/app/main/ui/workspace/text_palette.cljs b/frontend/src/app/main/ui/workspace/text_palette.cljs index d2418c031..f508747f5 100644 --- a/frontend/src/app/main/ui/workspace/text_palette.cljs +++ b/frontend/src/app/main/ui/workspace/text_palette.cljs @@ -8,6 +8,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] + [app.main.data.events :as ev] [app.main.data.workspace.texts :as dwt] [app.main.fonts :as f] [app.main.refs :as refs] @@ -18,23 +19,30 @@ [app.util.i18n :refer [tr]] [app.util.object :as obj] [cuerdas.core :as str] + [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc typography-item - [{:keys [file-id selected-ids typography name-only? size]}] + [{:keys [file-id selected-ids typography name-only? size current-file-id]}] (let [font-data (f/get-font-data (:font-id typography)) font-variant-id (:font-variant-id typography) variant-data (->> font-data :variants (d/seek #(= (:id %) font-variant-id))) + handle-click (mf/use-callback - (mf/deps typography selected-ids) + (mf/deps typography selected-ids file-id current-file-id) (fn [] (let [attrs (merge {:typography-ref-file file-id :typography-ref-id (:id typography)} (dissoc typography :id :name))] + (st/emit! (ptk/event + ::ev/event + {::ev/name "use-library-typography" + ::ev/origin "text-palette" + :external-library (not= file-id current-file-id)})) (run! #(st/emit! (dwt/update-text-attrs {:id % @@ -160,6 +168,7 @@ [:& typography-item {:key idx :file-id file-id + :current-file-id current-file-id :selected-ids selected-ids :typography item :size size}])])] diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index edc556025..c0cf1d7c3 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -422,7 +422,7 @@ file-id (:id component) (gpt/point final-x final-y) - {:start-move? true :initial-point viewport-coord}))))) + {:start-move? true :initial-point viewport-coord :origin "sidebar"}))))) (when (or (dnd/has-type? e "penpot/shape") (dnd/has-type? e "penpot/component") (dnd/has-type? e "Files") diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index b1c38e76d..29b8b15b0 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -676,7 +676,7 @@ :else (let [id-ref (atom nil)] - (st/emit! (dwl/instantiate-component file-id id (gpt/point 0 0) {:id-ref id-ref})) + (st/emit! (dwl/instantiate-component file-id id (gpt/point 0 0) {:id-ref id-ref :origin "plugin"})) (shape/shape-proxy plugin-id @id-ref)))) :getPluginData diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 62f00de6b..e001ffb0e 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -4070,7 +4070,7 @@ msgstr "local library" msgid "workspace.assets.not-found" msgstr "No assets found" -#, unused +#: src/app/main/ui/workspace/sidebar/assets/file_library.cljs:68 msgid "workspace.assets.open-library" msgstr "Open library file"