0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-12 15:51:37 -05:00

Merge pull request #3303 from penpot/azazeln28-cursors

 Add CSS cursor classes
This commit is contained in:
Eva Marco 2023-06-15 08:10:44 +02:00 committed by GitHub
commit 1555d4abaf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 136 additions and 50 deletions

View file

@ -18,6 +18,7 @@
[app.main.ui :as ui]
[app.main.ui.alert]
[app.main.ui.confirm]
[app.main.ui.cursors :as cursors]
[app.main.ui.delete-shared]
[app.main.ui.modal :refer [modal]]
[app.main.ui.routes :as rt]
@ -44,6 +45,7 @@
(defn init-ui
[]
(cursors/init-styles)
(mf/mount (mf/element ui/app) (dom/get-element "app"))
(mf/mount (mf/element modal) (dom/get-element "modal")))

View file

@ -7,6 +7,8 @@
(ns app.main.ui.cursors
(:require-macros [app.main.ui.cursors :refer [cursor-ref cursor-fn]])
(:require
[app.common.data.macros :as dm]
[app.util.css :as css]
[app.util.timers :as ts]
[cuerdas.core :as str]
[rumext.v2 :as mf]))
@ -51,6 +53,63 @@
(def resize-ew-2 (cursor-fn :resize-h-2 0))
(def resize-ns-2 (cursor-fn :resize-h-2 90))
(defn get-static
[name]
(dm/str "cursor-" name))
(defn get-dynamic
[name rotation]
(dm/str "cursor-" name "-" (.floor js/Math rotation)))
(defn init-static-cursor-style
[style name value]
(.add style (dm/str ".cursor-" name) (js-obj "cursor" (dm/str value " !important"))))
(defn init-dynamic-cursor-style
[style name fn]
(let [rotations (seq (range 0 360 1))]
(doseq [rotation rotations]
(.add style (dm/str ".cursor-" name "-" rotation) (js-obj "cursor" (dm/str (fn rotation) " !important"))))))
(defn init-styles
[]
(let [style (css/create-style)]
;; static
(init-static-cursor-style style "comments" comments)
(init-static-cursor-style style "create-artboard" create-artboard)
(init-static-cursor-style style "create-ellipse" create-ellipse)
(init-static-cursor-style style "create-polygon" create-polygon)
(init-static-cursor-style style "create-rectangle" create-rectangle)
(init-static-cursor-style style "create-shape" create-shape)
(init-static-cursor-style style "duplicate" duplicate)
(init-static-cursor-style style "hand" hand)
(init-static-cursor-style style "move-pointer" move-pointer)
(init-static-cursor-style style "pen" pen)
(init-static-cursor-style style "pen-node" pen-node)
(init-static-cursor-style style "pencil" pencil)
(init-static-cursor-style style "picker" picker)
(init-static-cursor-style style "pointer-inner" pointer-inner)
(init-static-cursor-style style "pointer-move" pointer-move)
(init-static-cursor-style style "pointer-node" pointer-node)
(init-static-cursor-style style "resize-alt" resize-alt)
(init-static-cursor-style style "zoom" zoom)
(init-static-cursor-style style "zoom-in" zoom-in)
(init-static-cursor-style style "zoom-out" zoom-out)
;; dynamic
(init-dynamic-cursor-style style "resize-ew" resize-ew)
(init-dynamic-cursor-style style "resize-nesw" resize-nesw)
(init-dynamic-cursor-style style "resize-ns" resize-ns)
(init-dynamic-cursor-style style "resize-nwse" resize-nwse)
(init-dynamic-cursor-style style "rotate" rotate)
(init-dynamic-cursor-style style "text" text)
(init-dynamic-cursor-style style "scale-ew" scale-ew)
(init-dynamic-cursor-style style "scale-nesw" scale-nesw)
(init-dynamic-cursor-style style "scale-ns" scale-ns)
(init-dynamic-cursor-style style "scale-nwse" scale-nwse)
(init-dynamic-cursor-style style "resize-ew-2" resize-ew-2)
(init-dynamic-cursor-style style "resize-ns-2" resize-ns-2)))
(mf/defc debug-preview
{::mf/wrap-props false}
[]

View file

@ -358,9 +358,9 @@
:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move
:class (when (or hover? selected?)
(if (= (:resize-axis rect-data) :x) (cur/get-dynamic "resize-ew" 0) (cur/get-dynamic "resize-ew" 90)))
:style {:fill (if (or hover? selected?) distance-color "none")
:cursor (when (or hover? selected?)
(if (= (:resize-axis rect-data) :x) (cur/resize-ew 0) (cur/resize-ew 90)))
:opacity (if selected? 0.5 0.25)}}]))
(mf/defc padding-rects [{:keys [frame zoom alt? shift?]}]
@ -661,9 +661,9 @@
:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move
:class (when (or hover? selected?)
(if (= (:resize-axis rect-data) :x) (cur/get-dynamic "resize-ew" 0) (cur/get-dynamic "resize-ew" 90)))
:style {:fill (if (or hover? selected?) distance-color "none")
:cursor (when (or hover? selected?)
(if (= (:resize-axis rect-data) :x) (cur/resize-ew 0) (cur/resize-ew 90)))
:opacity (if selected? 0.5 0.25)}}]))
(mf/defc gap-rects [{:keys [frame zoom]}]

View file

@ -99,10 +99,9 @@
:on-pointer-enter on-enter
:on-pointer-leave on-leave
:pointer-events (when-not preview? "visible")
:style {:cursor (cond
(= edit-mode :draw) cur/pen-node
(= edit-mode :move) cur/pointer-node)
:stroke-width 0
:class (cond (= edit-mode :draw) (cur/get-static "pen-node")
(= edit-mode :move) (cur/get-static "pointer-node"))
:style {:stroke-width 0
:fill "none"}}]]))
(mf/defc path-handler [{:keys [index prefix point handler zoom selected? hover? edit-mode snap-angle?]}]
@ -160,8 +159,8 @@
:on-pointer-down on-pointer-down
:on-pointer-enter on-enter
:on-pointer-leave on-leave
:style {:cursor (when (= edit-mode :move) cur/pointer-move)
:fill "none"
:class (when (= edit-mode :move) (cur/get-static "pointer-move"))
:style {:fill "none"
:stroke-width 0}}]])))
(mf/defc path-preview [{:keys [zoom command from]}]

View file

@ -222,8 +222,7 @@
[:div.text-editor
{:ref self-ref
:style {:cursor (cur/text (:rotation shape))
:width (:width shape)
:style {:width (:width shape)
:height (:height shape)
;; We hide the editor when is blurred because otherwise the selection won't let us see
;; the underlying text. Use opacity because display or visibility won't allow to recover
@ -231,6 +230,7 @@
:opacity (when @blurred 0)}
:on-pointer-down on-pointer-down
:class (dom/classnames
(cur/get-dynamic "text" (:rotation shape)) true
:align-top (= (:vertical-align content "top") "top")
:align-center (= (:vertical-align content) "center")
:align-bottom (= (:vertical-align content) "bottom"))}

View file

@ -330,8 +330,8 @@
:key (str "viewport" page-id)
:view-box (utils/format-viewbox vbox)
:ref on-viewport-ref
:class (when drawing-tool "drawing")
:style {:cursor @cursor :touch-action "none"}
:class (dm/str @cursor (when drawing-tool "drawing"))
:style {:touch-action "none"}
:fill "none"
:on-click on-click

View file

@ -15,7 +15,6 @@
[app.main.data.workspace.grid-layout.editor :as dwge]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.cursors :as cur]
[app.util.dom :as dom]
[cuerdas.core :as str]
[rumext.v2 :as mf]))
@ -230,15 +229,15 @@
[:rect.resize-handler
{:x x
:y y
:class (if (= type :column)
"resize-ew-0"
"resize-ns-0")
:height height
:width width
:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move
:style {:fill "transparent"
:cursor (if (= type :column)
(cur/resize-ew 0)
(cur/resize-ns 0))}}]))
:on-pointer-move on-pointer-move
:style {:fill "transparent"}}]))
(mf/defc editor
{::mf/wrap-props false}

View file

@ -302,9 +302,9 @@
:y y
:width width
:height height
:class (if (= axis :x) (cur/get-dynamic "resize-ew" 0) (cur/get-dynamic "resize-ns" 0))
:style {:fill "none"
:pointer-events (if frame-guide-outside? "none" "fill")
:cursor (if (= axis :x) (cur/resize-ew 0) (cur/resize-ns 0))}
:pointer-events (if frame-guide-outside? "none" "fill")}
:on-pointer-enter on-pointer-enter
:on-pointer-leave on-pointer-leave
:on-pointer-down on-pointer-down
@ -417,9 +417,9 @@
:on-pointer-up on-pointer-up
:on-lost-pointer-capture on-lost-pointer-capture
:on-pointer-move on-pointer-move
:class (if (= axis :x) (cur/get-dynamic "resize-ew" 0) (cur/get-dynamic "resize-ns" 0))
:style {:fill "none"
:pointer-events "fill"
:cursor (if (= axis :x) (cur/resize-ew 0) (cur/resize-ns 0))}}]))
:pointer-events "fill"}}]))
(when (:new-position @state)
[:& guide {:guide {:axis axis

View file

@ -206,7 +206,7 @@
[:div.pixel-overlay
{:id "pixel-overlay"
:tab-index 0
:style {:cursor cur/picker}
:class (cur/get-static "picker")
:on-pointer-down handle-pointer-down-picker
:on-pointer-up handle-pointer-up-picker
:on-pointer-move handle-pointer-move-picker}

View file

@ -165,9 +165,9 @@
:top-right 90
:bottom-right 180
:bottom-left 270)]
[:rect {:style {:cursor (cur/rotate (+ rotation angle))}
:x x
[:rect {:x x
:y y
:class (cur/get-dynamic "rotate" (+ rotation angle))
:width size
:height size
:fill (if (debug? :handlers) "blue" "none")
@ -180,8 +180,8 @@
(let [layout (mf/deref refs/workspace-layout)
scale-text (:scale-text layout)
cursor (if (#{:top-left :bottom-right} position)
(if scale-text (cur/scale-nesw rotation) (cur/resize-nesw rotation))
(if scale-text (cur/scale-nwse rotation) (cur/resize-nwse rotation)))
(if scale-text (cur/get-dynamic "scale-nesw" rotation) (cur/get-dynamic "resize-nesw" rotation))
(if scale-text (cur/get-dynamic "scale-nwse" rotation) (cur/get-dynamic "resize-nwse" rotation)))
{cx' :x cy' :y} (gpt/transform (gpt/point cx cy) transform)]
[:g.resize-handler
@ -203,21 +203,21 @@
{cx' :x cy' :y} (gpt/transform (gpt/point cx cy) transform)]
[:rect {:x cx'
:y cy'
:class cursor
:width resize-point-circle-radius
:height resize-point-circle-radius
:transform (when rotation (dm/fmt "rotate(%, %, %)" rotation cx' cy'))
:style {:fill (if (debug? :handlers) "red" "none")
:stroke-width 0
:cursor cursor}
:stroke-width 0}
:on-pointer-down #(on-resize {:x cx' :y cy'} %)}])
[:circle {:on-pointer-down #(on-resize {:x cx' :y cy'} %)
:r (/ resize-point-circle-radius zoom)
:cx cx'
:cy cy'
:class cursor
:style {:fill (if (debug? :handlers) "red" "none")
:stroke-width 0
:cursor cursor}}])]))
:stroke-width 0}}])]))
(mf/defc resize-side-handler
"The side handler is always rendered horizontally and then rotated"
@ -246,13 +246,13 @@
:y target-y
:width length
:height height
:class (if (#{:left :right} position)
(if scale-text (cur/get-dynamic "scale-ew" rotation) (cur/get-dynamic "resize-ew" rotation))
(if scale-text (cur/get-dynamic "scale-ns" rotation) (cur/get-dynamic "resize-ns" rotation)))
:transform transform-str
:on-pointer-down #(on-resize res-point %)
:style {:fill (if (debug? :handlers) "yellow" "none")
:stroke-width 0
:cursor (if (#{:left :right} position)
(if scale-text (cur/scale-ew rotation) (cur/resize-ew rotation))
(if scale-text (cur/scale-ns rotation) (cur/resize-ns rotation))) }}]]))
:stroke-width 0}}]]))
(defn minimum-selrect [{:keys [x y width height] :as selrect}]
(let [final-width (max width min-selrect-side)

View file

@ -20,19 +20,19 @@
(defn get-cursor [cursor]
(case cursor
:hand cur/hand
:comments cur/comments
:create-artboard cur/create-artboard
:create-rectangle cur/create-rectangle
:create-ellipse cur/create-ellipse
:pen cur/pen
:pencil cur/pencil
:create-shape cur/create-shape
:duplicate cur/duplicate
:zoom cur/zoom
:zoom-in cur/zoom-in
:zoom-out cur/zoom-out
cur/pointer-inner))
:hand (cur/get-static "hand")
:comments (cur/get-static "comments")
:create-artboard (cur/get-static "create-artboard")
:create-rectangle (cur/get-static "create-rectangle")
:create-ellipse (cur/get-static "create-ellipse")
:pen (cur/get-static "pen")
:pencil (cur/get-static "pencil")
:create-shape (cur/get-static "create-shape")
:duplicate (cur/get-static "duplicate")
:zoom (cur/get-static "zoom")
:zoom-in (cur/get-static "zoom-in")
:zoom-out (cur/get-static "zoom-out")
(cur/get-static "pointer-inner")))
;; Ensure that the label has always the same font
;; size, regardless of zoom

View file

@ -0,0 +1,27 @@
(ns app.util.css
(:require
[app.common.data.macros :as dm]
[app.util.dom :as dom]))
(defn declarations->str
"Converts an object of CSS declarations to a string"
[declarations]
(let [entries (.from js/Array (.entries js/Object declarations))]
(.reduce entries (fn [acc [k v]]
(dm/str acc k ": " v ";")) "")))
(defn add-rule
"Adds a CSS rule to a CSS Style Sheet"
[styleSheet selector declarations]
(.insertRule styleSheet (dm/str selector " {" (declarations->str declarations) "}")))
;; FIXME: Maybe we should rename this to `create-dynamic-style`?
(defn create-style
"Creates a new CSS Style Sheet and returns an object that allows adding rules to it"
[]
(let [style (dom/create-element "style")]
(dom/set-attribute! style "type" "text/css")
(dom/append-child! js/document.head style)
(js-obj "add" (partial add-rule (.-sheet style)))))