diff --git a/CHANGES.md b/CHANGES.md index aea60b608c..910495858b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -29,6 +29,7 @@ - Add per-group add button for typographies (by @eureka928) [Github #5275](https://github.com/penpot/penpot/issues/5275) - Use page name for multi-export ZIP/PDF downloads (by @Dexterity104) [Github #8773](https://github.com/penpot/penpot/issues/8773) - Make links in comments clickable (by @eureka928) [Github #1602](https://github.com/penpot/penpot/issues/1602) +- Add visibility toggle for strokes (by @eureka928) [Github #7438](https://github.com/penpot/penpot/issues/7438) ### :bug: Bugs fixed diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index 20935a1723..5f6ac22ad3 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -145,7 +145,8 @@ [::sm/one-of stroke-caps]] [:stroke-color {:optional true} clr/schema:hex-color] [:stroke-color-gradient {:optional true} clr/schema:gradient] - [:stroke-image {:optional true} clr/schema:image]]) + [:stroke-image {:optional true} clr/schema:image] + [:hidden {:optional true} :boolean]]) (def stroke-attrs "A set of attrs that corresponds to stroke data type" diff --git a/frontend/src/app/main/ui/shapes/custom_stroke.cljs b/frontend/src/app/main/ui/shapes/custom_stroke.cljs index 02c3b5d07e..01d5c64c5b 100644 --- a/frontend/src/app/main/ui/shapes/custom_stroke.cljs +++ b/frontend/src/app/main/ui/shapes/custom_stroke.cljs @@ -509,7 +509,8 @@ (when (some? shape-strokes) [:> :g props - (for [[index value] (reverse (d/enumerate shape-strokes))] + (for [[index value] (reverse (d/enumerate shape-strokes)) + :when (not (:hidden value))] [:& shape-custom-stroke {:shape shape :stroke value :index index diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs index 96cf70f8f5..491aef1343 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs @@ -12,6 +12,7 @@ [app.common.types.stroke :as cts] [app.main.data.workspace :as udw] [app.main.data.workspace.colors :as dc] + [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.tokens.application :as dwta] [app.main.store :as st] [app.main.ui.components.title-bar :refer [title-bar*]] @@ -155,6 +156,13 @@ (st/emit! (udw/trigger-bounding-box-cloaking ids)) (st/emit! (dc/change-stroke-attrs ids {:stroke-cap-start stroke-cap-end :stroke-cap-end stroke-cap-start} index))))) + on-toggle-visibility + (mf/use-fn + (mf/deps ids) + (fn [index] + (st/emit! (udw/trigger-bounding-box-cloaking ids) + (dwsh/update-shapes ids #(update-in % [:strokes index :hidden] not))))) + on-add-stroke (fn [_] (st/emit! (udw/trigger-bounding-box-cloaking ids)) @@ -226,6 +234,7 @@ :applied-tokens (when (= 0 index) applied-tokens) :on-detach-token on-detach-token :on-remove on-remove + :on-toggle-visibility on-toggle-visibility :on-reorder handle-reorder :disable-drag disable-drag :on-focus on-focus diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs index 6eb0cc349d..d1c0a80497 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs @@ -40,6 +40,7 @@ on-stroke-cap-start-change on-stroke-cap-end-change on-stroke-cap-switch + on-toggle-visibility disable-drag on-focus on-blur @@ -49,7 +50,9 @@ select-on-focus ids]}] - (let [token-numeric-inputs + (let [hidden? (:hidden stroke) + + token-numeric-inputs (features/use-feature "tokens/numeric-input") on-drop @@ -182,10 +185,18 @@ on-cap-switch (mf/use-fn (mf/deps index on-stroke-cap-switch) - #(on-stroke-cap-switch index))] + #(on-stroke-cap-switch index)) + + on-toggle-visibility + (mf/use-fn + (mf/deps index on-toggle-visibility) + (fn [] + (when on-toggle-visibility + (on-toggle-visibility index))))] [:div {:class (stl/css-case :stroke-data true + :hidden hidden? :dnd-over-top (= (:over dprops) :top) :dnd-over-bot (= (:over dprops) :bot)) :aria-label (str "stroke-row-" index)} @@ -195,22 +206,33 @@ ;; Stroke Color ;; FIXME: memorize stroke color - [:> color-row* {:color (ctc/stroke->color stroke) - :index index - :title title - :on-change on-color-change-refactor - :on-detach on-color-detach - :on-remove on-remove - :disable-drag disable-drag - :applied-token (if (= index 0) - stroke-color-token - nil) - :on-detach-token on-detach-token-color - :on-token-change on-token-change - :on-focus on-focus - :origin :stroke-color - :select-on-focus select-on-focus - :on-blur on-blur}] + [:div {:class (stl/css :stroke-color-actions)} + [:> color-row* {:color (ctc/stroke->color stroke) + :index index + :title title + :on-change on-color-change-refactor + :on-detach on-color-detach + :disable-drag disable-drag + :applied-token (if (= index 0) + stroke-color-token + nil) + :on-detach-token on-detach-token-color + :on-token-change on-token-change + :on-focus on-focus + :origin :stroke-color + :select-on-focus select-on-focus + :on-blur on-blur}] + + (when (some? on-toggle-visibility) + [:> icon-button* {:variant "ghost" + :aria-label (tr "workspace.options.stroke.toggle-stroke") + :on-click on-toggle-visibility + :icon (if hidden? "hide" "shown")}]) + + [:> icon-button* {:variant "ghost" + :aria-label (tr "workspace.options.stroke.remove-stroke") + :on-click on-remove + :icon i/remove}]] ;; Stroke Width, Alignment & Style (if token-numeric-inputs @@ -230,6 +252,7 @@ :options stroke-alignment-options :variant "icon-only" :data-testid "stroke.alignment" + :disabled hidden? :wrapper-class (stl/css :stroke-align-icon-select) :on-change on-alignment-change}] @@ -239,6 +262,7 @@ :wrapper-class (stl/css :stroke-style-icon-select) :data-testid "stroke.style" :variant "icon-only" + :disabled hidden? :dropdown-alignment :right :on-change on-style-change}])] @@ -258,6 +282,7 @@ :data-testid "stroke.alignment"} [:& select {:default-value stroke-alignment :options stroke-alignment-options + :disabled hidden? :on-change on-alignment-change}]] (when-not disable-stroke-style @@ -265,6 +290,7 @@ :data-testid "stroke.style"} [:& select {:default-value stroke-style :options stroke-style-options + :disabled hidden? :on-change on-style-change}]])]) ;; Stroke Caps @@ -272,11 +298,14 @@ [:div {:class (stl/css :stroke-caps-options)} [:& select {:default-value (:stroke-cap-start stroke) :options stroke-caps-options + :disabled hidden? :on-change on-caps-start-change}] [:> icon-button* {:variant "secondary" :aria-label (tr "labels.switch") + :disabled hidden? :on-click on-cap-switch :icon i/switch}] [:& select {:default-value (:stroke-cap-end stroke) :options stroke-caps-options + :disabled hidden? :on-change on-caps-end-change}]])])) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss index a93107afa9..c764e60f3f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.scss @@ -27,6 +27,25 @@ &.dnd-over-bot { --reorder-bottom-display: block; } + + &.hidden { + .stroke-options, + .stroke-options-tokens, + .stroke-caps-options { + opacity: 0.5; + pointer-events: none; + } + } +} + +.stroke-color-actions { + display: flex; + align-items: center; + + > :first-child { + flex: 1; + min-width: 0; + } } .stroke-options { diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 3d8fe0d0df..f12cbbc332 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -558,45 +558,46 @@ [shape-id strokes thumbnail?] (h/call wasm/internal-module "_clear_shape_strokes") (keep (fn [stroke] - (let [opacity (or (:stroke-opacity stroke) 1.0) - color (:stroke-color stroke) - gradient (:stroke-color-gradient stroke) - image (:stroke-image stroke) - width (:stroke-width stroke) - align (:stroke-alignment stroke) - style (-> stroke :stroke-style sr/translate-stroke-style) - cap-start (-> stroke :stroke-cap-start sr/translate-stroke-cap) - cap-end (-> stroke :stroke-cap-end sr/translate-stroke-cap) - offset (mem/alloc types.fills.impl/FILL-U8-SIZE) - heap (mem/get-heap-u8) - dview (js/DataView. (.-buffer heap))] - (case align - :inner (h/call wasm/internal-module "_add_shape_inner_stroke" width style cap-start cap-end) - :outer (h/call wasm/internal-module "_add_shape_outer_stroke" width style cap-start cap-end) - (h/call wasm/internal-module "_add_shape_center_stroke" width style cap-start cap-end)) + (when-not (:hidden stroke) + (let [opacity (or (:stroke-opacity stroke) 1.0) + color (:stroke-color stroke) + gradient (:stroke-color-gradient stroke) + image (:stroke-image stroke) + width (:stroke-width stroke) + align (:stroke-alignment stroke) + style (-> stroke :stroke-style sr/translate-stroke-style) + cap-start (-> stroke :stroke-cap-start sr/translate-stroke-cap) + cap-end (-> stroke :stroke-cap-end sr/translate-stroke-cap) + offset (mem/alloc types.fills.impl/FILL-U8-SIZE) + heap (mem/get-heap-u8) + dview (js/DataView. (.-buffer heap))] + (case align + :inner (h/call wasm/internal-module "_add_shape_inner_stroke" width style cap-start cap-end) + :outer (h/call wasm/internal-module "_add_shape_outer_stroke" width style cap-start cap-end) + (h/call wasm/internal-module "_add_shape_center_stroke" width style cap-start cap-end)) - (cond - (some? gradient) - (do - (types.fills.impl/write-gradient-fill offset dview opacity gradient) - (h/call wasm/internal-module "_add_shape_stroke_fill")) + (cond + (some? gradient) + (do + (types.fills.impl/write-gradient-fill offset dview opacity gradient) + (h/call wasm/internal-module "_add_shape_stroke_fill")) - (some? image) - (let [image-id (get image :id) - buffer (uuid/get-u32 image-id) - cached-image? (h/call wasm/internal-module "_is_image_cached" - (aget buffer 0) (aget buffer 1) - (aget buffer 2) (aget buffer 3) - thumbnail?)] - (types.fills.impl/write-image-fill offset dview opacity image) - (h/call wasm/internal-module "_add_shape_stroke_fill") - (when (== cached-image? 0) - (fetch-image shape-id image-id thumbnail?))) + (some? image) + (let [image-id (get image :id) + buffer (uuid/get-u32 image-id) + cached-image? (h/call wasm/internal-module "_is_image_cached" + (aget buffer 0) (aget buffer 1) + (aget buffer 2) (aget buffer 3) + thumbnail?)] + (types.fills.impl/write-image-fill offset dview opacity image) + (h/call wasm/internal-module "_add_shape_stroke_fill") + (when (== cached-image? 0) + (fetch-image shape-id image-id thumbnail?))) - (some? color) - (do - (types.fills.impl/write-solid-fill offset dview opacity color) - (h/call wasm/internal-module "_add_shape_stroke_fill"))))) + (some? color) + (do + (types.fills.impl/write-solid-fill offset dview opacity color) + (h/call wasm/internal-module "_add_shape_stroke_fill")))))) strokes)) (defn set-shape-svg-attrs diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 5fc069d7fe..2a481b0d0d 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -7316,6 +7316,10 @@ msgstr "Outside" msgid "workspace.options.stroke.remove-stroke" msgstr "Remove stroke" +#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs +msgid "workspace.options.stroke.toggle-stroke" +msgstr "Toggle stroke" + #: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:137 msgid "workspace.options.stroke.solid" msgstr "Solid"