diff --git a/frontend/src/app/main.cljs b/frontend/src/app/main.cljs index cb7ecae4c..04b6a00f4 100644 --- a/frontend/src/app/main.cljs +++ b/frontend/src/app/main.cljs @@ -7,7 +7,6 @@ (ns app.main (:require [app.common.logging :as log] - [app.common.spec :as us] [app.common.uuid :as uuid] [app.config :as cf] [app.main.data.events :as ev] @@ -18,14 +17,12 @@ [app.main.ui :as ui] [app.main.ui.confirm] [app.main.ui.modal :refer [modal]] + [app.main.ui.routes :as rt] [app.main.worker] [app.util.dom :as dom] [app.util.i18n :as i18n] - [app.util.router :as rt] - [app.util.storage :refer [storage]] [app.util.theme :as theme] [beicon.core :as rx] - [cljs.spec.alpha :as s] [potok.core :as ptk] [rumext.alpha :as mf])) @@ -33,79 +30,32 @@ (log/set-level! :root :warn) (log/set-level! :app :info) - (when (= :browser @cf/target) - (log/info :message "wecome to penpot" :version (:full @cf/version) :public-uri (str cf/public-uri))) - + (log/info :message "Welcome to penpot" :version (:full @cf/version) :public-uri (str cf/public-uri))) (declare reinit) -(s/def ::any any?) - -(defn match-path - [router path] - (when-let [match (rt/match router path)] - (if-let [conform (get-in match [:data :conform])] - (let [spath (get conform :path-params ::any) - squery (get conform :query-params ::any)] - (try - (-> (dissoc match :params) - (assoc :path-params (us/conform spath (get match :path-params)) - :query-params (us/conform squery (get match :query-params)))) - (catch :default _ - nil))) - match))) - -(defn on-navigate - [router path] - (let [match (match-path router path) - profile (:profile @storage) - nopath? (or (= path "") (= path "/")) - authed? (and (not (nil? profile)) - (not= (:id profile) uuid/zero))] - - (cond - (and nopath? authed? (nil? match)) - (if (not= uuid/zero profile) - (st/emit! (rt/nav :dashboard-projects {:team-id (du/get-current-team-id profile)})) - (st/emit! (rt/nav :auth-login))) - - (and (not authed?) (nil? match)) - (st/emit! (rt/nav :auth-login)) - - (nil? match) - (st/emit! (rt/assign-exception {:type :not-found})) - - :else - (st/emit! (rt/navigated match))))) - (defn init-ui [] (mf/mount (mf/element ui/app) (dom/get-element "app")) (mf/mount (mf/element modal) (dom/get-element "modal"))) - (defn initialize [] - (letfn [(on-profile [_profile] - (rx/of (rt/initialize-router ui/routes) - (rt/initialize-history on-navigate)))] - (ptk/reify ::initialize - ptk/UpdateEvent - (update [_ state] - (assoc state :session-id (uuid/next))) + (ptk/reify ::initialize + ptk/UpdateEvent + (update [_ state] + (assoc state :session-id (uuid/next))) - ptk/WatchEvent - (watch [_ _ stream] - (rx/merge - (rx/of - (ptk/event ::ev/initialize) - (du/initialize-profile)) - (->> stream - (rx/filter (ptk/type? ::du/profile-fetched)) - (rx/take 1) - (rx/map deref) - (rx/mapcat on-profile))))))) + ptk/WatchEvent + (watch [_ _ stream] + (rx/merge + (rx/of (ptk/event ::ev/initialize) + (du/initialize-profile)) + (->> stream + (rx/filter du/profile-fetched?) + (rx/take 1) + (rx/map #(rt/init-routes))))))) (defn ^:export init [] @@ -121,11 +71,14 @@ (mf/unmount (dom/get-element "modal")) (init-ui)) -(add-watch i18n/locale "locale" (fn [_ _ o v] - (when (not= o v) - (reinit)))) - (defn ^:dev/after-load after-load [] (reinit)) +;; Reload the UI when the language changes +(add-watch + i18n/locale "locale" + (fn [_ _ old-value current-value] + (when (not= old-value current-value) + (reinit)))) + diff --git a/frontend/src/app/main/data/users.cljs b/frontend/src/app/main/data/users.cljs index b894cdeff..3356c0ae9 100644 --- a/frontend/src/app/main/data/users.cljs +++ b/frontend/src/app/main/data/users.cljs @@ -93,6 +93,9 @@ ;; --- EVENT: fetch-profile +(def profile-fetched? + (ptk/type? ::profile-fetched)) + (defn profile-fetched [{:keys [id] :as profile}] (us/verify ::profile profile) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 7f880572a..3612d8490 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -1,4 +1,3 @@ - ;; 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/. diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index bd75ba4f7..b005dc11c 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -6,8 +6,6 @@ (ns app.main.ui (:require - [app.common.spec :as us] - [app.config :as cf] [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.auth :refer [auth]] @@ -25,68 +23,8 @@ [app.main.ui.viewer :as viewer] [app.main.ui.workspace :as workspace] [app.util.router :as rt] - [cljs.spec.alpha :as s] [rumext.alpha :as mf])) -;; --- Routes - -(s/def ::page-id ::us/uuid) -(s/def ::file-id ::us/uuid) -(s/def ::section ::us/keyword) -(s/def ::index ::us/integer) -(s/def ::token (s/nilable ::us/not-empty-string)) -(s/def ::share-id ::us/uuid) - -(s/def ::viewer-path-params - (s/keys :req-un [::file-id])) - -(s/def ::viewer-query-params - (s/keys :opt-un [::index ::share-id ::section ::page-id])) - -(def routes - [["/auth" - ["/login" :auth-login] - (when (contains? @cf/flags :registration) - ["/register" :auth-register]) - (when (contains? @cf/flags :registration) - ["/register/validate" :auth-register-validate]) - (when (contains? @cf/flags :registration) - ["/register/success" :auth-register-success]) - ["/recovery/request" :auth-recovery-request] - ["/recovery" :auth-recovery] - ["/verify-token" :auth-verify-token]] - - ["/settings" - ["/profile" :settings-profile] - ["/password" :settings-password] - ["/feedback" :settings-feedback] - ["/options" :settings-options]] - - ["/view/:file-id" - {:name :viewer - :conform - {:path-params ::viewer-path-params - :query-params ::viewer-query-params}}] - - (when *assert* - ["/debug/icons-preview" :debug-icons-preview]) - - ;; Used for export - ["/render-object/:file-id/:page-id/:object-id" :render-object] - ["/render-sprite/:file-id" :render-sprite] - - ["/dashboard/team/:team-id" - ["/members" :dashboard-team-members] - ["/settings" :dashboard-team-settings] - ["/projects" :dashboard-projects] - ["/search" :dashboard-search] - ["/fonts" :dashboard-fonts] - ["/fonts/providers" :dashboard-font-providers] - ["/libraries" :dashboard-libraries] - ["/projects/:project-id" :dashboard-files]] - - ["/workspace/:project-id/:file-id" :workspace]]) - (mf/defc on-main-error [{:keys [error] :as props}] (mf/use-effect (st/emitf (rt/assign-exception error))) diff --git a/frontend/src/app/main/ui/routes.cljs b/frontend/src/app/main/ui/routes.cljs new file mode 100644 index 000000000..28d402c85 --- /dev/null +++ b/frontend/src/app/main/ui/routes.cljs @@ -0,0 +1,122 @@ +;; 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.ui.routes + (:require + [app.common.spec :as us] + [app.common.uuid :as uuid] + [app.config :as cf] + [app.main.data.users :as du] + [app.main.store :as st] + [app.util.router :as rt] + [app.util.storage :refer [storage]] + [beicon.core :as rx] + [cljs.spec.alpha :as s] + [potok.core :as ptk])) + +(s/def ::page-id ::us/uuid) +(s/def ::file-id ::us/uuid) +(s/def ::section ::us/keyword) +(s/def ::index ::us/integer) +(s/def ::token (s/nilable ::us/not-empty-string)) +(s/def ::share-id ::us/uuid) + +(s/def ::viewer-path-params + (s/keys :req-un [::file-id])) + +(s/def ::viewer-query-params + (s/keys :opt-un [::index ::share-id ::section ::page-id])) + +(s/def ::any any?) + +(def routes + [["/auth" + ["/login" :auth-login] + (when (contains? @cf/flags :registration) + ["/register" :auth-register]) + (when (contains? @cf/flags :registration) + ["/register/validate" :auth-register-validate]) + (when (contains? @cf/flags :registration) + ["/register/success" :auth-register-success]) + ["/recovery/request" :auth-recovery-request] + ["/recovery" :auth-recovery] + ["/verify-token" :auth-verify-token]] + + ["/settings" + ["/profile" :settings-profile] + ["/password" :settings-password] + ["/feedback" :settings-feedback] + ["/options" :settings-options]] + + ["/view/:file-id" + {:name :viewer + :conform + {:path-params ::viewer-path-params + :query-params ::viewer-query-params}}] + + (when *assert* + ["/debug/icons-preview" :debug-icons-preview]) + + ;; Used for export + ["/render-object/:file-id/:page-id/:object-id" :render-object] + ["/render-sprite/:file-id" :render-sprite] + + ["/dashboard/team/:team-id" + ["/members" :dashboard-team-members] + ["/settings" :dashboard-team-settings] + ["/projects" :dashboard-projects] + ["/search" :dashboard-search] + ["/fonts" :dashboard-fonts] + ["/fonts/providers" :dashboard-font-providers] + ["/libraries" :dashboard-libraries] + ["/projects/:project-id" :dashboard-files]] + + ["/workspace/:project-id/:file-id" :workspace]]) + +(defn- match-path + [router path] + (when-let [match (rt/match router path)] + (if-let [conform (get-in match [:data :conform])] + (let [spath (get conform :path-params ::any) + squery (get conform :query-params ::any)] + (try + (-> (dissoc match :params) + (assoc :path-params (us/conform spath (get match :path-params)) + :query-params (us/conform squery (get match :query-params)))) + (catch :default _ + nil))) + match))) + +(defn on-navigate + [router path] + (let [match (match-path router path) + profile (:profile @storage) + nopath? (or (= path "") (= path "/")) + authed? (and (not (nil? profile)) + (not= (:id profile) uuid/zero))] + + (cond + (and nopath? authed? (nil? match)) + (if (not= uuid/zero profile) + (st/emit! (rt/nav :dashboard-projects {:team-id (du/get-current-team-id profile)})) + (st/emit! (rt/nav :auth-login))) + + (and (not authed?) (nil? match)) + (st/emit! (rt/nav :auth-login)) + + (nil? match) + (st/emit! (rt/assign-exception {:type :not-found})) + + :else + (st/emit! (rt/navigated match))))) + +(defn init-routes + [] + (ptk/reify ::init-routes + ptk/WatchEvent + (watch [_ _ _] + (rx/of (rt/initialize-router routes) + (rt/initialize-history on-navigate))))) diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index b239a9185..e0688ade1 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -36,9 +36,6 @@ (def picked-color-select (l/derived :picked-color-select refs/workspace-local)) -(def picked-shift? - (l/derived :picked-shift? refs/workspace-local)) - (def viewport (l/derived (l/in [:workspace-local :vport]) st/state)) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs index d4a2e1772..b886df4f1 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs @@ -115,7 +115,8 @@ :on-mouse-down #(reset! dragging? true) :on-mouse-up #(reset! dragging? false) :on-pointer-down (partial dom/capture-pointer) - :on-pointer-up (partial dom/release-pointer) + :on-lost-pointer-capture #(do (dom/release-pointer %) + (reset! dragging? false)) :on-click calculate-pos :on-mouse-move #(when @dragging? (calculate-pos %))}] [:div.handler {:style {:pointer-events "none" diff --git a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs index ea79bbd3c..8fbd1e534 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs @@ -26,7 +26,8 @@ {:on-mouse-down #(reset! dragging? true) :on-mouse-up #(reset! dragging? false) :on-pointer-down (partial dom/capture-pointer) - :on-pointer-up (partial dom/release-pointer) + :on-lost-pointer-capture #(do (dom/release-pointer %) + (reset! dragging? false)) :on-click calculate-pos :on-mouse-move #(when @dragging? (calculate-pos %))} [:div.handler {:style {:pointer-events "none" diff --git a/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs index e0e630e43..4518decda 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs @@ -35,7 +35,8 @@ :on-mouse-down #(reset! dragging? true) :on-mouse-up #(reset! dragging? false) :on-pointer-down (partial dom/capture-pointer) - :on-pointer-up (partial dom/release-pointer) + :on-lost-pointer-capture #(do (dom/release-pointer %) + (reset! dragging? false)) :on-click calculate-pos :on-mouse-move #(when @dragging? (calculate-pos %))}