diff --git a/CHANGES.md b/CHANGES.md index 7a50b12b26..aa6c682958 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -64,6 +64,7 @@ ### :bug: Bugs fixed - Fix font rendering on grid thumbnails [Taiga #3473](https://tree.taiga.io/project/penpot/issue/3473) +- Fix inconsistent representation of rectangles [Taiga #3977](https://tree.taiga.io/project/penpot/issue/3977) - Fix recent fonts info [Taiga #3953](https://tree.taiga.io/project/penpot/issue/3953) - Fix clipped elements affect boards and centering [Taiga #3666](https://tree.taiga.io/project/penpot/issue/3666) - Fix intro action in multi input [Taiga #3541](https://tree.taiga.io/project/penpot/issue/3541) @@ -78,6 +79,7 @@ - Fix unexpected removal of guides on copy&paste frames [Taiga #3887](https://tree.taiga.io/project/penpot/issue/3887) by @andrewzhurov - Fix props preserving on copy&paste texts [Taiga #3629](https://tree.taiga.io/project/penpot/issue/3629) by @andrewzhurov - Fix unexpected layers ungrouping on moving it [Taiga #3932](https://tree.taiga.io/project/penpot/issue/3932) by @andrewzhurov +- Fix unexpected exception and behavior on colorpicker with gradients [Taiga #3448](https://tree.taiga.io/project/penpot/issue/3448) ### :arrow_up: Deps updates ### :heart: Community contributions by (Thank you!) diff --git a/common/src/app/common/path/shapes_to_path.cljc b/common/src/app/common/path/shapes_to_path.cljc index d4adbccdb8..6c3916ba5e 100644 --- a/common/src/app/common/path/shapes_to_path.cljc +++ b/common/src/app/common/path/shapes_to_path.cljc @@ -224,7 +224,11 @@ #_:else (rect->path shape)) ;; Apply the transforms that had the shape - transform (:transform shape) + transform + (cond-> (:transform shape (gmt/matrix)) + (:flip-x shape) (gmt/scale (gpt/point -1 1)) + (:flip-y shape) (gmt/scale (gpt/point 1 -1))) + new-content (cond-> new-content (some? transform) (gsp/transform-content (gmt/transform-in (gsc/center-shape shape) transform)))] diff --git a/common/src/app/common/types/shape/radius.cljc b/common/src/app/common/types/shape/radius.cljc index c93189e948..a93a8a927e 100644 --- a/common/src/app/common/types/shape/radius.cljc +++ b/common/src/app/common/types/shape/radius.cljc @@ -87,11 +87,17 @@ (defn set-radius-4 [shape attr value] - (cond-> shape - (:rx shape) - (-> (dissoc :rx :rx) - (assoc :r1 0 :r2 0 :r3 0 :r4 0)) + (let [attr (cond->> attr + (:flip-x shape) + (get {:r1 :r2 :r2 :r1 :r3 :r4 :r4 :r3}) - :always - (assoc attr value))) + (:flip-y shape) + (get {:r1 :r4 :r2 :r3 :r3 :r2 :r4 :r1}))] + (cond-> shape + (:rx shape) + (-> (dissoc :rx :rx) + (assoc :r1 0 :r2 0 :r3 0 :r4 0)) + + :always + (assoc attr value)))) diff --git a/frontend/resources/styles/main/partials/color-palette.scss b/frontend/resources/styles/main/partials/color-palette.scss index 78eeed0139..3ef34c52af 100644 --- a/frontend/resources/styles/main/partials/color-palette.scss +++ b/frontend/resources/styles/main/partials/color-palette.scss @@ -82,6 +82,7 @@ .color-palette-actions-button { cursor: pointer; + display: flex; & svg { width: 1rem; height: 1rem; diff --git a/frontend/src/app/main/broadcast.cljs b/frontend/src/app/main/broadcast.cljs new file mode 100644 index 0000000000..ef50e4b31b --- /dev/null +++ b/frontend/src/app/main/broadcast.cljs @@ -0,0 +1,52 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) UXBOX Labs SL + +(ns app.main.broadcast + "BroadcastChannel API." + (:require + [app.common.transit :as t] + [beicon.core :as rx] + [potok.core :as ptk])) + +(defrecord BroadcastMessage [id type data] + cljs.core/IDeref + (-deref [_] data)) + +(def ^:const default-topic "penpot") + +;; The main broadcast channel instance, used for emit data +(defonce default-channel + (js/BroadcastChannel. default-topic)) + +(defonce stream + (->> (rx/create (fn [subs] + (let [chan (js/BroadcastChannel. default-topic)] + (unchecked-set chan "onmessage" #(rx/push! subs (unchecked-get % "data"))) + (fn [] (.close ^js chan))))) + (rx/map t/decode-str) + (rx/map map->BroadcastMessage) + (rx/share))) + +(defn emit! + ([type data] + (.postMessage ^js default-channel (t/encode-str {:id nil :type type :data data})) + nil) + ([id type data] + (.postMessage ^js default-channel (t/encode-str {:id id :type type :data data})) + nil)) + +(defn type? + ([type] + (fn [obj] (= (:type obj) type))) + ([obj type] + (= (:type obj) type))) + +(defn event + [type data] + (ptk/reify ::event + ptk/EffectEvent + (effect [_ _ _] + (emit! type data)))) diff --git a/frontend/src/app/main/data/workspace/colors.cljs b/frontend/src/app/main/data/workspace/colors.cljs index 904412bd23..61f91a062e 100644 --- a/frontend/src/app/main/data/workspace/colors.cljs +++ b/frontend/src/app/main/data/workspace/colors.cljs @@ -6,55 +6,32 @@ (ns app.main.data.workspace.colors (:require - [app.common.colors :as clr] + [app.common.colors :as colors] [app.common.data :as d] [app.common.pages.helpers :as cph] + [app.main.broadcast :as mbc] [app.main.data.modal :as md] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.layout :as layout] + [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.texts :as dwt] [app.util.color :as uc] [beicon.core :as rx] [potok.core :as ptk])) -(defn change-palette-selected - "Change the library used by the general palette tool" - [selected] - (ptk/reify ::change-palette-selected - ptk/UpdateEvent - (update [_ state] - (assoc-in state [:workspace-global :selected-palette] selected)) - - ptk/EffectEvent - (effect [_ state _] - (let [wglobal (:workspace-global state)] - (layout/persist-layout-state! wglobal))))) - -(defn change-palette-selected-colorpicker - "Change the library used by the color picker" - [selected] - (ptk/reify ::change-palette-selected-colorpicker - ptk/UpdateEvent - (update [_ state] - (assoc-in state [:workspace-global :selected-palette-colorpicker] selected)) - - ptk/EffectEvent - (effect [_ state _] - (let [wglobal (:workspace-global state)] - (layout/persist-layout-state! wglobal))))) +;; A set of keys that are used for shared state identifiers +(def ^:const colorpicker-selected-broadcast-key ::colorpicker-selected) +(def ^:const colorpalette-selected-broadcast-key ::colorpalette-selected) (defn show-palette "Show the palette tool and change the library it uses" [selected] (ptk/reify ::show-palette - ptk/UpdateEvent - (update [_ state] - (assoc-in state [:workspace-global :selected-palette] selected)) - ptk/WatchEvent (watch [_ _ _] - (rx/of (layout/toggle-layout-flag :colorpalette :force? true))) + (rx/of (layout/toggle-layout-flag :colorpalette :force? true) + (mbc/event colorpalette-selected-broadcast-key selected))) ptk/EffectEvent (effect [_ state _] @@ -158,10 +135,10 @@ ptk/WatchEvent (watch [_ state _] (let [change-fn (fn [shape attrs] - (-> shape - (cond-> (not (contains? shape :fills)) - (assoc :fills [])) - (assoc-in [:fills position] (into {} attrs))))] + (-> shape + (cond-> (not (contains? shape :fills)) + (assoc :fills [])) + (assoc-in [:fills position] (into {} attrs))))] (transform-fill state ids color change-fn))))) (defn change-fill-and-clear @@ -342,45 +319,11 @@ (-> state (assoc-in [:workspace-global :picking-color?] true) (assoc ::md/modal {:id (random-uuid) - :data {:color clr/black :opacity 1} + :data {:color colors/black :opacity 1} :type :colorpicker :props {:on-change handle-change-color} :allow-click-outside true}))))))) -(defn start-gradient - [gradient] - (ptk/reify ::start-gradient - ptk/UpdateEvent - (update [_ state] - (let [id (-> state wsh/lookup-selected first)] - (-> state - (assoc-in [:workspace-global :current-gradient] gradient) - (assoc-in [:workspace-global :current-gradient :shape-id] id)))))) - -(defn stop-gradient - [] - (ptk/reify ::stop-gradient - ptk/UpdateEvent - (update [_ state] - (-> state - (update :workspace-global dissoc :current-gradient))))) - -(defn update-gradient - [changes] - (ptk/reify ::update-gradient - ptk/UpdateEvent - (update [_ state] - (-> state - (update-in [:workspace-global :current-gradient] merge changes))))) - -(defn select-gradient-stop - [spot] - (ptk/reify ::select-gradient-stop - ptk/UpdateEvent - (update [_ state] - (-> state - (assoc-in [:workspace-global :editing-stop] spot))))) - (defn color-att->text [color] {:fill-color (:color color) @@ -409,7 +352,9 @@ :fill (change-fill [(:shape-id shape)] new-color (:index shape)) :stroke (change-stroke [(:shape-id shape)] new-color (:index shape)) :shadow (change-shadow [(:shape-id shape)] new-color (:index shape)) - :content (dwt/update-text-with-function (:shape-id shape) (partial change-text-color old-color new-color (:index shape)))))))))) + :content (dwt/update-text-with-function + (:shape-id shape) + (partial change-text-color old-color new-color (:index shape)))))))))) (defn apply-color-from-palette [color is-alt?] @@ -431,3 +376,177 @@ (if is-alt? (rx/of (change-stroke ids (merge uc/empty-color color) 0)) (rx/of (change-fill ids (merge uc/empty-color color) 0))))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; COLORPICKER STATE MANAGEMENT +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn split-color-components + [{:keys [color opacity] :as data}] + (let [value (if (uc/hex? color) color colors/black) + [r g b] (uc/hex->rgb value) + [h s v] (uc/hex->hsv value)] + (merge data + {:hex (or value "000000") + :alpha (or opacity 1) + :r r :g g :b b + :h h :s s :v v}))) + +(defn materialize-color-components + [{:keys [hex alpha] :as data}] + (-> data + (assoc :color hex) + (assoc :opacity alpha))) + +(defn clear-color-components + [data] + (dissoc data :hex :alpha :r :g :b :h :s :v)) + +(defn- create-gradient + [type] + {:start-x 0.5 + :start-y (if (= type :linear-gradient) 0.0 0.5) + :end-x 0.5 + :end-y 1 + :width 1.0}) + +(defn get-color-from-colorpicker-state + [{:keys [type current-color stops gradient] :as state}] + (if (= type :color) + (clear-color-components current-color) + {:gradient (-> gradient + (assoc :type (case type + :linear-gradient :linear + :radial-gradient :radial)) + (assoc :stops (mapv clear-color-components stops)) + (dissoc :shape-id))})) + +(defn- colorpicker-onchange-runner + "Effect event that runs the on-change callback with the latest + colorpicker state converted to color object." + [on-change] + (ptk/reify ::colorpicker-onchange-runner + ptk/WatchEvent + (watch [_ state _] + (when-let [color (some-> state :colorpicker get-color-from-colorpicker-state)] + (on-change color) + (rx/of (dwl/add-recent-color color)))))) + +(defn initialize-colorpicker + [on-change] + (ptk/reify ::initialize-colorpicker + ptk/WatchEvent + (watch [_ _ stream] + (let [stoper (rx/merge + (rx/filter (ptk/type? ::finalize-colorpicker) stream) + (rx/filter (ptk/type? ::initialize-colorpicker) stream))] + + (->> (rx/merge + (->> stream + (rx/filter (ptk/type? ::update-colorpicker-gradient)) + (rx/debounce 200)) + (rx/filter (ptk/type? ::update-colorpicker-color) stream) + (rx/filter (ptk/type? ::activate-colorpicker-gradient) stream)) + (rx/map (constantly (colorpicker-onchange-runner on-change))) + (rx/take-until stoper)))))) + +(defn finalize-colorpicker + [] + (ptk/reify ::finalize-colorpicker + ptk/UpdateEvent + (update [_ state] + (dissoc state :colorpicker)))) + +(defn update-colorpicker + [{:keys [gradient] :as data}] + (ptk/reify ::update-colorpicker + ptk/UpdateEvent + (update [_ state] + (let [shape-id (-> state wsh/lookup-selected first)] + (update state :colorpicker + (fn [state] + (if (some? gradient) + (let [stop (or (:editing-stop state) 0) + stops (mapv split-color-components (:stops gradient)) + type (case (:type gradient) + :linear :linear-gradient + :radial :radial-gradient)] + (-> state + (assoc :type type) + (assoc :current-color (nth stops stop)) + (assoc :stops stops) + (assoc :gradient (-> gradient + (dissoc :stops) + (assoc :shape-id shape-id))) + (assoc :editing-stop stop))) + + (-> state + (assoc :type :color) + (assoc :current-color (split-color-components (dissoc data :gradient))) + (dissoc :editing-stop) + (dissoc :gradient) + (dissoc :stops))))))))) + +(defn update-colorpicker-color + [changes] + (ptk/reify ::update-colorpicker-color + ptk/UpdateEvent + (update [_ state] + (update state :colorpicker + (fn [state] + (let [state (-> state + (update :current-color merge changes) + (update :current-color materialize-color-components))] + (if-let [stop (:editing-stop state)] + (update-in state [:stops stop] (fn [data] (->> changes + (merge data) + (materialize-color-components)))) + (-> state + (assoc :type :color) + (dissoc :gradient :stops :editing-stop))))))))) + +(defn update-colorpicker-gradient + [changes] + (ptk/reify ::update-colorpicker-gradient + ptk/UpdateEvent + (update [_ state] + (update-in state [:colorpicker :gradient] merge changes)))) + +(defn select-colorpicker-gradient-stop + [stop] + (ptk/reify ::select-colorpicket-gradient-stop + ptk/UpdateEvent + (update [_ state] + (update state :colorpicker + (fn [state] + (if-let [color (get-in state [:stops stop])] + (assoc state + :current-color color + :editing-stop stop) + state)))))) + +(defn activate-colorpicker-gradient + [type] + (ptk/reify ::activate-colorpicker-gradient + ptk/UpdateEvent + (update [_ state] + (update state :colorpicker + (fn [state] + (if (= type (:type state)) + (do + (-> state + (assoc :type :color) + (dissoc :editing-stop :stops :gradient))) + (let [gradient (create-gradient type) + color (:current-color state)] + (-> state + (assoc :type type) + (assoc :gradient gradient) + (cond-> (not (:stops state)) + (assoc :editing-stop 0 + :stops [(assoc color :offset 0) + (-> color + (assoc :alpha 0) + (assoc :offset 1) + (materialize-color-components))])))))))))) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 769ee703f0..a3f0b67650 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -117,7 +117,7 @@ (defn add-recent-color [color] - (us/assert ::ctc/recent-color color) + (us/assert! ::ctc/recent-color color) (ptk/reify ::add-recent-color ptk/WatchEvent (watch [it _ _] diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 24b9346e5a..73d05521af 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -426,3 +426,6 @@ (->> ids (some #(-> (cph/get-parent objects %) :layout)))) workspace-page-objects)) + +(def colorpicker + (l/derived :colorpicker st/state)) diff --git a/frontend/src/app/main/ui/components/color_bullet.cljs b/frontend/src/app/main/ui/components/color_bullet.cljs index aa177e0947..5fd3acd0fc 100644 --- a/frontend/src/app/main/ui/components/color_bullet.cljs +++ b/frontend/src/app/main/ui/components/color_bullet.cljs @@ -17,23 +17,31 @@ :radial (tr "workspace.gradients.radial") nil)) -(mf/defc color-bullet [{:keys [color on-click]}] - (if (uc/multiple? color) - [:div.color-bullet.multiple {:on-click #(when on-click (on-click %))}] +(mf/defc color-bullet + {::mf/wrap [mf/memo]} + [{:keys [color on-click]}] + (let [on-click (mf/use-fn + (mf/deps color on-click) + (fn [event] + (when (fn? on-click) + (^function on-click color event))))] - ;; No multiple selection - (let [color (if (string? color) {:color color :opacity 1} color)] - [:div.color-bullet.tooltip.tooltip-right - {:class (dom/classnames :is-library-color (some? (:id color)) - :is-not-library-color (nil? (:id color)) - :is-gradient (some? (:gradient color))) - :on-click #(when on-click (on-click %)) - :alt (or (:name color) (:color color) (gradient-type->string (:type (:gradient color))))} - (if (:gradient color) - [:div.color-bullet-wrapper {:style {:background (uc/color->background color)}}] - [:div.color-bullet-wrapper - [:div.color-bullet-left {:style {:background (uc/color->background (assoc color :opacity 1))}}] - [:div.color-bullet-right {:style {:background (uc/color->background color)}}]])]))) + (if (uc/multiple? color) + [:div.color-bullet.multiple {:on-click on-click}] + + ;; No multiple selection + (let [color (if (string? color) {:color color :opacity 1} color)] + [:div.color-bullet.tooltip.tooltip-right + {:class (dom/classnames :is-library-color (some? (:id color)) + :is-not-library-color (nil? (:id color)) + :is-gradient (some? (:gradient color))) + :on-click on-click + :alt (or (:name color) (:color color) (gradient-type->string (:type (:gradient color))))} + (if (:gradient color) + [:div.color-bullet-wrapper {:style {:background (uc/color->background color)}}] + [:div.color-bullet-wrapper + [:div.color-bullet-left {:style {:background (uc/color->background (assoc color :opacity 1))}}] + [:div.color-bullet-right {:style {:background (uc/color->background color)}}]])])))) (mf/defc color-name [{:keys [color size on-click on-double-click]}] (let [color (if (string? color) {:color color :opacity 1} color) diff --git a/frontend/src/app/main/ui/hooks.cljs b/frontend/src/app/main/ui/hooks.cljs index d9c2b72bae..6fc2c6850b 100644 --- a/frontend/src/app/main/ui/hooks.cljs +++ b/frontend/src/app/main/ui/hooks.cljs @@ -7,16 +7,26 @@ (ns app.main.ui.hooks "A collection of general purpose react hooks." (:require + [app.common.data.macros :as dm] [app.common.pages :as cp] + [app.common.uuid :as uuid] + [app.main.broadcast :as mbc] [app.main.data.shortcuts :as dsc] [app.main.refs :as refs] [app.main.store :as st] [app.util.dom :as dom] [app.util.dom.dnd :as dnd] + [app.util.storage :refer [storage]] [app.util.timers :as ts] [beicon.core :as rx] + [goog.functions :as f] [rumext.alpha :as mf])) +(defn use-id + "Get a stable id value across rerenders." + [] + (mf/use-memo #(dm/str (uuid/next)))) + (defn use-rxsub [ob] (let [[state reset-state!] (mf/useState @ob)] @@ -191,7 +201,6 @@ [(deref state) ref])) - (defn use-stream "Wraps the subscription to a stream into a `use-effect` call" ([stream on-subscribe] @@ -205,6 +214,7 @@ ;; https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state (defn use-previous + "Returns the value from previuous render cycle." [value] (let [ref (mf/use-ref value)] (mf/use-effect @@ -214,13 +224,27 @@ (mf/ref-val ref))) (defn use-update-var + "Returns a var pointer what automatically updates with latest values." [value] - (let [ref (mf/use-var value)] - (mf/use-effect - (mf/deps value) - (fn [] - (reset! ref value))) - ref)) + (let [ptr (mf/use-var value)] + (mf/with-effect [value] + (reset! ptr value)) + ptr)) + +(defn use-ref-callback + "Returns a stable callback pointer what calls the interned + callback. The interned callback will be automatically updated on + each reander if the reference changes and works as noop if the + pointer references to nil value." + [f] + (let [ptr (mf/use-ref nil)] + (mf/with-effect [f] + (mf/set-ref-val! ptr #js {:f f})) + (mf/use-fn + (fn [& args] + (let [obj (mf/ref-val ptr)] + (when ^boolean obj + (apply (.-f obj) args))))))) (defn use-equal-memo [val] @@ -258,4 +282,34 @@ #(cp/focus-objects objects focus))] objects))) +(defn use-debounce + [ms value] + (let [[state update-state-fn] (mf/useState value) + update-fn (mf/use-memo (mf/deps ms) #(f/debounce update-state-fn ms))] + (mf/with-effect [value] + (update-fn value)) + state)) +(defn use-shared-state + "A specialized hook that adds persistence and inter-context reactivity + to the default mf/use-state hook. + + The state is automatically persisted under the provided key on + localStorage. And it will keep watching events with type equals to + `key` for new values." + [key default] + (let [id (use-id) + state (mf/use-state (get @storage key default)) + stream (mf/with-memo [] + (->> mbc/stream + (rx/filter #(= (:type %) key)) + (rx/filter #(not= (:id %) id)) + (rx/map deref)))] + + (mf/with-effect [@state key] + (mbc/emit! id key @state) + (swap! storage assoc key @state)) + + (use-stream stream (partial reset! state)) + + state)) diff --git a/frontend/src/app/main/ui/hooks/resize.cljs b/frontend/src/app/main/ui/hooks/resize.cljs index d640fd81b4..101d84b219 100644 --- a/frontend/src/app/main/ui/hooks/resize.cljs +++ b/frontend/src/app/main/ui/hooks/resize.cljs @@ -8,6 +8,7 @@ (:require [app.common.geom.point :as gpt] [app.common.logging :as log] + [app.common.spec :as us] [app.main.ui.context :as ctx] [app.main.ui.hooks :as hooks] [app.util.dom :as dom] @@ -73,43 +74,38 @@ (defn use-resize-observer [callback] - (assert (some? callback)) + (us/assert! (some? callback) "the `callback` is mandatory") (let [prev-val-ref (mf/use-ref nil) - current-observer-ref (mf/use-ref nil) - - callback-ref (hooks/use-update-var {:callback callback}) + observer-ref (mf/use-ref nil) + callback (hooks/use-ref-callback callback) ;; We use the ref as a callback when the dom node is ready (or change) - node-ref - (mf/use-callback - (fn [^js node] - (when (some? node) - (let [^js current-observer (mf/ref-val current-observer-ref) - ^js prev-val (mf/ref-val prev-val-ref)] + node-ref (mf/use-fn + (fn [^js node] + (when (some? node) + (let [^js observer (mf/ref-val observer-ref) + ^js prev-val (mf/ref-val prev-val-ref)] - (when (and (not= prev-val node) (some? current-observer)) - (log/debug :action "disconnect" :js/prev-val prev-val :js/node node) - (.disconnect current-observer) - (mf/set-ref-val! current-observer-ref nil)) + (when (and (not= prev-val node) (some? observer)) + (log/debug :action "disconnect" :js/prev-val prev-val :js/node node) + (.disconnect observer) + (mf/set-ref-val! observer-ref nil)) - (when (and (not= prev-val node) (some? node)) - (let [^js observer - (js/ResizeObserver. - #(let [callback (get @callback-ref :callback)] - (callback last-resize-type (dom/get-client-size node))))] - (mf/set-ref-val! current-observer-ref observer) - (log/debug :action "observe" :js/node node :js/observer observer) - (.observe observer node)))) + (when (and (not= prev-val node) (some? node)) + (let [^js observer (js/ResizeObserver. + #(callback last-resize-type (dom/get-client-size node)))] + (mf/set-ref-val! observer-ref observer) + (log/debug :action "observe" :js/node node :js/observer observer) + (.observe observer node)))) - (mf/set-ref-val! prev-val-ref node))))] + (mf/set-ref-val! prev-val-ref node))))] + + (mf/with-effect [] + ;; On dismount we need to disconnect the current observer + (fn [] + (when-let [observer (mf/ref-val observer-ref)] + (log/debug :action "disconnect") + (.disconnect ^js observer)))) - (mf/use-effect - (fn [] - ;; On dismount we need to disconnect the current observer - (fn [] - (let [current-observer (mf/ref-val current-observer-ref)] - (when (some? current-observer) - (log/debug :action "disconnect") - (.disconnect current-observer)))))) node-ref)) diff --git a/frontend/src/app/main/ui/workspace/colorpalette.cljs b/frontend/src/app/main/ui/workspace/colorpalette.cljs index c468632309..39b0e17bbb 100644 --- a/frontend/src/app/main/ui/workspace/colorpalette.cljs +++ b/frontend/src/app/main/ui/workspace/colorpalette.cljs @@ -6,11 +6,13 @@ (ns app.main.ui.workspace.colorpalette (:require + [app.common.data.macros :as dm] [app.main.data.workspace.colors :as mdc] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.color-bullet :as cb] [app.main.ui.components.dropdown :refer [dropdown]] + [app.main.ui.hooks :as h] [app.main.ui.hooks.resize :refer [use-resize-hook]] [app.main.ui.icons :as i] [app.util.dom :as dom] @@ -19,36 +21,21 @@ [app.util.object :as obj] [cuerdas.core :as str] [goog.events :as events] - [okulary.core :as l] [rumext.alpha :as mf])) -;; --- Refs - -(def palettes-ref - (-> (l/in [:library :palettes]) - (l/derived st/state))) - -(def selected-palette-ref - (-> (l/in [:workspace-global :selected-palette]) - (l/derived st/state))) - -(def selected-palette-size-ref - (-> (l/in [:workspace-global :selected-palette-size]) - (l/derived st/state))) - ;; --- Components -(mf/defc palette-item - [{:keys [color]}] - (let [select-color - (fn [event] - (st/emit! (mdc/apply-color-from-palette color (kbd/alt? event))))] +(mf/defc palette-item + {::mf/wrap [mf/memo]} + [{:keys [color]}] + (letfn [(select-color [event] + (st/emit! (mdc/apply-color-from-palette color (kbd/alt? event))))] [:div.color-cell {:on-click select-color} [:& cb/color-bullet {:color color}] [:& cb/color-name {:color color}]])) (mf/defc palette - [{:keys [current-colors recent-colors file-colors shared-libs selected]}] + [{:keys [current-colors recent-colors file-colors shared-libs selected on-select]}] (let [state (mf/use-state {:show-menu false}) width (:width @state 0) @@ -97,54 +84,66 @@ (fn [_] (let [dom (mf/ref-val container) width (obj/get dom "clientWidth")] - (swap! state assoc :width width))))] + (swap! state assoc :width width)))) + on-select-palette + (mf/use-fn + (mf/deps on-select) + (fn [event] + (let [node (dom/get-current-target event) + value (dom/get-attribute node "data-palette")] + (on-select (if (or (= "file" value) (= "recent" value)) + (keyword value) + (parse-uuid value))))))] (mf/use-layout-effect #(let [dom (mf/ref-val container) width (obj/get dom "clientWidth")] (swap! state assoc :width width))) - (mf/use-effect - #(let [key1 (events/listen js/window "resize" on-resize)] - (fn [] - (events/unlistenByKey key1)))) + (mf/with-effect [] + (let [key1 (events/listen js/window "resize" on-resize)] + #(events/unlistenByKey key1))) [:div.color-palette {:ref parent-ref :class (dom/classnames :no-text (< size 72)) - :style #js {"--height" (str size "px") - "--bullet-size" (str (if (< size 72) (- size 15) (- size 30)) "px")}} + :style #js {"--height" (dm/str size "px") + "--bullet-size" (dm/str (if (< size 72) (- size 15) (- size 30)) "px")}} [:div.resize-area {:on-pointer-down on-pointer-down :on-lost-pointer-capture on-lost-pointer-capture :on-mouse-move on-mouse-move}] [:& dropdown {:show (:show-menu @state) :on-close #(swap! state assoc :show-menu false)} [:ul.workspace-context-menu.palette-menu - (for [[idx cur-library] (map-indexed vector (vals shared-libs))] - (let [colors (-> cur-library (get-in [:data :colors]) vals)] + (for [{:keys [data id] :as library} (vals shared-libs)] + (let [colors (-> data :colors vals)] [:li.palette-library - {:key (str "library-" idx) - :on-click #(st/emit! (mdc/change-palette-selected (:id cur-library)))} - (when (= selected (:id cur-library)) i/tick) - [:div.library-name (str (:name cur-library) " " (str/format "(%s)" (count colors)))] + {:key (dm/str "library-" id) + :on-click on-select-palette + :data-palette (dm/str id)} + (when (= selected id) i/tick) + [:div.library-name (str (:name library) " " (str/ffmt "(%)" (count colors)))] [:div.color-sample - (for [[idx {:keys [color]}] (map-indexed vector (take 7 colors))] - [:& cb/color-bullet {:key (str "color-" idx) + (for [[i {:keys [color]}] (map-indexed vector (take 7 colors))] + [:& cb/color-bullet {:key (dm/str "color-" i) :color color}])]])) [:li.palette-library - {:on-click #(st/emit! (mdc/change-palette-selected :file))} + {:on-click on-select-palette + :data-palette "file"} (when (= selected :file) i/tick) - [:div.library-name (str (tr "workspace.libraries.colors.file-library") - (str/format " (%s)" (count file-colors)))] + [:div.library-name (dm/str + (tr "workspace.libraries.colors.file-library") + (str/ffmt " (%)" (count file-colors)))] [:div.color-sample - (for [[idx color] (map-indexed vector (take 7 (vals file-colors))) ] - [:& cb/color-bullet {:key (str "color-" idx) + (for [[i color] (map-indexed vector (take 7 (vals file-colors))) ] + [:& cb/color-bullet {:key (dm/str "color-" i) :color color}])]] [:li.palette-library - {:on-click #(st/emit! (mdc/change-palette-selected :recent))} + {:on-click on-select-palette + :data-palette "recent"} (when (= selected :recent) i/tick) [:div.library-name (str (tr "workspace.libraries.colors.recent-colors") (str/format " (%s)" (count recent-colors)))] @@ -178,34 +177,32 @@ (let [recent-colors (mf/deref refs/workspace-recent-colors) file-colors (mf/deref refs/workspace-file-colors) shared-libs (mf/deref refs/workspace-libraries) - selected (or (mf/deref selected-palette-ref) :recent) - current-library-colors (mf/use-state [])] + selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent) - (mf/use-effect - (mf/deps selected) - (fn [] - (reset! current-library-colors - (into [] - (cond - (= selected :recent) (reverse recent-colors) - (= selected :file) (->> (vals file-colors) (sort-by :name)) - :else (->> (library->colors shared-libs selected) (sort-by :name))))))) + colors (mf/use-state []) + on-select (mf/use-fn #(reset! selected %))] - (mf/use-effect - (mf/deps recent-colors) - (fn [] - (when (= selected :recent) - (reset! current-library-colors (reverse recent-colors))))) + (mf/with-effect [@selected] + (fn [] + (reset! colors + (into [] + (cond + (= @selected :recent) (reverse recent-colors) + (= @selected :file) (->> (vals file-colors) (sort-by :name)) + :else (->> (library->colors shared-libs @selected) (sort-by :name))))))) - (mf/use-effect - (mf/deps file-colors) - (fn [] - (when (= selected :file) - (reset! current-library-colors (into [] (->> (vals file-colors) - (sort-by :name))))))) + (mf/with-effect [recent-colors @selected] + (when (= @selected :recent) + (reset! colors (reverse recent-colors)))) - [:& palette {:current-colors @current-library-colors + (mf/with-effect [file-colors @selected] + (when (= @selected :file) + (reset! colors (into [] (->> (vals file-colors) + (sort-by :name)))))) + + [:& palette {:current-colors @colors :recent-colors recent-colors :file-colors file-colors :shared-libs shared-libs - :selected selected}])) + :selected @selected + :on-select on-select}])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 12829dd128..da975ea1d0 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -6,7 +6,6 @@ (ns app.main.ui.workspace.colorpicker (:require - [app.common.colors :as clr] [app.main.data.modal :as modal] [app.main.data.workspace.colors :as dc] [app.main.data.workspace.libraries :as dwl] @@ -41,247 +40,102 @@ (def viewport (l/derived :vport refs/workspace-local)) -(def editing-spot-state-ref - (l/derived :editing-stop refs/workspace-global)) - -(def current-gradient-ref - (l/derived :current-gradient refs/workspace-global)) - ;; --- Color Picker Modal -(defn color->components [value opacity] - (let [value (if (uc/hex? value) value clr/black) - [r g b] (uc/hex->rgb value) - [h s v] (uc/hex->hsv value)] - - {:hex (or value "000000") - :alpha (or opacity 1) - :r r :g g :b b - :h h :s s :v v})) - -(defn data->state [{:keys [color opacity gradient]}] - (let [type (cond - (nil? gradient) :color - (= :linear (:type gradient)) :linear-gradient - (= :radial (:type gradient)) :radial-gradient) - - parse-stop (fn [{:keys [offset color opacity]}] - (vector offset (color->components color opacity))) - - stops (when gradient - (map parse-stop (:stops gradient))) - - current-color (if (nil? gradient) - (color->components color opacity) - (-> stops first second)) - - gradient-data (select-keys gradient [:start-x :start-y - :end-x :end-y - :width])] - - (cond-> {:type type - :current-color current-color} - gradient (assoc :gradient-data gradient-data) - stops (assoc :stops (into {} stops)) - stops (assoc :editing-stop (-> stops first first))))) - -(defn state->data [{:keys [type current-color stops gradient-data]}] - (if (= type :color) - {:color (:hex current-color) - :opacity (:alpha current-color)} - - (let [gradient-type (case type - :linear-gradient :linear - :radial-gradient :radial) - parse-stop (fn [[offset {:keys [hex alpha]}]] - (hash-map :offset offset - :color hex - :opacity alpha))] - {:gradient (-> {:type gradient-type - :stops (mapv parse-stop stops)} - (merge gradient-data))}))) - -(defn create-gradient-data [type] - {:start-x 0.5 - :start-y (if (= type :linear-gradient) 0.0 0.5) - :end-x 0.5 - :end-y 1 - :width 1.0}) - (mf/defc colorpicker [{:keys [data disable-gradient disable-opacity on-change on-accept]}] - (let [state (mf/use-state (data->state data)) - active-tab (mf/use-state :ramp #_:harmony #_:hsva) + (let [state (mf/deref refs/colorpicker) + node-ref (mf/use-ref) - ref-picker (mf/use-ref) - - dirty? (mf/use-var false) - last-color (mf/use-var data) - - picking-color? (mf/deref picking-color?) - picked-color (mf/deref picked-color) + ;; TODO: I think we need to put all this picking state under + ;; the same object for avoid creating adhoc refs for each + ;; value + picking-color? (mf/deref picking-color?) + picked-color (mf/deref picked-color) picked-color-select (mf/deref picked-color-select) - editing-spot-state (mf/deref editing-spot-state-ref) - current-gradient (mf/deref current-gradient-ref) + current-color (:current-color state) - current-color (:current-color @state) - - change-tab - (fn [tab] - #(reset! active-tab tab)) + active-tab (mf/use-state :ramp #_:harmony #_:hsva) + set-ramp-tab! (mf/use-fn #(reset! active-tab :ramp)) + set-harmony-tab! (mf/use-fn #(reset! active-tab :harmony)) + set-hsva-tab! (mf/use-fn #(reset! active-tab :hsva)) handle-change-color - (fn [changes] - (let [editing-stop (:editing-stop @state)] - (swap! state #(cond-> % - :always - (update :current-color merge changes) - - (not editing-stop) - (-> (assoc :type :color) - (dissoc :gradient-data :stops :editing-stops)) - - editing-stop - (update-in [:stops editing-stop] merge changes))) - (reset! dirty? true))) + (mf/use-fn #(st/emit! (dc/update-colorpicker-color %))) handle-click-picker - (fn [] - (if picking-color? - (do (modal/disallow-click-outside!) - (st/emit! (dc/stop-picker))) - (do (modal/allow-click-outside!) - (st/emit! (dc/start-picker))))) + (mf/use-fn + (mf/deps picking-color?) + (fn [] + (if picking-color? + (do (modal/disallow-click-outside!) + (st/emit! (dc/stop-picker))) + (do (modal/allow-click-outside!) + (st/emit! (dc/start-picker)))))) handle-change-stop - (fn [offset] - (when-let [offset-color (get-in @state [:stops offset])] - (swap! state assoc - :current-color offset-color - :editing-stop offset) - - (st/emit! (dc/select-gradient-stop offset)))) + (mf/use-fn + (fn [offset] + (st/emit! (dc/select-colorpicker-gradient-stop offset)))) on-select-library-color - (fn [color] - (let [editing-stop (:editing-stop @state) - is-gradient? (some? (:gradient color))] - - (if is-gradient? - (st/emit! (dc/start-gradient (:gradient color))) - (st/emit! (dc/stop-gradient))) - - (if (and (some? editing-stop) (not is-gradient?)) - (handle-change-color (color->components (:color color) (:opacity color))) - (do (reset! dirty? false) - (reset! state (-> (data->state color) - (assoc :editing-stop nil))) - (on-change color))))) - + (mf/use-fn + (fn [color] + (on-change color))) on-add-library-color - (fn [_] - (st/emit! (dwl/add-color (state->data @state)))) + (mf/use-fn + (mf/deps state) + (fn [_] + (st/emit! (dwl/add-color (dc/get-color-from-colorpicker-state state))))) - on-activate-gradient - (fn [type] - (fn [] - (reset! dirty? true) - (if (= type (:type @state)) - (do - (swap! state assoc :type :color) - (swap! state dissoc :editing-stop :stops :gradient-data) - (st/emit! (dc/stop-gradient))) - (let [gradient-data (create-gradient-data type)] - (swap! state assoc :type type :gradient-data gradient-data) - (when (not (:stops @state)) - (swap! state assoc - :editing-stop 0 - :stops {0 (:current-color @state) - 1 (-> (:current-color @state) - (assoc :alpha 0))}))))))] + on-activate-linear-gradient + (mf/use-fn #(st/emit! (dc/activate-colorpicker-gradient :linear-gradient))) + + on-activate-radial-gradient + (mf/use-fn #(st/emit! (dc/activate-colorpicker-gradient :radial-gradient)))] + + ;; Initialize colorpicker state + (mf/with-effect [] + (st/emit! (dc/initialize-colorpicker on-change)) + (partial st/emit! (dc/finalize-colorpicker))) + + ;; Update colorpicker with external color changes + (mf/with-effect [data] + (st/emit! (dc/update-colorpicker data))) ;; Updates the CSS color variable when there is a change in the color - (mf/use-effect - (mf/deps current-color) - (fn [] (let [node (mf/ref-val ref-picker) - {:keys [r g b h v]} current-color - rgb [r g b] - hue-rgb (uc/hsv->rgb [h 1.0 255]) - hsl-from (uc/hsv->hsl [h 0.0 v]) - hsl-to (uc/hsv->hsl [h 1.0 v]) + (mf/with-effect [current-color] + (let [node (mf/ref-val node-ref) + {:keys [r g b h v]} current-color + rgb [r g b] + hue-rgb (uc/hsv->rgb [h 1.0 255]) + hsl-from (uc/hsv->hsl [h 0.0 v]) + hsl-to (uc/hsv->hsl [h 1.0 v]) - format-hsl (fn [[h s l]] - (str/fmt "hsl(%s, %s, %s)" - h - (str (* s 100) "%") - (str (* l 100) "%")))] - (dom/set-css-property! node "--color" (str/join ", " rgb)) - (dom/set-css-property! node "--hue-rgb" (str/join ", " hue-rgb)) - (dom/set-css-property! node "--saturation-grad-from" (format-hsl hsl-from)) - (dom/set-css-property! node "--saturation-grad-to" (format-hsl hsl-to))))) - - ;; When closing the modal we update the recent-color list - (mf/use-effect - #(fn [] - (st/emit! (dc/stop-picker)) - (when @last-color - (st/emit! (dwl/add-recent-color @last-color))))) + format-hsl (fn [[h s l]] + (str/fmt "hsl(%s, %s, %s)" + h + (str (* s 100) "%") + (str (* l 100) "%")))] + (dom/set-css-property! node "--color" (str/join ", " rgb)) + (dom/set-css-property! node "--hue-rgb" (str/join ", " hue-rgb)) + (dom/set-css-property! node "--saturation-grad-from" (format-hsl hsl-from)) + (dom/set-css-property! node "--saturation-grad-to" (format-hsl hsl-to)))) ;; Updates color when used el pixel picker - (mf/use-effect - (mf/deps picking-color? picked-color picked-color-select) - (fn [] - (when (and picking-color? picked-color picked-color-select) - (let [[r g b alpha] picked-color - hex (uc/rgb->hex [r g b]) - [h s v] (uc/hex->hsv hex)] - (handle-change-color {:hex hex - :r r :g g :b b - :h h :s s :v v - :alpha (/ alpha 255)}))))) + (mf/with-effect [picking-color? picked-color picked-color-select] + (when (and picking-color? picked-color picked-color-select) + (let [[r g b alpha] picked-color + hex (uc/rgb->hex [r g b]) + [h s v] (uc/hex->hsv hex)] + (handle-change-color {:hex hex + :r r :g g :b b + :h h :s s :v v + :alpha (/ alpha 255)})))) - ;; Changes when another gradient handler is selected - (mf/use-effect - (mf/deps editing-spot-state) - #(when (not= editing-spot-state (:editing-stop @state)) - (handle-change-stop (or editing-spot-state 0)))) - - ;; Changes on the viewport when moving a gradient handler - (mf/use-effect - (mf/deps current-gradient) - (fn [] - (when current-gradient - (let [gradient-data (select-keys current-gradient [:start-x :start-y - :end-x :end-y - :width])] - (when (not= (:gradient-data @state) gradient-data) - (reset! dirty? true) - (swap! state assoc :gradient-data gradient-data)))))) - - ;; Check if we've opened a color with gradient - (mf/use-effect - (fn [] - (when (:gradient data) - (st/emit! (dc/start-gradient (:gradient data)))) - - ;; on-unmount we stop the handlers - #(st/emit! (dc/stop-gradient)))) - - ;; Send the properties to the store - (mf/use-effect - (mf/deps @state) - (fn [] - (when @dirty? - (let [color (state->data @state)] - (reset! dirty? false) - (reset! last-color color) - (when (:gradient color) - (st/emit! (dc/start-gradient (:gradient color)))) - (on-change color))))) - - [:div.colorpicker {:ref ref-picker} + [:div.colorpicker {:ref node-ref} [:div.colorpicker-content [:div.top-actions [:button.picker-btn @@ -292,70 +146,81 @@ (when (not disable-gradient) [:div.gradients-buttons [:button.gradient.linear-gradient - {:on-click (on-activate-gradient :linear-gradient) - :class (when (= :linear-gradient (:type @state)) "active")}] + {:on-click on-activate-linear-gradient + :class (when (= :linear-gradient (:type state)) "active")}] [:button.gradient.radial-gradient - {:on-click (on-activate-gradient :radial-gradient) - :class (when (= :radial-gradient (:type @state)) "active")}]])] + {:on-click on-activate-radial-gradient + :class (when (= :radial-gradient (:type state)) "active")}]])] - [:& gradients {:type (:type @state) - :stops (:stops @state) - :editing-stop (:editing-stop @state) - :on-select-stop handle-change-stop}] + + (when (or (= (:type state) :linear-gradient) + (= (:type state) :radial-gradient)) + [:& gradients + {:stops (:stops state) + :editing-stop (:editing-stop state) + :on-select-stop handle-change-stop}]) [:div.colorpicker-tabs [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand {:class (when (= @active-tab :ramp) "active") :alt (tr "workspace.libraries.colors.rgba") - :on-click (change-tab :ramp)} i/picker-ramp] + :on-click set-ramp-tab!} i/picker-ramp] [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand {:class (when (= @active-tab :harmony) "active") :alt (tr "workspace.libraries.colors.rgb-complementary") - :on-click (change-tab :harmony)} i/picker-harmony] + :on-click set-harmony-tab!} i/picker-harmony] [:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand {:class (when (= @active-tab :hsva) "active") :alt (tr "workspace.libraries.colors.hsv") - :on-click (change-tab :hsva)} i/picker-hsv]] + :on-click set-hsva-tab!} i/picker-hsv]] (if picking-color? [:div.picker-detail-wrapper [:div.center-circle] [:canvas#picker-detail {:width 200 :height 160}]] (case @active-tab - :ramp [:& ramp-selector {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag #(st/emit! (dwu/start-undo-transaction)) - :on-finish-drag #(st/emit! (dwu/commit-undo-transaction))}] - :harmony [:& harmony-selector {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag #(st/emit! (dwu/start-undo-transaction)) - :on-finish-drag #(st/emit! (dwu/commit-undo-transaction))}] - :hsva [:& hsva-selector {:color current-color - :disable-opacity disable-opacity - :on-change handle-change-color - :on-start-drag #(st/emit! (dwu/start-undo-transaction)) - :on-finish-drag #(st/emit! (dwu/commit-undo-transaction))}] + :ramp + [:& ramp-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag #(st/emit! (dwu/start-undo-transaction)) + :on-finish-drag #(st/emit! (dwu/commit-undo-transaction))}] + :harmony + [:& harmony-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag #(st/emit! (dwu/start-undo-transaction)) + :on-finish-drag #(st/emit! (dwu/commit-undo-transaction))}] + :hsva + [:& hsva-selector + {:color current-color + :disable-opacity disable-opacity + :on-change handle-change-color + :on-start-drag #(st/emit! (dwu/start-undo-transaction)) + :on-finish-drag #(st/emit! (dwu/commit-undo-transaction))}] nil)) - [:& color-inputs {:type (if (= @active-tab :hsva) :hsv :rgb) - :disable-opacity disable-opacity - :color current-color - :on-change handle-change-color}] + [:& color-inputs + {:type (if (= @active-tab :hsva) :hsv :rgb) + :disable-opacity disable-opacity + :color current-color + :on-change handle-change-color}] - [:& libraries {:current-color current-color - :disable-gradient disable-gradient - :disable-opacity disable-opacity - :on-select-color on-select-library-color - :on-add-library-color on-add-library-color}] + [:& libraries + {:current-color current-color + :disable-gradient disable-gradient + :disable-opacity disable-opacity + :on-select-color on-select-library-color + :on-add-library-color on-add-library-color}] (when on-accept [:div.actions [:button.btn-primary.btn-large {:on-click (fn [] - (on-accept (state->data @state)) + (on-accept (dc/get-color-from-colorpicker-state state)) (modal/hide!))} (tr "workspace.libraries.colors.save-color")]])]])) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs index b1645d3f64..d2d58ae509 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs @@ -11,13 +11,17 @@ [app.util.dom :as dom] [rumext.alpha :as mf])) +(defn parse-hex + [val] + (if (= (first val) \#) + val + (str \# val))) + (mf/defc color-inputs [{:keys [type color disable-opacity on-change]}] (let [{red :r green :g blue :b hue :h saturation :s value :v hex :hex alpha :alpha} color - parse-hex (fn [val] (if (= (first val) \#) val (str \# val))) - refs {:hex (mf/use-ref nil) :r (mf/use-ref nil) :g (mf/use-ref nil) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs index 56c3ef0509..78072f564c 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs @@ -6,32 +6,31 @@ (ns app.main.ui.workspace.colorpicker.gradients (:require + [app.common.data.macros :as dm] [cuerdas.core :as str] [rumext.alpha :as mf])) -(defn gradient->string [stops] - (let [format-stop - (fn [[offset {:keys [r g b alpha]}]] - (str/fmt "rgba(%s, %s, %s, %s) %s" - r g b alpha (str (* offset 100) "%"))) +(defn- format-rgba + [{:keys [r g b alpha offset]}] + (str/ffmt "rgba(%1, %2, %3, %4) %5%%" r g b alpha (* offset 100))) - gradient-css (str/join "," (map format-stop stops))] - (str/fmt "linear-gradient(90deg, %s)" gradient-css))) +(defn- gradient->string [stops] + (let [gradient-css (str/join ", " (map format-rgba stops))] + (str/ffmt "linear-gradient(90deg, %1)" gradient-css))) -(mf/defc gradients [{:keys [type stops editing-stop on-select-stop]}] - (when (#{:linear-gradient :radial-gradient} type) - [:div.gradient-stops - [:div.gradient-background-wrapper - [:div.gradient-background {:style {:background (gradient->string stops)}}]] +(mf/defc gradients + [{:keys [stops editing-stop on-select-stop]}] + [:div.gradient-stops + [:div.gradient-background-wrapper + [:div.gradient-background {:style {:background (gradient->string stops)}}]] - [:div.gradient-stop-wrapper - (for [[offset value] stops] - [:div.gradient-stop - {:class (when (= editing-stop offset) "active") - :on-click (partial on-select-stop offset) - :style {:left (str (* offset 100) "%")}} + [:div.gradient-stop-wrapper + (for [{:keys [offset hex r g b alpha] :as value} stops] + [:div.gradient-stop + {:class (when (= editing-stop offset) "active") + :on-click (partial on-select-stop offset) + :style {:left (dm/str (* offset 100) "%")} + :key (dm/str offset)} - (let [{:keys [hex r g b alpha]} value] - [:* - [:div.gradient-stop-color {:style {:background-color hex}}] - [:div.gradient-stop-alpha {:style {:background-color (str/format "rgba(%s, %s, %s, %s)" r g b alpha)}}]])])]])) + [:div.gradient-stop-color {:style {:background-color hex}}] + [:div.gradient-stop-alpha {:style {:background-color (str/ffmt "rgba(%1, %2, %3, %4)" r g b alpha)}}]])]]) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index 79b4becb6c..8e3b6e3925 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -6,90 +6,85 @@ (ns app.main.ui.workspace.colorpicker.libraries (:require - [app.common.uuid :refer [uuid]] + [app.common.data.macros :as dm] [app.main.data.workspace.colors :as dc] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.components.color-bullet :refer [color-bullet]] + [app.main.ui.hooks :as h] [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [okulary.core :as l] [rumext.alpha :as mf])) -(def selected-palette-ref - (-> (l/in [:workspace-global :selected-palette-colorpicker]) - (l/derived st/state))) - (mf/defc libraries [{:keys [on-select-color on-add-library-color disable-gradient disable-opacity]}] - (let [selected-library (or (mf/deref selected-palette-ref) :recent) - current-library-colors (mf/use-state []) + (let [selected (h/use-shared-state dc/colorpicker-selected-broadcast-key :recent) + current-colors (mf/use-state []) shared-libs (mf/deref refs/workspace-libraries) file-colors (mf/deref refs/workspace-file-colors) recent-colors (mf/deref refs/workspace-recent-colors) - parse-selected - (fn [selected-str] - (if (#{"recent" "file"} selected-str) - (keyword selected-str) - (uuid selected-str))) + on-library-change + (mf/use-fn + (fn [event] + (let [val (dom/get-target-val event)] + (reset! selected + (if (or (= val "recent") + (= val "file")) + (keyword val) + (parse-uuid val)))))) - check-valid-color? (fn [color] - (and (or (not disable-gradient) (not (:gradient color))) - (or (not disable-opacity) (= 1 (:opacity color)))))] + check-valid-color? + (fn [color] + (and (or (not disable-gradient) (not (:gradient color))) + (or (not disable-opacity) (= 1 (:opacity color)))))] ;; Load library colors when the select is changed - (mf/use-effect - (mf/deps selected-library) - (fn [] - (let [mapped-colors - (cond - (= selected-library :recent) - ;; The `map?` check is to keep backwards compatibility. We transform from string to map - (map #(if (map? %) % (hash-map :color %)) (reverse (or recent-colors []))) + (mf/with-effect [@selected recent-colors file-colors] + (let [colors (cond + (= @selected :recent) + ;; The `map?` check is to keep backwards compatibility. We transform from string to map + (map #(if (map? %) % {:color %}) (reverse (or recent-colors []))) - (= selected-library :file) - (vals file-colors) + (= @selected :file) + (vals file-colors) - :else ;; Library UUID - (->> (get-in shared-libs [selected-library :data :colors]) - (vals) - (map #(merge % {:file-id selected-library}))))] + :else ;; Library UUID + (as-> @selected file-id + (->> (get-in shared-libs [file-id :data :colors]) + (vals) + (map #(assoc % :file-id file-id)))))] - (reset! current-library-colors (into [] (filter check-valid-color?) mapped-colors))))) + (reset! current-colors (into [] (filter check-valid-color?) colors)))) ;; If the file colors change and the file option is selected updates the state - (mf/use-effect - (mf/deps file-colors) - (fn [] (when (= selected-library :file) - (let [colors (vals file-colors)] - (reset! current-library-colors (into [] (filter check-valid-color?) colors)))))) + (mf/with-effect [file-colors] + (when (= @selected :file) + (let [colors (vals file-colors)] + (reset! current-colors (into [] (filter check-valid-color?) colors))))) [:div.libraries - [:select {:on-change (fn [e] - (when-let [val (parse-selected (dom/get-target-val e))] - (st/emit! (dc/change-palette-selected-colorpicker val)))) - :value (name selected-library)} + [:select {:on-change on-library-change :value (name @selected)} [:option {:value "recent"} (tr "workspace.libraries.colors.recent-colors")] [:option {:value "file"} (tr "workspace.libraries.colors.file-library")] (for [[_ {:keys [name id]}] shared-libs] - [:option {:key id - :value id} name])] + [:option {:key id :value id} name])] [:div.selected-colors - (when (= selected-library :file) + (when (= @selected :file) [:div.color-bullet.button.plus-button {:style {:background-color "var(--color-white)"} :on-click on-add-library-color} i/plus]) [:div.color-bullet.button {:style {:background-color "var(--color-white)"} - :on-click #(st/emit! (dc/show-palette selected-library))} + :on-click #(st/emit! (dc/show-palette @selected))} i/palette] - (for [[idx color] (map-indexed vector @current-library-colors)] - [:& color-bullet {:key (str "color-" idx) - :color color - :on-click #(on-select-color color)}])]])) + (for [[idx color] (map-indexed vector @current-colors)] + [:& color-bullet + {:key (dm/str "color-" idx) + :color color + :on-click on-select-color}])]])) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs index 9a3f0d0782..28c72adf2f 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs @@ -79,7 +79,7 @@ shape-bb-ref (hooks/use-update-var shape-bb) - updates-str (mf/use-memo #(rx/subject)) + updates-str (mf/use-memo #(rx/subject)) thumbnail-data-ref (mf/use-memo (mf/deps page-id id) #(refs/thumbnail-frame-data page-id id)) thumbnail-data (mf/deref thumbnail-data-ref) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs index 5b147fc76d..052a8f7d68 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs @@ -152,12 +152,9 @@ (fn [state] (let [old-state (mf/ref-val prev-value)] (if (and (some? state) (some? old-state)) - (let [block-changes (ted/get-content-changes old-state state) - - prev-data (-> (ted/get-editor-current-inline-styles old-state) - (dissoc :text-align :text-direction)) - - block-to-setup (get-blocks-to-setup block-changes) + (let [block-changes (ted/get-content-changes old-state state) + prev-data (ted/get-editor-current-inline-styles old-state) + block-to-setup (get-blocks-to-setup block-changes) block-to-add-styles (get-blocks-to-add-styles block-changes)] (-> state (ted/setup-block-styles block-to-setup prev-data) @@ -211,11 +208,12 @@ handle-pasted-text (fn [text _ _] - (let [style (ted/get-editor-current-inline-styles state) - state (-> (ted/insert-text state text style) - (handle-change))] + (let [current-block-styles (ted/get-editor-current-block-data state) + inline-styles (ted/get-editor-current-inline-styles state) + style (merge current-block-styles inline-styles) + state (-> (ted/insert-text state text style) + (handle-change))] (st/emit! (dwt/update-editor-state shape state))) - "handled")] (mf/use-layout-effect on-mount) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 79d84a7675..dd197446f0 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -19,7 +19,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [clojure.set :refer [union]] + [clojure.set :refer [rename-keys union]] [rumext.alpha :as mf])) (def measure-attrs @@ -46,10 +46,26 @@ :svg-raw #{:size :position :rotation} :text #{:size :position :rotation}}) +(defn select-measure-keys + "Consider some shapes can be drawn from bottom to top or from left to right" + [shape] + (let [shape (cond + (and (:flip-x shape) (:flip-y shape)) + (rename-keys shape {:r1 :r3 :r2 :r4 :r3 :r1 :r4 :r2}) + + (:flip-x shape) + (rename-keys shape {:r1 :r2 :r2 :r1 :r3 :r4 :r4 :r3}) + + (:flip-y shape) + (rename-keys shape {:r1 :r4 :r2 :r3 :r3 :r2 :r4 :r1}) + + :else + shape)] + (select-keys shape measure-attrs))) + ;; -- User/drawing coords (mf/defc measures-menu [{:keys [ids ids-with-children values type all-types shape] :as props}] - (let [options (if (= type :multiple) (reduce #(union %1 %2) (map #(get type->options %) all-types)) (get type->options type)) @@ -221,7 +237,7 @@ (st/emit! (dch/update-shapes ids (fn [shape] (assoc shape :hide-in-viewer (not value)))))))) select-all #(-> % (dom/get-target) (.select))] - + (mf/use-layout-effect (mf/deps radius-mode @radius-multi?) (fn [] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs index fd608efd18..3f2200139a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.workspace.sidebar.options.rows.color-row (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.pages :as cp] [app.main.data.modal :as modal] [app.main.refs :as refs] @@ -22,34 +23,8 @@ [app.util.i18n :as i18n :refer [tr]] [rumext.alpha :as mf])) -(defn color-picker-callback - [color disable-gradient disable-opacity handle-change-color handle-open handle-close] - (fn [event] - (let [color - (cond - (uc/multiple? color) - {:color cp/default-color - :opacity 1} - - (= :multiple (:opacity color)) - (assoc color :opacity 1) - - :else - color) - - x (.-clientX event) - y (.-clientY event) - props {:x x - :y y - :disable-gradient disable-gradient - :disable-opacity disable-opacity - :on-change handle-change-color - :on-close handle-close - :data color}] - (handle-open color) - (modal/show! :colorpicker props)))) - -(defn opacity->string [opacity] +(defn opacity->string + [opacity] (if (= opacity :multiple) "" (str (-> opacity @@ -57,7 +32,8 @@ (* 100) (fmt/format-number))))) -(defn remove-multiple [v] +(defn remove-multiple + [v] (if (= v :multiple) nil v)) (mf/defc color-row @@ -68,64 +44,88 @@ file-colors (mf/deref refs/workspace-file-colors) shared-libs (mf/deref refs/workspace-libraries) hover-detach (mf/use-state false) + on-change (h/use-ref-callback on-change) + src-colors (if (= (:file-id color) current-file-id) + file-colors + (dm/get-in shared-libs [(:file-id color) :data :colors])) - on-change-var (h/use-update-var {:fn on-change}) + color-name (dm/get-in src-colors [(:id color) :name]) - src-colors (if (= (:file-id color) current-file-id) - file-colors - (get-in shared-libs [(:file-id color) :data :colors])) + parse-color + (mf/use-fn + (fn [color] + (update color :color #(or % (:value color))))) - color-name (get-in src-colors [(:id color) :name]) + detach-value + (mf/use-fn + (mf/deps on-detach color) + (fn [] + (when on-detach + (on-detach color)))) - parse-color (fn [color] - (-> color - (update :color #(or % (:value color))))) + handle-select + (mf/use-fn + (mf/deps select-only color) + (fn [] + (select-only color))) - detach-value (fn [] - (when on-detach (on-detach color))) + handle-value-change + (mf/use-fn + (mf/deps color on-change) + (fn [new-value] + (on-change (-> color + (assoc :color new-value) + (dissoc :gradient))))) - change-value (fn [new-value] - (when (:fn @on-change-var) ((:fn @on-change-var) (-> color - (assoc :color new-value) - (dissoc :gradient))))) + handle-opacity-change + (mf/use-fn + (mf/deps color on-change) + (fn [value] + (on-change (assoc color + :opacity (/ value 100) + :id nil + :file-id nil)))) - change-opacity (fn [new-opacity] - (when (:fn @on-change-var) ((:fn @on-change-var) (assoc color - :opacity new-opacity - :id nil - :file-id nil)))) + handle-click-color + (mf/use-fn + (mf/deps disable-gradient disable-opacity on-change on-close on-open) + (fn [color event] + (let [color (cond + (uc/multiple? color) + {:color cp/default-color + :opacity 1} - handle-pick-color (fn [color] - (when (:fn @on-change-var) ((:fn @on-change-var) (merge uc/empty-color color)))) + (= :multiple (:opacity color)) + (assoc color :opacity 1) - handle-select (fn [] - (select-only color)) + :else + color) - handle-open (fn [color] - (when on-open (on-open (merge uc/empty-color color)))) + {:keys [x y]} (dom/get-client-position event) - handle-close (fn [value opacity id file-id] - (when on-close (on-close value opacity id file-id))) + props {:x x + :y y + :disable-gradient disable-gradient + :disable-opacity disable-opacity + :on-change #(on-change (merge uc/empty-color %)) + :on-close (fn [value opacity id file-id] + (when on-close + (on-close value opacity id file-id))) + :data color}] - handle-value-change (fn [new-value] - (-> new-value - change-value)) + (when on-open + (on-open (merge uc/empty-color color))) - handle-opacity-change (fn [value] - (change-opacity (/ value 100))) + (modal/show! :colorpicker props)))) - handle-click-color (color-picker-callback color - disable-gradient - disable-opacity - handle-pick-color - handle-open - handle-close) prev-color (h/use-previous color) on-drop - (fn [_ data] - (on-reorder (:index data))) + (mf/use-fn + (mf/deps on-reorder) + (fn [_ data] + (on-reorder (:index data)))) [dprops dref] (if (some? on-reorder) (h/use-sortable @@ -138,11 +138,9 @@ :name (str "Color row" index)}) [nil nil])] - (mf/use-effect - (mf/deps color prev-color) - (fn [] - (when (not= prev-color color) - (modal/update-props! :colorpicker {:data (parse-color color)})))) + (mf/with-effect [color prev-color] + (when (not= prev-color color) + (modal/update-props! :colorpicker {:data (parse-color color)}))) [:div.row-flex.color-data {:title title :class (dom/classnames @@ -182,7 +180,7 @@ (when select-only [:div.element-set-actions-button {:on-click handle-select} i/pointer-inner])] - + ;; Rendering a plain color/opacity :else diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index 0b1896be34..0b2ca73263 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -21,11 +21,11 @@ [app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]] [app.main.ui.workspace.sidebar.options.menus.layout-container :refer [layout-container-attrs layout-container-menu]] [app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]] - [app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]] + [app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measure-attrs measures-menu]] [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-attrs shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [app.main.ui.workspace.sidebar.options.menus.text :as ot] - [rumext.alpha :as mf])) + [rumext.alpha :as mf])) ;; Define how to read each kind of attribute depending on the shape type: ;; - shape: read the attribute directly from the shape. @@ -197,8 +197,10 @@ :shape (let [;; Get the editable attrs from the shape, ensuring that all attributes ;; are present, with value nil if they are not present in the shape. shape-values (merge - (into {} (map #(vector % nil)) editable-attrs) - (select-keys shape editable-attrs))] + (into {} (map #(vector % nil)) editable-attrs) + (cond + (= attr-group :measure) (select-measure-keys shape) + :else (select-keys shape editable-attrs)))] [(conj ids id) (merge-attrs values shape-values)]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs index 4c16b9fe0e..3850f30924 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs @@ -12,7 +12,7 @@ [app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-attrs fill-menu]] [app.main.ui.workspace.sidebar.options.menus.layer :refer [layer-attrs layer-menu]] [app.main.ui.workspace.sidebar.options.menus.layout-item :refer [layout-item-attrs layout-item-menu]] - [app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]] + [app.main.ui.workspace.sidebar.options.menus.measures :refer [select-measure-keys measures-menu]] [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]] @@ -23,8 +23,7 @@ [{:keys [shape] :as props}] (let [ids [(:id shape)] type (:type shape) - - measure-values (select-keys shape measure-attrs) + measure-values (select-measure-keys shape) layer-values (select-keys shape layer-attrs) constraint-values (select-keys shape constraint-attrs) fill-values (select-keys shape fill-attrs) diff --git a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs index 08b524f0ba..4648836473 100644 --- a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs @@ -19,7 +19,6 @@ [app.util.dom :as dom] [beicon.core :as rx] [cuerdas.core :as str] - [okulary.core :as l] [rumext.alpha :as mf])) (def gradient-line-stroke-width 2) @@ -32,12 +31,6 @@ (def gradient-square-stroke-color "var(--color-white)") (def gradient-square-stroke-color-selected "var(--color-select)") -(def editing-spot-ref - (l/derived (l/in [:workspace-global :editing-stop]) st/state)) - -(def current-gradient-ref - (l/derived (l/in [:workspace-global :current-gradient]) st/state =)) - (mf/defc shadow [{:keys [id x y width height offset]}] [:filter {:id id :x x @@ -130,27 +123,32 @@ (let [moving-point (mf/use-var nil) angle (+ 90 (gpt/angle from-p to-p)) - on-click (fn [position event] - (dom/stop-propagation event) - (dom/prevent-default event) - (when (#{:from-p :to-p} position) - (st/emit! (dc/select-gradient-stop (case position - :from-p 0 - :to-p 1))))) + on-click + (fn [position event] + (dom/stop-propagation event) + (dom/prevent-default event) + (when (#{:from-p :to-p} position) + (st/emit! (dc/select-colorpicker-gradient-stop + (case position + :from-p 0 + :to-p 1))))) - on-mouse-down (fn [position event] - (dom/stop-propagation event) - (dom/prevent-default event) - (reset! moving-point position) - (when (#{:from-p :to-p} position) - (st/emit! (dc/select-gradient-stop (case position - :from-p 0 - :to-p 1))))) + on-mouse-down + (fn [position event] + (dom/stop-propagation event) + (dom/prevent-default event) + (reset! moving-point position) + (when (#{:from-p :to-p} position) + (st/emit! (dc/select-colorpicker-gradient-stop + (case position + :from-p 0 + :to-p 1))))) - on-mouse-up (fn [_position event] - (dom/stop-propagation event) - (dom/prevent-default event) - (reset! moving-point nil))] + on-mouse-up + (fn [_position event] + (dom/stop-propagation event) + (dom/prevent-default event) + (reset! moving-point nil))] (mf/use-effect (mf/deps @moving-point from-p to-p width-p) @@ -230,37 +228,24 @@ :on-mouse-down (partial on-mouse-down :to-p) :on-mouse-up (partial on-mouse-up :to-p)}]])) - -(mf/defc gradient-handlers - {::mf/wrap [mf/memo]} - [{:keys [id zoom]}] - (let [current-change (mf/use-state {}) - shape-ref (mf/use-memo (mf/deps id) #(refs/object-by-id id)) - shape (mf/deref shape-ref) - - gradient (mf/deref current-gradient-ref) - gradient (merge gradient @current-change) - - editing-spot (mf/deref editing-spot-ref) - - transform (gsh/transform-matrix shape) +(mf/defc gradient-handlers* + [{:keys [zoom stops gradient editing-stop shape]}] + (let [transform (gsh/transform-matrix shape) transform-inverse (gsh/inverse-transform-matrix shape) {:keys [x y width height] :as sr} (:selrect shape) [{start-color :color start-opacity :opacity} - {end-color :color end-opacity :opacity}] (:stops gradient) + {end-color :color end-opacity :opacity}] stops from-p (-> (gpt/point (+ x (* width (:start-x gradient))) (+ y (* height (:start-y gradient)))) - (gpt/transform transform)) - to-p (-> (gpt/point (+ x (* width (:end-x gradient))) (+ y (* height (:end-y gradient)))) (gpt/transform transform)) - gradient-vec (gpt/to-vec from-p to-p) + gradient-vec (gpt/to-vec from-p to-p) gradient-length (gpt/length gradient-vec) width-v (-> gradient-vec @@ -271,13 +256,12 @@ width-p (gpt/add from-p width-v) change! - (mf/use-callback + (mf/use-fn (fn [changes] - (swap! current-change merge changes) - (st/emit! (dc/update-gradient changes)))) + (st/emit! (dc/update-colorpicker-gradient changes)))) on-change-start - (mf/use-callback + (mf/use-fn (mf/deps transform-inverse width height) (fn [point] (let [point (gpt/transform point transform-inverse) @@ -286,7 +270,7 @@ (change! {:start-x start-x :start-y start-y})))) on-change-finish - (mf/use-callback + (mf/use-fn (mf/deps transform-inverse width height) (fn [point] (let [point (gpt/transform point transform-inverse) @@ -295,7 +279,7 @@ (change! {:end-x end-x :end-y end-y})))) on-change-width - (mf/use-callback + (mf/use-fn (mf/deps gradient-length width height) (fn [point] (let [scale-factor-y (/ gradient-length (/ height 2)) @@ -304,17 +288,35 @@ (when (and norm-dist (d/num? norm-dist)) (change! {:width norm-dist})))))] - (when (and gradient + [:& gradient-handler-transformed + {:editing editing-stop + :from-p from-p + :to-p to-p + :width-p (when (= :radial (:type gradient)) width-p) + :from-color {:value start-color :opacity start-opacity} + :to-color {:value end-color :opacity end-opacity} + :zoom zoom + :on-change-start on-change-start + :on-change-finish on-change-finish + :on-change-width on-change-width}])) + +(mf/defc gradient-handlers + {::mf/wrap [mf/memo]} + [{:keys [id zoom]}] + (let [shape-ref (mf/use-memo (mf/deps id) #(refs/object-by-id id)) + shape (mf/deref shape-ref) + + state (mf/deref refs/colorpicker) + gradient (:gradient state) + stops (:stops state) + editing-stop (:editing-stop state)] + + (when (and (some? gradient) (= id (:shape-id gradient)) (not= (:type shape) :text)) - [:& gradient-handler-transformed - {:editing editing-spot - :from-p from-p - :to-p to-p - :width-p (when (= :radial (:type gradient)) width-p) - :from-color {:value start-color :opacity start-opacity} - :to-color {:value end-color :opacity end-opacity} - :zoom zoom - :on-change-start on-change-start - :on-change-finish on-change-finish - :on-change-width on-change-width}]))) + [:& gradient-handlers* + {:zoom zoom + :gradient gradient + :stops stops + :editing-stop editing-stop + :shape shape}]))) diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index 23e4044106..c30e1d4856 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -121,7 +121,7 @@ (defn get-current-target "Extract the current target from event instance (different from target - when event triggered in a child of the subscribing element)." + when event triggered in a child of the subscribing element)." [^js event] (when (some? event) (.-currentTarget event))) diff --git a/frontend/src/app/util/text_editor.cljs b/frontend/src/app/util/text_editor.cljs index 28da8d72cc..dac7739369 100644 --- a/frontend/src/app/util/text_editor.cljs +++ b/frontend/src/app/util/text_editor.cljs @@ -72,10 +72,10 @@ (defn get-editor-current-inline-styles [state] (if (impl/isCurrentEmpty state) - (let [block (impl/getCurrentBlock state)] - (get-editor-block-data block)) + (get-editor-current-block-data state) (-> (.getCurrentInlineStyle ^js state) - (txt/styles-to-attrs)))) + (txt/styles-to-attrs) + (dissoc :text-align :text-direction)))) (defn update-editor-current-block-data [state attrs] @@ -89,7 +89,8 @@ (impl/updateBlockData state block-key (clj->js attrs)) (let [attrs (-> (impl/getInlineStyle state block-key 0) - (txt/styles-to-attrs))] + (txt/styles-to-attrs) + (dissoc :text-align :text-direction))] (impl/updateBlockData state block-key (clj->js attrs))))) state (impl/applyInlineStyle state (txt/attrs-to-styles attrs)) diff --git a/frontend/translations/ar.po b/frontend/translations/ar.po index 960e7df7d5..bb9b7ba3e6 100644 --- a/frontend/translations/ar.po +++ b/frontend/translations/ar.po @@ -62,23 +62,23 @@ msgstr "سعيد برؤيتك مجددا!" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "تسجيل الدخول عبر Github" +msgstr "Github" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "تسجيل الدخول عبر Gitlab" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "تسجيل الدخول عبر جوجل" +msgstr "جوجل" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "تسجيل الدخول باستخدام LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "تسجيل الدخول باستخدام OpenID (SSO)" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -2055,4 +2055,4 @@ msgid "workspace.options.layer-options.blend-mode.difference" msgstr "اختلاف" msgid "workspace.viewport.click-to-close-path" -msgstr "انقر لإغلاق المسار" \ No newline at end of file +msgstr "انقر لإغلاق المسار" diff --git a/frontend/translations/ca.po b/frontend/translations/ca.po index e98aca7108..4496449639 100644 --- a/frontend/translations/ca.po +++ b/frontend/translations/ca.po @@ -65,23 +65,23 @@ msgstr "Ens agrada tornar a veure-vos!" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "Entra amb GitHub" +msgstr "GitHub" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "Entra amb Gitlab" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "Entra amb Google" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Entra amb LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "Entra amb OpenID (SSO)" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -4162,4 +4162,4 @@ msgid "workspace.updates.update" msgstr "Actualitza" msgid "workspace.viewport.click-to-close-path" -msgstr "Feu clic per a tancar el camí" \ No newline at end of file +msgstr "Feu clic per a tancar el camí" diff --git a/frontend/translations/da.po b/frontend/translations/da.po index 9f09c8dbd5..03988030a4 100644 --- a/frontend/translations/da.po +++ b/frontend/translations/da.po @@ -65,23 +65,23 @@ msgstr "Fedt at se dig igen!" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "Log på med Github" +msgstr "Github" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "Log på med Gitlab" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "Log på med Google" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Log på med LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "Log på med OpenID (SSO)" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -476,4 +476,4 @@ msgstr "Skrifttype Udbydere - %s - Penpot" #: src/app/main/ui/dashboard/fonts.cljs msgid "title.dashboard.fonts" -msgstr "Skrifttyper - %s - Penpot" \ No newline at end of file +msgstr "Skrifttyper - %s - Penpot" diff --git a/frontend/translations/de.po b/frontend/translations/de.po index 3a62b62ffc..b8f78418ba 100644 --- a/frontend/translations/de.po +++ b/frontend/translations/de.po @@ -66,23 +66,23 @@ msgstr "Schön, Sie wiederzusehen!" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "Anmelden mit GitHub" +msgstr "GitHub" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "Einloggen mit Gitlab" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "Anmelden mit Google" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Anmelden mit LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "Anmelden mit OpenID (SSO)" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -3764,4 +3764,4 @@ msgid "workspace.updates.update" msgstr "Aktualisieren" msgid "workspace.viewport.click-to-close-path" -msgstr "Klicken Sie, um den Pfad zu schließen" \ No newline at end of file +msgstr "Klicken Sie, um den Pfad zu schließen" diff --git a/frontend/translations/el.po b/frontend/translations/el.po index 1827939934..51a554bf72 100644 --- a/frontend/translations/el.po +++ b/frontend/translations/el.po @@ -60,15 +60,15 @@ msgstr "Χαίρομαι που σας ξαναδώ" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "Συνδεθείτε με το Github" +msgstr "Github" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "Συνδεθείτε με το Gitlab" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Συνδεθείτε με το LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -2303,4 +2303,4 @@ msgid "workspace.updates.update" msgstr "Ενημέρωση" msgid "workspace.viewport.click-to-close-path" -msgstr "Κάντε κλικ για να κλείσετε τη διαδρομή" \ No newline at end of file +msgstr "Κάντε κλικ για να κλείσετε τη διαδρομή" diff --git a/frontend/translations/en.po b/frontend/translations/en.po index d05dc54959..57f87e162a 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -75,11 +75,11 @@ msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Login with LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "OpenID Connect" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index ce5b3ecc0a..89dddd273f 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -78,11 +78,11 @@ msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Entrar con LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "OpenID Connect" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" diff --git a/frontend/translations/fa.po b/frontend/translations/fa.po index 2e1a92081b..eaa690f767 100644 --- a/frontend/translations/fa.po +++ b/frontend/translations/fa.po @@ -69,23 +69,23 @@ msgstr "خوشحالم که دوباره شما را می‌بینم!" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "ورود با گیتهاب" +msgstr "گیتهاب" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "ورود با گیتلب" +msgstr "گیتلب" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "ورود با گوگل" +msgstr "گوگل" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "ورود با LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "ورود با OpenID" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -2413,4 +2413,4 @@ msgid "workspace.updates.update" msgstr "به‌روزرسانی" msgid "workspace.viewport.click-to-close-path" -msgstr "برای بستن مسیر کلیک کنید" \ No newline at end of file +msgstr "برای بستن مسیر کلیک کنید" diff --git a/frontend/translations/fr.po b/frontend/translations/fr.po index e7666eb7c2..4333c5ffd3 100644 --- a/frontend/translations/fr.po +++ b/frontend/translations/fr.po @@ -66,23 +66,23 @@ msgstr "Ravi de vous revoir !" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "Se connecter via GitHub" +msgstr "GitHub" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "Se connecter via GitLab" +msgstr "GitLab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "Se connecter via Google" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Se connecter via LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "Se connecter via OpenID (SSO)" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -3207,4 +3207,4 @@ msgid "workspace.updates.update" msgstr "Actualiser" msgid "workspace.viewport.click-to-close-path" -msgstr "Cliquez pour fermer le chemin" \ No newline at end of file +msgstr "Cliquez pour fermer le chemin" diff --git a/frontend/translations/gl.po b/frontend/translations/gl.po index 6a5b03236a..e9c505bc8f 100644 --- a/frontend/translations/gl.po +++ b/frontend/translations/gl.po @@ -73,11 +73,11 @@ msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Entrar con LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "OpenID Connect" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -565,4 +565,4 @@ msgstr "S" #, permanent msgid "handoff.attributes.stroke.alignment.center" -msgstr "Centro" \ No newline at end of file +msgstr "Centro" diff --git a/frontend/translations/he.po b/frontend/translations/he.po index 49ddebf3ce..5bc9b86d4b 100644 --- a/frontend/translations/he.po +++ b/frontend/translations/he.po @@ -75,11 +75,11 @@ msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "כניסה עם LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "OpenID Connect" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -4213,4 +4213,4 @@ msgid "workspace.updates.update" msgstr "עדכון" msgid "workspace.viewport.click-to-close-path" -msgstr "לחיצה תסגור את הנתיב" \ No newline at end of file +msgstr "לחיצה תסגור את הנתיב" diff --git a/frontend/translations/id.po b/frontend/translations/id.po index 5071613760..b70e2ab453 100644 --- a/frontend/translations/id.po +++ b/frontend/translations/id.po @@ -69,23 +69,23 @@ msgstr "Senang bertemu denganmu lagi!" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "Masuk dengan Github" +msgstr "Github" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "Masuk dengan Gitlab" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "Masuk dengan Google" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Masuk dengan LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "Masuk dengan OpenID (SSO)" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -254,4 +254,4 @@ msgstr "* Dapat mencakup komponen, grafik, warna dan/atau tipografi." msgid "dashboard.export.explain" msgstr "" "Satu atau lebih file yang ingin anda ekspor, menggunakan pustaka bersama. " -"Apa yang akan anda lakukan dengan asetnya*?" \ No newline at end of file +"Apa yang akan anda lakukan dengan asetnya*?" diff --git a/frontend/translations/lt.po b/frontend/translations/lt.po index a768e4df2d..a3acf4cc38 100644 --- a/frontend/translations/lt.po +++ b/frontend/translations/lt.po @@ -79,11 +79,11 @@ msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Prisijungti su LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "OpenID prisijungimas" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -392,4 +392,4 @@ msgid "dashboard.import.progress.upload-data" msgstr "Įkeliami duomenys į serverį (%s/%s)" msgid "dashboard.import.progress.upload-media" -msgstr "Įkeliamas failas: %s" \ No newline at end of file +msgstr "Įkeliamas failas: %s" diff --git a/frontend/translations/ml.po b/frontend/translations/ml.po index 71beaaa818..c123de101b 100644 --- a/frontend/translations/ml.po +++ b/frontend/translations/ml.po @@ -69,23 +69,23 @@ msgstr "നിങ്ങളെ വീണ്ടും കാണാൻ കഴിഞ #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "ഗിറ്റ്ഹബ്ബ് ഉപയോഗിച്ച് ലോഗിൻ ചെയ്യുക" +msgstr "ഗിറ്റ്ഹബ്ബ്" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "ഗിറ്റ്ലാബ് ഉപയോഗിച്ച് ലോഗിൻ ചെയ്യുക" +msgstr "ഗിറ്റ്ലാബ്" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "ഗൂഗിൾ ഉപയോഗിച്ച് ലോഗിൻ ചെയ്യുക" +msgstr "ഗൂഗിൾ" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "LDAP ഉപയോഗിച്ച് ലോഗിൻ ചെയ്യുക" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "ഓപ്പൺഐഡി (SSO) ഉപയോഗിച്ച് ലോഗിൻ ചെയ്യുക" +msgstr "ഓപ്പൺഐഡി" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -263,4 +263,4 @@ msgid "dashboard.export-single" msgstr "പെൻപോട്ട് ഫയൽ എക്സ്പോർട്ട് ചെയ്യുക" msgid "dashboard.export.detail" -msgstr "* ഘടകങ്ങൾ, ഗ്രാഫിക്സ്, നിറങ്ങൾ അല്ലെങ്കിൽ മുദ്രണകലകൾ എന്നിവ ഉൾപ്പെടാം." \ No newline at end of file +msgstr "* ഘടകങ്ങൾ, ഗ്രാഫിക്സ്, നിറങ്ങൾ അല്ലെങ്കിൽ മുദ്രണകലകൾ എന്നിവ ഉൾപ്പെടാം." diff --git a/frontend/translations/pl.po b/frontend/translations/pl.po index d1956d0c54..6896712f06 100644 --- a/frontend/translations/pl.po +++ b/frontend/translations/pl.po @@ -78,11 +78,11 @@ msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Zaloguj się przez LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "OpenID Connect" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -4175,4 +4175,4 @@ msgid "workspace.updates.update" msgstr "Aktualizuj" msgid "workspace.viewport.click-to-close-path" -msgstr "Kliknij, aby zamknąć ścieżkę" \ No newline at end of file +msgstr "Kliknij, aby zamknąć ścieżkę" diff --git a/frontend/translations/pt_BR.po b/frontend/translations/pt_BR.po index 9625ec6304..e4bfbe812a 100644 --- a/frontend/translations/pt_BR.po +++ b/frontend/translations/pt_BR.po @@ -65,23 +65,23 @@ msgstr "Bom te ver de novo!" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "Entrar com o Github" +msgstr "Github" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "Entrar com o Gitlab" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "Entrar com o Google" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Entrar com LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "Entrar com OpenID (SSO)" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -2089,4 +2089,4 @@ msgid "workspace.updates.update" msgstr "Atualizar" msgid "workspace.viewport.click-to-close-path" -msgstr "Clique para fechar o caminho" \ No newline at end of file +msgstr "Clique para fechar o caminho" diff --git a/frontend/translations/ro.po b/frontend/translations/ro.po index 90cc810d17..1770235260 100644 --- a/frontend/translations/ro.po +++ b/frontend/translations/ro.po @@ -66,23 +66,23 @@ msgstr "Mă bucur să te văd din nou!" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "Conectează-te cu Github" +msgstr "Github" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "Conectează-te cu Gitlab" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "Conectează-te cu Google" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Conectează-te cu LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "Conectează-te cu OpenID (SSO)" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -2553,4 +2553,4 @@ msgid "workspace.updates.update" msgstr "Actualizează" msgid "workspace.viewport.click-to-close-path" -msgstr "Click pentru a închide calea" \ No newline at end of file +msgstr "Click pentru a închide calea" diff --git a/frontend/translations/ru.po b/frontend/translations/ru.po index ad5d5a55b8..54bf0a4421 100644 --- a/frontend/translations/ru.po +++ b/frontend/translations/ru.po @@ -63,23 +63,23 @@ msgstr "Рады видеть Вас снова!" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "Вход через Gitnub" +msgstr "Gitnub" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "Вход через Gitlab" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "Войти с Google" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "Вход через LDAP" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "Войти с OpenID (SSO)" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -2329,4 +2329,4 @@ msgid "workspace.updates.update" msgstr "" msgid "workspace.viewport.click-to-close-path" -msgstr "Нажмите для замыкания контура" \ No newline at end of file +msgstr "Нажмите для замыкания контура" diff --git a/frontend/translations/tr.po b/frontend/translations/tr.po index 6000e588fb..3f34d8bd69 100644 --- a/frontend/translations/tr.po +++ b/frontend/translations/tr.po @@ -78,11 +78,11 @@ msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "LDAP ile oturum aç" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "OpenID ile Bağlan" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -4264,4 +4264,4 @@ msgid "workspace.updates.update" msgstr "Güncelle" msgid "workspace.viewport.click-to-close-path" -msgstr "Yolu kapatmak için tıklayın" \ No newline at end of file +msgstr "Yolu kapatmak için tıklayın" diff --git a/frontend/translations/zh_CN.po b/frontend/translations/zh_CN.po index ceb612e102..6e56d1139e 100644 --- a/frontend/translations/zh_CN.po +++ b/frontend/translations/zh_CN.po @@ -61,23 +61,23 @@ msgstr "很高兴又见到你!" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "使用GitHub登录" +msgstr "GitHub" #: src/app/main/ui/auth/register.cljs, src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "使用Gitlab登录" +msgstr "Gitlab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "使用Google登录" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "使用LDAP登录" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "使用OpenID登录" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -3527,4 +3527,4 @@ msgid "workspace.updates.update" msgstr "更新" msgid "workspace.viewport.click-to-close-path" -msgstr "单击以闭合路径" \ No newline at end of file +msgstr "单击以闭合路径" diff --git a/frontend/translations/zh_Hant.po b/frontend/translations/zh_Hant.po index 2dd554d420..f07e439ff4 100644 --- a/frontend/translations/zh_Hant.po +++ b/frontend/translations/zh_Hant.po @@ -61,23 +61,23 @@ msgstr "很高興再次見到你!" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-github-submit" -msgstr "透過 GitHub 登入" +msgstr "GitHub" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-gitlab-submit" -msgstr "透過 GitLab 登入" +msgstr "GitLab" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-google-submit" -msgstr "透過 Google 登入" +msgstr "Google" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-ldap-submit" -msgstr "透過 LDAP 登入" +msgstr "LDAP" #: src/app/main/ui/auth/login.cljs msgid "auth.login-with-oidc-submit" -msgstr "使用 OpenID (SSO) 登入" +msgstr "OpenID" #: src/app/main/ui/auth/recovery.cljs msgid "auth.new-password" @@ -1087,4 +1087,4 @@ msgstr "歷史" #: src/app/main/data/workspace/libraries.cljs msgid "workspace.updates.update" -msgstr "更新" \ No newline at end of file +msgstr "更新"