diff --git a/CHANGES.md b/CHANGES.md index 06a817c131..6304ec2b43 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -38,6 +38,7 @@ - Add guide locking and fix locked elements not selectable in viewer (by @Dexterity104) [Github #8358](https://github.com/penpot/penpot/issues/8358) - Apply styles to selection (by @AzazelN28) [Taiga #13647](https://tree.taiga.io/project/penpot/task/13647) - Reorder prototyping overlay options to show Position before Relative to (by @rockchris099) [Github #2910](https://github.com/penpot/penpot/issues/2910) +- Add customizable colors for ruler guides (by @Dexterity104) [Github #5199](https://github.com/penpot/penpot/issues/5199) - Persist asset search query and section filter when switching sidebar tabs (by @eureka0928) [Github #2913](https://github.com/penpot/penpot/issues/2913) - Add delete and duplicate buttons to typography dialog (by @eureka0928) [Github #5270](https://github.com/penpot/penpot/issues/5270) - Edit ruler guide position by double-clicking the guide pill (by @eureka0928) [Github #2311](https://github.com/penpot/penpot/issues/2311) diff --git a/common/src/app/common/types/page.cljc b/common/src/app/common/types/page.cljc index 0d4041aaa0..0f3e05f97a 100644 --- a/common/src/app/common/types/page.cljc +++ b/common/src/app/common/types/page.cljc @@ -34,7 +34,8 @@ [:id ::sm/uuid] [:axis [::sm/one-of #{:x :y}]] [:position ::sm/safe-number] - [:frame-id {:optional true} [:maybe ::sm/uuid]]]) + [:frame-id {:optional true} [:maybe ::sm/uuid]] + [:color {:optional true} [:maybe ctc/schema:hex-color]]]) (def schema:guides [:map-of {:gen/max 2} ::sm/uuid schema:guide]) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 75939e4858..eb1f1744b9 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1195,6 +1195,16 @@ (-> params (assoc :kind :grid-cells :grid grid :cells cells)))))))) +(defn show-guide-context-menu + [{:keys [position guide] :as params}] + (dm/assert! (gpt/point? position)) + (ptk/reify ::show-guide-context-menu + ptk/WatchEvent + (watch [_ _ _] + (rx/of (show-context-menu + (-> params (assoc :kind :guide + :guide guide))))))) + (def hide-context-menu (ptk/reify ::hide-context-menu ptk/UpdateEvent diff --git a/frontend/src/app/main/data/workspace/guides.cljs b/frontend/src/app/main/data/workspace/guides.cljs index 16762ad3ed..3946e3efbe 100644 --- a/frontend/src/app/main/data/workspace/guides.cljs +++ b/frontend/src/app/main/data/workspace/guides.cljs @@ -152,6 +152,23 @@ (map build-move-event) (rx/from)))))) +(defn update-guide-color + [guide-id color] + (ptk/reify ::update-guide-color + ptk/WatchEvent + (watch [it state _] + (let [{:keys [guides] :as page} (dsh/lookup-page state) + guide (get guides guide-id)] + (when (some? guide) + (let [updated-guide (if (some? color) + (assoc guide :color color) + (dissoc guide :color)) + changes + (-> (pcb/empty-changes it) + (pcb/with-page page) + (pcb/set-guide guide-id updated-guide))] + (rx/of (dwc/commit-changes changes)))))))) + (defn set-hover-guide [id hover?] (ptk/reify ::set-hover-guide diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index 23552907fe..7b645384bb 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -899,6 +899,50 @@ :disabled (not has-copied-tracks?)}]])) +(def guide-color-presets + ["#ff3277" "#4dabf7" "#51cf66" "#fcc419" "#ff922b" "#cc5de8" "#ffffff" "#868e96"]) + +(mf/defc guide-color-context-menu* + {::mf/props :obj + ::mf/private true} + [{:keys [mdata]}] + (let [{:keys [guide]} mdata + guide-id (:id guide) + current-color (or (:color guide) (first guide-color-presets)) + + do-set-color + (mf/use-fn + (mf/deps guide-id) + (fn [event] + (let [color (dom/get-data (dom/get-current-target event) "color")] + (st/emit! dw/hide-context-menu + (dwg/update-guide-color guide-id color))))) + + do-remove-guide + (mf/use-fn + (mf/deps guide) + (fn [] + (st/emit! dw/hide-context-menu + (dwg/remove-guide guide))))] + + [:* + [:li {:class (stl/css :context-menu-item :guide-color-label)} + [:span {:class (stl/css :title)} + (tr "workspace.context-menu.guides.change-color")]] + [:li {:class (stl/css :guide-color-swatches)} + (for [color guide-color-presets] + [:span {:key color + :class (stl/css-case + :guide-color-swatch true + :selected (= color current-color)) + :data-color color + :on-click do-set-color + :title color + :style {:background-color color}}])] + [:> menu-separator* {}] + [:> menu-entry* {:title (tr "workspace.context-menu.guides.remove") + :on-click do-remove-guide}]])) + ;; FIXME: optimize because it is rendered always (mf/defc context-menu* @@ -936,4 +980,5 @@ :page [:> page-item-context-menu* {:mdata mdata}] :grid-track [:> grid-track-context-menu* {:mdata mdata}] :grid-cells [:> grid-cells-context-menu* {:mdata mdata}] + :guide [:> guide-color-context-menu* {:mdata mdata}] [:> viewport-context-menu* {:mdata mdata}]))]]])) diff --git a/frontend/src/app/main/ui/workspace/context_menu.scss b/frontend/src/app/main/ui/workspace/context_menu.scss index 53d1d0baf2..a6d1c799a3 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.scss +++ b/frontend/src/app/main/ui/workspace/context_menu.scss @@ -138,3 +138,30 @@ pointer-events: none; opacity: 0.6; } + +.guide-color-label { + cursor: default; + pointer-events: none; +} + +.guide-color-swatches { + display: flex; + flex-wrap: wrap; + gap: deprecated.$s-6; + padding: deprecated.$s-4 deprecated.$s-6 deprecated.$s-8; + list-style: none; +} + +.guide-color-swatch { + width: deprecated.$s-20; + height: deprecated.$s-20; + border-radius: 50%; + cursor: pointer; + flex-shrink: 0; + box-sizing: border-box; + border: deprecated.$s-2 solid var(--panel-border-color); + + &.selected { + border: deprecated.$s-2 solid var(--menu-foreground-color); + } +} diff --git a/frontend/src/app/main/ui/workspace/viewport/guides.cljs b/frontend/src/app/main/ui/workspace/viewport/guides.cljs index bb6df6e965..c79cafe702 100644 --- a/frontend/src/app/main/ui/workspace/viewport/guides.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/guides.cljs @@ -31,7 +31,8 @@ (def ^:const guide-width 1) (def ^:const guide-opacity 0.7) (def ^:const guide-opacity-hover 1) -(def ^:const guide-color colors/new-danger) +(def ^:const default-guide-color colors/new-danger) + (def ^:const guide-pill-width 34) (def ^:const guide-pill-height 20) (def ^:const guide-pill-corner-radius 4) @@ -285,10 +286,14 @@ (mf/defc guide* {::mf/wrap [mf/memo]} [{:keys [guide is-hover on-guide-change get-hover-frame vbox zoom - hover-frame disabled-guides frame-modifier frame-transform]}] + hover-frame disabled-guides frame-modifier frame-transform + on-guide-context-menu]}] (let [axis (get guide :axis) + guide-color + (or (:color guide) default-guide-color) + read-only? (mf/use-ctx ctx/workspace-read-only?) @@ -303,7 +308,7 @@ handle-change-position (mf/use-fn - (mf/deps on-guide-change) + (mf/deps on-guide-change guide) (fn [changes] (when on-guide-change (on-guide-change (merge guide changes))))) @@ -399,7 +404,13 @@ (not (ctst/rotated-frame? frame)))) [:g.guide-area {:opacity (when frame-guide-outside? 0)} (when-not disabled-guides - (let [{:keys [x y width height]} (guide-area-axis pos vbox zoom frame axis)] + (let [{:keys [x y width height]} (guide-area-axis pos vbox zoom frame axis) + on-context-menu + (fn [event] + (dom/prevent-default event) + (dom/stop-propagation event) + (when on-guide-context-menu + (on-guide-context-menu event guide)))] [:rect {:x x :y y :width width @@ -413,6 +424,7 @@ :on-pointer-up on-pointer-up :on-lost-pointer-capture on-lost-pointer-capture :on-pointer-move on-pointer-move + :on-context-menu on-context-menu :on-double-click on-double-click}])) (if (some? frame) @@ -597,6 +609,13 @@ (st/emit! (dw/update-guides guide)) (st/emit! (dw/remove-guide guide))))) + on-guide-context-menu + (mf/use-fn + (fn [event guide] + (let [position (dom/get-client-position event)] + (st/emit! (dw/show-guide-context-menu {:position position + :guide guide}))))) + frame-modifiers (-> (group-by :id modifiers) (update-vals (comp :transform first)))] @@ -628,4 +647,5 @@ :frame-transform (get frame-modifiers frame-id) :get-hover-frame get-hover-frame :on-guide-change on-guide-change + :on-guide-context-menu on-guide-context-menu :disabled-guides disabled-guides}]))])) diff --git a/frontend/src/app/plugins/ruler_guides.cljs b/frontend/src/app/plugins/ruler_guides.cljs index 9cf7535660..8c90b74ca9 100644 --- a/frontend/src/app/plugins/ruler_guides.cljs +++ b/frontend/src/app/plugins/ruler_guides.cljs @@ -94,6 +94,22 @@ value)] (st/emit! (dwgu/update-guides (assoc guide :position position))))))} + :color + {:this true + :get + (fn [self] + (-> self u/proxy->ruler-guide :color)) + + :set + (fn [self value] + (cond + (not (r/check-permission plugin-id "content:write")) + (u/not-valid plugin-id :color "Plugin doesn't have 'content:write' permission") + + :else + (let [guide (u/proxy->ruler-guide self)] + (st/emit! (dwgu/update-guides (assoc guide :color value))))))} + :remove (fn [] (let [guide (u/locate-ruler-guide file-id page-id id)] diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 2b325e4e11..f86456267e 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -5730,6 +5730,12 @@ msgstr "Copy columns" msgid "workspace.context-menu.grid-cells.paste-tracks" msgstr "Paste" +msgid "workspace.context-menu.guides.change-color" +msgstr "Guide color" + +msgid "workspace.context-menu.guides.remove" +msgstr "Remove guide" + #: src/app/main/ui/workspace/context_menu.cljs:754 msgid "workspace.context-menu.grid-track.column.add-after" msgstr "Add 1 column to the right"