diff --git a/frontend/deps.edn b/frontend/deps.edn index 55ea41dfbc..eb597d0ebb 100644 --- a/frontend/deps.edn +++ b/frontend/deps.edn @@ -33,6 +33,9 @@ thheller/shadow-cljs {:mvn/version "2.8.110"} + lambdaisland/uri {:mvn/version "1.3.45" + :exclusions [org.clojure/data.json]} + ;; i18n parsing carocad/parcera {:mvn/version "0.11.0"} org.antlr/antlr4-runtime {:mvn/version "4.7"}}} diff --git a/frontend/resources/styles/main/partials/debug-icons-preview.scss b/frontend/resources/styles/main/partials/debug-icons-preview.scss index ed8e7054d6..5e56fc0a4e 100644 --- a/frontend/resources/styles/main/partials/debug-icons-preview.scss +++ b/frontend/resources/styles/main/partials/debug-icons-preview.scss @@ -1,9 +1,14 @@ +.debug-preview { + max-height: 100vh; + display: flex; + flex-direction: column; + overflow: scroll; +} .debug-icons-preview { display: flex; flex-wrap: wrap; - overflow: scroll; - .icon-item { + .icon-item, .cursor-item { padding: 10px; display: flex; flex-direction: column; @@ -17,4 +22,7 @@ height: 100%; } } + .cursor-item { + height: auto; + } } diff --git a/frontend/src/uxbox/main/ui.cljs b/frontend/src/uxbox/main/ui.cljs index 84f30e87e7..3c9b9b5531 100644 --- a/frontend/src/uxbox/main/ui.cljs +++ b/frontend/src/uxbox/main/ui.cljs @@ -23,6 +23,7 @@ [uxbox.main.ui.auth :refer [auth verify-token]] [uxbox.main.ui.dashboard :refer [dashboard]] [uxbox.main.ui.icons :as i] + [uxbox.main.ui.cursors :as c] [uxbox.main.ui.messages :as msgs] [uxbox.main.ui.settings :as settings] [uxbox.main.ui.static :refer [not-found-page not-authorized-page]] @@ -106,7 +107,12 @@ :debug-icons-preview (when *assert* - [:& i/debug-icons-preview]) + [:div.debug-preview + [:h1 "Cursors"] + [:& c/debug-preview] + [:h1 "Icons"] + [:& i/debug-icons-preview] + ]) (:dashboard-search :dashboard-team diff --git a/frontend/src/uxbox/main/ui/cursors.clj b/frontend/src/uxbox/main/ui/cursors.clj new file mode 100644 index 0000000000..8ef5e672ee --- /dev/null +++ b/frontend/src/uxbox/main/ui/cursors.clj @@ -0,0 +1,75 @@ +;; 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/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns uxbox.main.ui.cursors + (:import java.net.URLEncoder) + (:require [rumext.alpha] + [clojure.java.io :as io] + [lambdaisland.uri.normalize :as uri] + [cuerdas.core :as str])) + +(def cursor-folder "images/cursors") + +(def default-hotspot-x 12) +(def default-hotspot-y 12) +(def default-rotation 0) + +(defn parse-svg [svg-data] + (-> svg-data + ;; Remove the header + (str/replace #"(?i)<\?xml[^\?]*\?>", "") + + ;; Remove comments + (str/replace #"<\!\-\-(.*?(?=\-\->))\-\->" "") + + ;; Remofe end of line + (str/replace #"\r?\n|\r" " ") + + ;; Replace double quotes for single + (str/replace #"\"" "'") + + ;; Remove the svg root tag + (str/replace #"(?i)" "") + + ;; And the closing tag + (str/replace #"(?i)<\/svg>" "") + + ;; Remove some defs that can be redundant + (str/replace #"" "") + + ;; Unifies the spaces into single space + (str/replace #"\s+" " ") + + ;; Remove spaces at the beginning of the svg + (str/replace #"^\s+" "") + + ;; Remove spaces at the end + (str/replace #"\s+$" ""))) + +(defn encode-svg-cursor + [id rotation x y] + (let [svg-path (str cursor-folder "/" (name id) ".svg") + data (-> svg-path io/resource slurp parse-svg uri/percent-encode) + transform (if rotation (str " transform='rotate(" rotation ")'") "") + data (clojure.pprint/cl-format + nil + "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='24px' height='24px'~A%3E~A%3C/svg%3E\") ~A ~A, auto" + transform data x y)] + data)) + +(defmacro cursor-ref + ([id] (encode-svg-cursor id default-rotation default-hotspot-x default-hotspot-y)) + ([id rotation] (encode-svg-cursor id rotation default-hotspot-x default-hotspot-y)) + ([id rotation x y] (encode-svg-cursor id rotation x y))) + +(defmacro cursor-fn + [id initial] + (let [cursor (encode-svg-cursor id "{{rotation}}" default-hotspot-x default-hotspot-y)] + `(fn [rot#] + (str/replace ~cursor "{{rotation}}" (+ ~initial rot#))))) diff --git a/frontend/src/uxbox/main/ui/cursors.cljs b/frontend/src/uxbox/main/ui/cursors.cljs new file mode 100644 index 0000000000..4fd68072fe --- /dev/null +++ b/frontend/src/uxbox/main/ui/cursors.cljs @@ -0,0 +1,61 @@ +;; 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/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns uxbox.main.ui.cursors + (:require-macros [uxbox.main.ui.cursors :refer [cursor-ref + cursor-fn]]) + (:require [rumext.alpha :as mf] + [cuerdas.core :as str] + [uxbox.util.timers :as ts])) + +(def create-artboard (cursor-ref :create-artboard)) +(def create-ellipse (cursor-ref :create-ellipse)) +(def create-polygon (cursor-ref :create-polygon)) +(def create-rectangle (cursor-ref :create-reclangle)) +(def create-shape (cursor-ref :create-shape)) +(def duplicate (cursor-ref :duplicate 0 0 0)) +(def hand (cursor-ref :hand)) +(def move-pointer (cursor-ref :move-pointer)) +(def pencil (cursor-ref :pencil 0 0 24)) +(def pen (cursor-ref :pen 0 0 0)) +(def pointer-inner (cursor-ref :pointer-inner 0 0 0)) +(def resize-alt (cursor-ref :resize-alt)) + +#_(def resize-nesw (cursor-fn :resize-diagonal 90)) +#_(def resize-nwse (cursor-fn :resize-diagonal 0)) +(def resize-nesw (cursor-fn :resize-h 45)) +(def resize-nwse (cursor-fn :resize-h 135)) + +(def resize-ew (cursor-fn :resize-h 0)) +(def resize-ns (cursor-fn :resize-h 90)) + +(def rotate (cursor-fn :rotate 90)) +(def text (cursor-ref :text)) + +(mf/defc debug-preview + {::mf/wrap-props false} + [props] + (let [rotation (mf/use-state 0)] + (mf/use-effect (fn [] (ts/interval 100 #(reset! rotation inc)))) + + [:section.debug-icons-preview + (for [[key val] (sort-by first (ns-publics 'uxbox.main.ui.cursors))] + (when (not= key 'debug-icons-preview) + (let [value (deref val) + value (if (fn? value) (value @rotation) value)] + [:div.cursor-item {:key key} + [:div {:style {:width "100px" + :height "100px" + :background-image (-> value (str/replace #"(url\(.*\)).*" "$1")) + :background-size "cover" + :cursor value}}] + + [:span {:style {:white-space "nowrap" + :margin-right "1rem"}} (pr-str key)]])))])) +