mirror of
https://github.com/penpot/penpot.git
synced 2025-02-10 17:18:21 -05:00
commit
14359d9acf
15 changed files with 110 additions and 99 deletions
|
@ -25,9 +25,6 @@
|
||||||
|
|
||||||
;; --- Constants
|
;; --- Constants
|
||||||
|
|
||||||
(def email-rx
|
|
||||||
#"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
|
|
||||||
|
|
||||||
(def uuid-rx
|
(def uuid-rx
|
||||||
#"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
|
#"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
|
||||||
|
|
||||||
|
@ -86,12 +83,6 @@
|
||||||
v
|
v
|
||||||
::s/invalid))
|
::s/invalid))
|
||||||
|
|
||||||
(defn- email-conformer
|
|
||||||
[v]
|
|
||||||
(if (and (string? v) (re-matches email-rx v))
|
|
||||||
v
|
|
||||||
::s/invalid))
|
|
||||||
|
|
||||||
(defn keyword-conformer
|
(defn keyword-conformer
|
||||||
[v]
|
[v]
|
||||||
(cond
|
(cond
|
||||||
|
@ -109,7 +100,6 @@
|
||||||
(s/def ::keyword (s/conformer keyword-conformer name))
|
(s/def ::keyword (s/conformer keyword-conformer name))
|
||||||
(s/def ::inst inst?)
|
(s/def ::inst inst?)
|
||||||
(s/def ::string string?)
|
(s/def ::string string?)
|
||||||
(s/def ::email (s/conformer email-conformer str))
|
|
||||||
(s/def ::color (s/conformer color-conformer str))
|
(s/def ::color (s/conformer color-conformer str))
|
||||||
(s/def ::uuid (s/conformer uuid-conformer str))
|
(s/def ::uuid (s/conformer uuid-conformer str))
|
||||||
(s/def ::boolean (s/conformer boolean-conformer boolean-unformer))
|
(s/def ::boolean (s/conformer boolean-conformer boolean-unformer))
|
||||||
|
@ -134,6 +124,18 @@
|
||||||
(>= % min-safe-int)
|
(>= % min-safe-int)
|
||||||
(<= % max-safe-int)))
|
(<= % max-safe-int)))
|
||||||
|
|
||||||
|
|
||||||
|
;; --- SPEC: email
|
||||||
|
|
||||||
|
(let [re #"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+"
|
||||||
|
cfn (fn [v]
|
||||||
|
(if (string? v)
|
||||||
|
(if-let [matches (re-seq re v)]
|
||||||
|
(first matches)
|
||||||
|
(do ::s/invalid))
|
||||||
|
::s/invalid))]
|
||||||
|
(s/def ::email (s/conformer cfn str)))
|
||||||
|
|
||||||
;; --- Macros
|
;; --- Macros
|
||||||
|
|
||||||
(defn spec-assert*
|
(defn spec-assert*
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
[app.config :as cfg]
|
[app.config :as cfg]
|
||||||
[app.main.data.auth :as da]
|
[app.main.data.auth :as da]
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
[app.main.data.users :as udu]
|
[app.main.data.users :as du]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui :as ui]
|
[app.main.ui :as ui]
|
||||||
|
@ -79,20 +79,19 @@
|
||||||
|
|
||||||
(defn init-ui
|
(defn init-ui
|
||||||
[]
|
[]
|
||||||
(st/emit! (rt/initialize-router ui/routes)
|
|
||||||
(rt/initialize-history on-navigate))
|
|
||||||
|
|
||||||
(st/emit! (udu/fetch-profile)
|
|
||||||
(udu/fetch-user-teams))
|
|
||||||
(mf/mount (mf/element ui/app) (dom/get-element "app"))
|
(mf/mount (mf/element ui/app) (dom/get-element "app"))
|
||||||
(mf/mount (mf/element modal) (dom/get-element "modal")))
|
(mf/mount (mf/element modal) (dom/get-element "modal")))
|
||||||
|
|
||||||
(defn ^:export init
|
(defn ^:export init
|
||||||
[]
|
[]
|
||||||
(i18n/init! cfg/translations)
|
(i18n/init! cfg/translations)
|
||||||
(theme/init! cfg/themes)
|
(theme/init! cfg/themes)
|
||||||
(st/init)
|
(st/init)
|
||||||
(init-ui))
|
(init-ui)
|
||||||
|
|
||||||
|
(st/emit! (rt/initialize-router ui/routes)
|
||||||
|
(rt/initialize-history on-navigate)
|
||||||
|
(du/fetch-profile-and-teams)))
|
||||||
|
|
||||||
(defn reinit
|
(defn reinit
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -47,10 +47,10 @@
|
||||||
(watch [this state stream]
|
(watch [this state stream]
|
||||||
(let [team-id (current-team-id profile)
|
(let [team-id (current-team-id profile)
|
||||||
props (:props profile)]
|
props (:props profile)]
|
||||||
(rx/merge
|
(rx/concat
|
||||||
(rx/of (du/profile-fetched profile)
|
(rx/of (du/profile-fetched profile))
|
||||||
(rt/nav' :dashboard-projects {:team-id team-id}))
|
(rx/of (du/fetch-teams))
|
||||||
|
(rx/of (rt/nav' :dashboard-projects {:team-id team-id}))
|
||||||
(when-not (:onboarding-viewed props)
|
(when-not (:onboarding-viewed props)
|
||||||
(->> (rx/of (modal/show {:type :onboarding}))
|
(->> (rx/of (modal/show {:type :onboarding}))
|
||||||
(rx/delay 1000))))))))
|
(rx/delay 1000))))))))
|
||||||
|
|
|
@ -65,8 +65,6 @@
|
||||||
;; Data Fetching
|
;; Data Fetching
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;; --- Fetch Team
|
|
||||||
|
|
||||||
(defn fetch-team
|
(defn fetch-team
|
||||||
[{:keys [id] :as params}]
|
[{:keys [id] :as params}]
|
||||||
(letfn [(fetched [team state]
|
(letfn [(fetched [team state]
|
||||||
|
@ -117,7 +115,7 @@
|
||||||
(defn fetch-bundle
|
(defn fetch-bundle
|
||||||
[{:keys [id] :as params}]
|
[{:keys [id] :as params}]
|
||||||
(us/assert ::us/uuid id)
|
(us/assert ::us/uuid id)
|
||||||
(ptk/reify ::fetch-team
|
(ptk/reify ::fetch-bundle
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [profile (:profile state)]
|
(let [profile (:profile state)]
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
[app.config :as cf]
|
[app.config :as cf]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.media :as di]
|
[app.main.data.media :as di]
|
||||||
[app.main.data.messages :as dm]
|
[app.main.data.messages :as dm]
|
||||||
[app.main.repo :as rp]
|
[app.main.repo :as rp]
|
||||||
|
@ -47,19 +48,29 @@
|
||||||
::lang
|
::lang
|
||||||
::theme]))
|
::theme]))
|
||||||
|
|
||||||
;; --- Profile Fetched
|
(defn fetch-teams
|
||||||
|
[]
|
||||||
|
(letfn [(on-fetched [state data]
|
||||||
|
(let [teams (d/index-by :id data)]
|
||||||
|
(assoc state :teams teams)))]
|
||||||
|
(ptk/reify ::fetch-teams
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state s]
|
||||||
|
(->> (rp/query! :teams)
|
||||||
|
(rx/map (fn [data] #(on-fetched % data))))))))
|
||||||
|
|
||||||
(defn profile-fetched
|
(defn profile-fetched
|
||||||
[{:keys [fullname id] :as data}]
|
[{:keys [fullname id] :as data}]
|
||||||
(us/verify ::profile data)
|
(us/verify ::profile data)
|
||||||
(ptk/reify ::profile-fetched
|
(ptk/reify ::profile-fetched
|
||||||
|
IDeref
|
||||||
|
(-deref [_] data)
|
||||||
|
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(-> state
|
(-> state
|
||||||
(assoc :profile-id id)
|
(assoc :profile-id id)
|
||||||
(assoc :profile data)
|
(assoc :profile data)))
|
||||||
;; Safeguard if the profile is loaded after teams
|
|
||||||
(assoc-in [:profile :teams] (get-in state [:profile :teams]))))
|
|
||||||
|
|
||||||
ptk/EffectEvent
|
ptk/EffectEvent
|
||||||
(effect [_ state stream]
|
(effect [_ state stream]
|
||||||
|
@ -73,12 +84,31 @@
|
||||||
|
|
||||||
(defn fetch-profile
|
(defn fetch-profile
|
||||||
[]
|
[]
|
||||||
(reify
|
(ptk/reify ::fetch-profile
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state s]
|
(watch [_ state stream]
|
||||||
(->> (rp/query! :profile)
|
(->> (rp/query! :profile)
|
||||||
(rx/map profile-fetched)))))
|
(rx/map profile-fetched)))))
|
||||||
|
|
||||||
|
(defn fetch-profile-and-teams
|
||||||
|
"Event used mainly on application bootstrap; it fetches the profile
|
||||||
|
and if and only if the fetched profile corresponds to an
|
||||||
|
authenticated user; proceed to fetch teams."
|
||||||
|
[]
|
||||||
|
(ptk/reify ::fetch-profile-and-teams
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(rx/merge
|
||||||
|
(rx/of (fetch-profile))
|
||||||
|
(->> stream
|
||||||
|
(rx/filter (ptk/type? ::profile-fetched))
|
||||||
|
(rx/take 1)
|
||||||
|
(rx/map deref)
|
||||||
|
(rx/mapcat (fn [profile]
|
||||||
|
(if (= uuid/zero (:id profile))
|
||||||
|
(rx/empty)
|
||||||
|
(rx/of (fetch-teams))))))))))
|
||||||
|
|
||||||
;; --- Update Profile
|
;; --- Update Profile
|
||||||
|
|
||||||
(defn update-profile
|
(defn update-profile
|
||||||
|
@ -204,24 +234,3 @@
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(->> (rp/query :team-users {:team-id team-id})
|
(->> (rp/query :team-users {:team-id team-id})
|
||||||
(rx/map #(partial fetched %)))))))
|
(rx/map #(partial fetched %)))))))
|
||||||
|
|
||||||
(defn user-teams-fetched [data]
|
|
||||||
(ptk/reify ::user-teams-fetched
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(let [teams (->> data
|
|
||||||
(group-by :id)
|
|
||||||
(d/mapm #(first %2)))]
|
|
||||||
(assoc-in state [:profile :teams] teams)))))
|
|
||||||
|
|
||||||
(defn fetch-user-teams []
|
|
||||||
(ptk/reify ::fetch-user-teams
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state s]
|
|
||||||
(->> (rp/query! :teams)
|
|
||||||
(rx/map user-teams-fetched)
|
|
||||||
(rx/catch (fn [error]
|
|
||||||
(if (= (:type error) :not-found)
|
|
||||||
(rx/of (rt/nav :auth-login))
|
|
||||||
(rx/empty))))))))
|
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,9 @@
|
||||||
(def profile
|
(def profile
|
||||||
(l/derived :profile st/state))
|
(l/derived :profile st/state))
|
||||||
|
|
||||||
|
(def teams
|
||||||
|
(l/derived :teams st/state))
|
||||||
|
|
||||||
(def exception
|
(def exception
|
||||||
(l/derived :exception st/state))
|
(l/derived :exception st/state))
|
||||||
|
|
||||||
|
|
|
@ -205,7 +205,7 @@
|
||||||
(mf/defc teams-selector-dropdown
|
(mf/defc teams-selector-dropdown
|
||||||
[{:keys [team profile locale] :as props}]
|
[{:keys [team profile locale] :as props}]
|
||||||
(let [show-dropdown? (mf/use-state false)
|
(let [show-dropdown? (mf/use-state false)
|
||||||
teams (mf/use-state [])
|
teams (mf/deref refs/teams)
|
||||||
|
|
||||||
on-create-clicked
|
on-create-clicked
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
|
@ -217,12 +217,6 @@
|
||||||
(da/set-current-team! team-id)
|
(da/set-current-team! team-id)
|
||||||
(st/emit! (rt/nav :dashboard-projects {:team-id team-id}))))]
|
(st/emit! (rt/nav :dashboard-projects {:team-id team-id}))))]
|
||||||
|
|
||||||
(mf/use-layout-effect
|
|
||||||
(mf/deps (:id team))
|
|
||||||
(fn []
|
|
||||||
(->> (rp/query! :teams)
|
|
||||||
(rx/subs #(reset! teams %)))))
|
|
||||||
|
|
||||||
[:ul.dropdown.teams-dropdown
|
[:ul.dropdown.teams-dropdown
|
||||||
[:li.title (t locale "dashboard.switch-team")]
|
[:li.title (t locale "dashboard.switch-team")]
|
||||||
[:hr]
|
[:hr]
|
||||||
|
@ -230,7 +224,7 @@
|
||||||
[:span.team-icon i/logo-icon]
|
[:span.team-icon i/logo-icon]
|
||||||
[:span.team-text (t locale "dashboard.your-penpot")]]
|
[:span.team-text (t locale "dashboard.your-penpot")]]
|
||||||
|
|
||||||
(for [team (remove :is-default @teams)]
|
(for [team (remove :is-default (vals teams))]
|
||||||
[:* {:key (:id team)}
|
[:* {:key (:id team)}
|
||||||
[:li.team-name {:on-click (partial team-selected (:id team))}
|
[:li.team-name {:on-click (partial team-selected (:id team))}
|
||||||
[:span.team-icon
|
[:span.team-icon
|
||||||
|
|
|
@ -9,14 +9,15 @@
|
||||||
|
|
||||||
(ns app.main.ui.measurements
|
(ns app.main.ui.measurements
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[app.common.data :as d]
|
||||||
|
[app.common.geom.point :as gpt]
|
||||||
|
[app.common.geom.shapes :as gsh]
|
||||||
|
[app.common.math :as mth]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.store :as st]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[app.common.data :as d]
|
[rumext.alpha :as mf]))
|
||||||
[app.common.math :as mth]
|
|
||||||
[app.common.geom.shapes :as gsh]
|
|
||||||
[app.common.geom.point :as gpt]
|
|
||||||
[app.main.store :as st]))
|
|
||||||
|
|
||||||
;; ------------------------------------------------
|
;; ------------------------------------------------
|
||||||
;; CONSTANTS
|
;; CONSTANTS
|
||||||
|
@ -233,7 +234,8 @@
|
||||||
:stroke-width (/ select-guide-width zoom)
|
:stroke-width (/ select-guide-width zoom)
|
||||||
:stroke-dasharray (/ select-guide-dasharray zoom)}}])])
|
:stroke-dasharray (/ select-guide-dasharray zoom)}}])])
|
||||||
|
|
||||||
(mf/defc measurement [{:keys [bounds frame selected-shapes hover-shape zoom]}]
|
(mf/defc measurement
|
||||||
|
[{:keys [bounds frame selected-shapes hover-shape zoom]}]
|
||||||
(let [selected-ids (into #{} (map :id) selected-shapes)
|
(let [selected-ids (into #{} (map :id) selected-shapes)
|
||||||
selected-selrect (gsh/selection-rect selected-shapes)
|
selected-selrect (gsh/selection-rect selected-shapes)
|
||||||
hover-selrect (:selrect hover-shape)
|
hover-selrect (:selrect hover-shape)
|
||||||
|
@ -244,9 +246,9 @@
|
||||||
[:g.measurement-feedback {:pointer-events "none"}
|
[:g.measurement-feedback {:pointer-events "none"}
|
||||||
[:& selection-guides {:selrect selected-selrect :bounds bounds :zoom zoom}]
|
[:& selection-guides {:selrect selected-selrect :bounds bounds :zoom zoom}]
|
||||||
[:& size-display {:selrect selected-selrect :zoom zoom}]
|
[:& size-display {:selrect selected-selrect :zoom zoom}]
|
||||||
|
|
||||||
(if (or (not hover-shape) (not hover-selected-shape?))
|
(if (or (not hover-shape) (not hover-selected-shape?))
|
||||||
(when frame
|
(when (and frame (not= uuid/zero (:id frame)))
|
||||||
[:g.hover-shapes
|
[:g.hover-shapes
|
||||||
[:& distance-display {:from (:selrect frame)
|
[:& distance-display {:from (:selrect frame)
|
||||||
:to selected-selrect
|
:to selected-selrect
|
||||||
|
|
|
@ -265,19 +265,18 @@
|
||||||
|
|
||||||
(mf/defc viewer-page
|
(mf/defc viewer-page
|
||||||
[{:keys [file-id page-id index token section] :as props}]
|
[{:keys [file-id page-id index token section] :as props}]
|
||||||
|
|
||||||
(mf/use-effect
|
|
||||||
(mf/deps file-id page-id token)
|
|
||||||
(st/emitf (dv/initialize props)))
|
|
||||||
|
|
||||||
(let [data (mf/deref refs/viewer-data)
|
(let [data (mf/deref refs/viewer-data)
|
||||||
state (mf/deref refs/viewer-local)]
|
state (mf/deref refs/viewer-local)]
|
||||||
|
|
||||||
|
(mf/use-effect
|
||||||
|
(mf/deps file-id page-id token)
|
||||||
|
(fn []
|
||||||
|
(st/emit! (dv/initialize props))))
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
(mf/deps (:file data))
|
(mf/deps (:file data))
|
||||||
#(when (:file data)
|
#(when-let [name (get-in data [:file :name])]
|
||||||
(dom/set-html-title (tr "title.viewer"
|
(dom/set-html-title (tr "title.viewer" name))))
|
||||||
(get-in data [:file :name])))))
|
|
||||||
|
|
||||||
(when (and data state)
|
(when (and data state)
|
||||||
[:& viewer-content
|
[:& viewer-content
|
||||||
|
|
|
@ -188,12 +188,12 @@
|
||||||
total (count frames)
|
total (count frames)
|
||||||
locale (mf/deref i18n/locale)
|
locale (mf/deref i18n/locale)
|
||||||
profile (mf/deref refs/profile)
|
profile (mf/deref refs/profile)
|
||||||
anonymous? (= uuid/zero (:id profile))
|
teams (mf/deref refs/teams)
|
||||||
|
|
||||||
team-id (get-in data [:project :team-id])
|
team-id (get-in data [:project :team-id])
|
||||||
|
|
||||||
has-permission? (and (not anonymous?)
|
has-permission? (and (not= uuid/zero (:id profile))
|
||||||
(contains? (:teams profile) team-id))
|
(contains? teams team-id))
|
||||||
|
|
||||||
project-id (get-in data [:project :id])
|
project-id (get-in data [:project :id])
|
||||||
file-id (get-in data [:file :id])
|
file-id (get-in data [:file :id])
|
||||||
|
|
|
@ -88,7 +88,11 @@
|
||||||
zoom (d/check-num zoom 1)
|
zoom (d/check-num zoom 1)
|
||||||
drawing-tool (:tool drawing)
|
drawing-tool (:tool drawing)
|
||||||
drawing-obj (:object drawing)
|
drawing-obj (:object drawing)
|
||||||
selected-shapes (->> selected (mapv #(get objects %)))
|
|
||||||
|
selected-shapes (into []
|
||||||
|
(comp (map #(get objects %))
|
||||||
|
(filter some?))
|
||||||
|
selected)
|
||||||
selected-frames (into #{} (map :frame-id) selected-shapes)
|
selected-frames (into #{} (map :frame-id) selected-shapes)
|
||||||
|
|
||||||
;; Only when we have all the selected shapes in one frame
|
;; Only when we have all the selected shapes in one frame
|
||||||
|
@ -292,7 +296,7 @@
|
||||||
{:page-id page-id}])
|
{:page-id page-id}])
|
||||||
|
|
||||||
[:& widgets/viewport-actions]
|
[:& widgets/viewport-actions]
|
||||||
|
|
||||||
(when show-prototypes?
|
(when show-prototypes?
|
||||||
[:& interactions/interactions
|
[:& interactions/interactions
|
||||||
{:selected selected}])
|
{:selected selected}])
|
||||||
|
|
|
@ -68,9 +68,9 @@
|
||||||
::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "zoom"]))]}
|
::mf/wrap [#(mf/memo' % (mf/check-props ["shapes" "zoom"]))]}
|
||||||
[props]
|
[props]
|
||||||
(let [shapes (obj/get props "shapes")
|
(let [shapes (obj/get props "shapes")
|
||||||
zoom (obj/get props "zoom")
|
zoom (obj/get props "zoom")
|
||||||
color (if (or (> (count shapes) 1) (nil? (:shape-ref (first shapes))))
|
color (if (or (> (count shapes) 1) (nil? (:shape-ref (first shapes))))
|
||||||
"#31EFB8" "#00E0FF")]
|
"#31EFB8" "#00E0FF")]
|
||||||
(for [shape shapes]
|
(for [shape shapes]
|
||||||
[:& outline {:key (str "outline-" (:id shape))
|
[:& outline {:key (str "outline-" (:id shape))
|
||||||
:shape (gsh/transform-shape shape)
|
:shape (gsh/transform-shape shape)
|
||||||
|
@ -97,7 +97,8 @@
|
||||||
shapes (->> outlines-ids
|
shapes (->> outlines-ids
|
||||||
(filter #(not= edition %))
|
(filter #(not= edition %))
|
||||||
(map #(get objects %))
|
(map #(get objects %))
|
||||||
(filterv show-outline?))]
|
(filterv show-outline?)
|
||||||
|
(filter some?))]
|
||||||
|
|
||||||
[:g.outlines {:display (when (some? transform) "none")}
|
[:g.outlines {:display (when (some? transform) "none")}
|
||||||
[:& shape-outlines-render {:shapes shapes
|
[:& shape-outlines-render {:shapes shapes
|
||||||
|
|
|
@ -31,11 +31,11 @@
|
||||||
(into [] (impl-simplify/simplify points tolerance true)))))
|
(into [] (impl-simplify/simplify points tolerance true)))))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
(def commands-regex #"(?i)[a-z][^a-z]*")
|
(def commands-regex #"(?i)[mzlhvcsqta][^mzlhvcsqta]*")
|
||||||
|
|
||||||
;; Matches numbers for path values allows values like... -.01, 10, +12.22
|
;; Matches numbers for path values allows values like... -.01, 10, +12.22
|
||||||
;; 0 and 1 are special because can refer to flags
|
;; 0 and 1 are special because can refer to flags
|
||||||
(def num-regex #"[+-]?(\d+(\.\d+)?|\.\d+)")
|
(def num-regex #"[+-]?(\d+(\.\d+)?|\.\d+)(e[+-]?\d+)?")
|
||||||
|
|
||||||
(def flag-regex #"[01]")
|
(def flag-regex #"[01]")
|
||||||
|
|
||||||
|
@ -373,14 +373,15 @@
|
||||||
(reduce simplify-command [[start] start-pos start-pos start-pos start-pos])
|
(reduce simplify-command [[start] start-pos start-pos start-pos start-pos])
|
||||||
(first))))
|
(first))))
|
||||||
|
|
||||||
(defn path->content [string]
|
(defn path->content [path-str]
|
||||||
(let [clean-string (-> string
|
(let [clean-path-str
|
||||||
(str/trim)
|
(-> path-str
|
||||||
;; Change "commas" for spaces
|
(str/trim)
|
||||||
(str/replace #"," " ")
|
;; Change "commas" for spaces
|
||||||
;; Remove all consecutive spaces
|
(str/replace #"," " ")
|
||||||
(str/replace #"\s+" " "))
|
;; Remove all consecutive spaces
|
||||||
commands (re-seq commands-regex clean-string)]
|
(str/replace #"\s+" " "))
|
||||||
|
commands (re-seq commands-regex clean-path-str)]
|
||||||
(-> (mapcat parse-command commands)
|
(-> (mapcat parse-command commands)
|
||||||
(simplify-commands))))
|
(simplify-commands))))
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
(swap! storage assoc ::locale lang)
|
(swap! storage assoc ::locale lang)
|
||||||
(reset! locale lang))
|
(reset! locale lang))
|
||||||
(do
|
(do
|
||||||
|
(swap! storage dissoc ::locale)
|
||||||
(reset! locale (autodetect)))))
|
(reset! locale (autodetect)))))
|
||||||
|
|
||||||
(defn reset-locale
|
(defn reset-locale
|
||||||
|
|
|
@ -90,9 +90,7 @@
|
||||||
(let [target (.-target ^js event)]
|
(let [target (.-target ^js event)]
|
||||||
(when (and (not (.-isContentEditable target)) ;; ignore when pasting into
|
(when (and (not (.-isContentEditable target)) ;; ignore when pasting into
|
||||||
(not= (.-tagName target) "INPUT")) ;; an editable control
|
(not= (.-tagName target) "INPUT")) ;; an editable control
|
||||||
(-> ^js event
|
(.. ^js event getBrowserEvent -clipboardData))))
|
||||||
(.getBrowserEvent)
|
|
||||||
(.-clipboardData)))))
|
|
||||||
|
|
||||||
(defn extract-text
|
(defn extract-text
|
||||||
[clipboard-data]
|
[clipboard-data]
|
||||||
|
|
Loading…
Add table
Reference in a new issue