diff --git a/frontend/resources/styles/common/framework.scss b/frontend/resources/styles/common/framework.scss index 80db6b5fc..e443bc3ac 100644 --- a/frontend/resources/styles/common/framework.scss +++ b/frontend/resources/styles/common/framework.scss @@ -956,112 +956,6 @@ input[type=range]:focus::-ms-fill-upper { } -// Messages -.message { - position: fixed; - top: 0; - left: 0px; - width: 100%; - z-index: 12; - @include animation(0, 1s, fadeInDown); - - .message-body { - align-items: center; - border-radius: $br-small; - border-bottom: 3px solid transparent; - color: $color-white; - display: flex; - flex-wrap: wrap; - justify-content: center; - margin: 0 auto; - padding: $medium $big; - position: relative; - width: 100%; - - span { - font-size: $fs18; - max-width: 60%; - text-align: center; - width: 100%; - } - - .close { - cursor: pointer; - position: absolute; - top: 10px; - right: 10px; - opacity: .3; - width: 18px; - - svg { - fill: $color-black; - height: 18px; - width: 18px; - transform: rotate(45deg); - } - - &:hover { - opacity: .8; - } - - } - - .message-action { - align-items: center; - display: flex; - justify-content: space-around; - margin-top: $medium; - max-width: 60%; - width: 100%; - } - - } - - &.error { - - .message-body { - background-color: $color-danger; - border-color: $color-danger-dark; - } - - } - - &.success { - - .message-body { - background-color: $color-success; - border-color: $color-success-dark; - } - - } - - &.info { - - .message-body { - background-color: $color-info; - border-color: $color-info-dark; - } - - } - - &.quick { - - .message-body { - - .close { - display: none; - } - - } - - } - - &.hide-message { - @include animation(0, .6s, fadeOutUp); - } - -} - .message-version { align-items: center; background-color: rgba(27, 170, 214, .6); diff --git a/frontend/resources/styles/main.scss b/frontend/resources/styles/main.scss index 6ea6dd0bf..57c2bafe1 100644 --- a/frontend/resources/styles/main.scss +++ b/frontend/resources/styles/main.scss @@ -75,6 +75,7 @@ @import "main/partials/viewer-header"; @import "main/partials/viewer-thumbnails"; @import "main/partials/viewer"; +@import "main/partials/messages"; //################################################# // Resources diff --git a/frontend/resources/styles/main/partials/messages.scss b/frontend/resources/styles/main/partials/messages.scss new file mode 100644 index 000000000..a4bcc00ec --- /dev/null +++ b/frontend/resources/styles/main/partials/messages.scss @@ -0,0 +1,74 @@ +// Messages + +.message { + position: fixed; + top: 0; + left: 0px; + width: 100%; + height: 40px; + z-index: 13; + + display: flex; + justify-content: center; + align-items: center; + + .close-button { + position: absolute; + right: 0px; + top: 0px; + width: 40px; + height: 40px; + + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + + svg { + fill: $color-black; + height: 18px; + width: 18px; + transform: rotate(45deg); + } + + &:hover { + opacity: .8; + } + + } + + .message-content { + color: $color-white; + + span { + font-size: $fs18; + max-width: 60%; + } + } + + &.error { + background-color: $color-danger; + border-color: $color-danger-dark; + } + + &.success { + background-color: $color-success; + border-color: $color-success-dark; + } + + &.info { + background-color: $color-info; + border-color: $color-info-dark; + } + + &.quick { + .close-button { + display: none; + } + } + + &.hide-message { + @include animation(0, .6s, fadeOutUp); + } +} + diff --git a/frontend/src/uxbox/main.cljs b/frontend/src/uxbox/main.cljs index 63f222f91..40f5a7382 100644 --- a/frontend/src/uxbox/main.cljs +++ b/frontend/src/uxbox/main.cljs @@ -22,7 +22,6 @@ [uxbox.util.dom :as dom] [uxbox.util.html.history :as html-history] [uxbox.util.i18n :as i18n] - [uxbox.util.messages :as uum] [uxbox.util.router :as rt] [uxbox.util.storage :refer [storage]] [uxbox.util.timers :as ts])) diff --git a/frontend/src/uxbox/main/data/auth.cljs b/frontend/src/uxbox/main/data/auth.cljs index b76786ad7..168a6d97c 100644 --- a/frontend/src/uxbox/main/data/auth.cljs +++ b/frontend/src/uxbox/main/data/auth.cljs @@ -16,7 +16,7 @@ [uxbox.main.repo :as rp] [uxbox.main.store :refer [initial-state]] [uxbox.main.data.users :as du] - [uxbox.util.messages :as um] + [uxbox.main.data.messages :as dm] [uxbox.util.router :as rt] [uxbox.util.i18n :as i18n :refer [tr]] [uxbox.util.storage :refer [storage]])) @@ -53,7 +53,7 @@ (let [params {:email email :password password :scope "webapp"} - on-error #(rx/of (um/error (tr "errors.auth.unauthorized")))] + on-error #(rx/of (dm/error (tr "errors.auth.unauthorized")))] (->> (rp/mutation :login params) (rx/map logged-in) (rx/catch rp/client-error? on-error)))))) diff --git a/frontend/src/uxbox/main/data/messages.cljs b/frontend/src/uxbox/main/data/messages.cljs new file mode 100644 index 000000000..4dc2e772b --- /dev/null +++ b/frontend/src/uxbox/main/data/messages.cljs @@ -0,0 +1,50 @@ +;; 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.data.messages + (:require + [cljs.spec.alpha :as s] + [potok.core :as ptk] + [beicon.core :as rx] + [uxbox.common.data :as d] + [uxbox.common.pages :as cp] + [uxbox.common.spec :as us] + [uxbox.common.exceptions :as ex] + [uxbox.config :as cfg])) + +(declare hide) +(declare show) + +(def +animation-timeout+ 600) + +(defn show + [data] + (ptk/reify ::show + ptk/UpdateEvent + (update [_ state] + (let [message (assoc data :status :visible)] + (assoc state :message message))) + + ptk/WatchEvent + (watch [_ state stream] + (let [stoper (rx/filter (ptk/type? ::show) stream)] + (->> (rx/of hide) + (rx/delay (:timeout data)) + (rx/take-until stoper)))))) + +(def hide + (ptk/reify ::hide + ptk/UpdateEvent + (update [_ state] + (update state :message assoc :status :hide)) + + ptk/WatchEvent + (watch [_ state stream] + (->> (rx/of #(dissoc % :message)) + (rx/delay +animation-timeout+))))) diff --git a/frontend/src/uxbox/main/data/users.cljs b/frontend/src/uxbox/main/data/users.cljs index 0a6e4158e..cc2ccf96a 100644 --- a/frontend/src/uxbox/main/data/users.cljs +++ b/frontend/src/uxbox/main/data/users.cljs @@ -13,7 +13,6 @@ [uxbox.common.spec :as us] [uxbox.main.repo :as rp] [uxbox.util.i18n :as i18n :refer [tr]] - [uxbox.util.messages :as uum] [uxbox.util.storage :refer [storage]])) ;; --- Common Specs diff --git a/frontend/src/uxbox/main/ui.cljs b/frontend/src/uxbox/main/ui.cljs index 7a0cf1602..630ff1e03 100644 --- a/frontend/src/uxbox/main/ui.cljs +++ b/frontend/src/uxbox/main/ui.cljs @@ -18,6 +18,7 @@ [uxbox.common.exceptions :as ex] [uxbox.common.data :as d] [uxbox.main.data.auth :refer [logout]] + [uxbox.main.data.messages :as dm] [uxbox.main.refs :as refs] [uxbox.main.store :as st] [uxbox.main.ui.dashboard :refer [dashboard]] @@ -31,7 +32,6 @@ [uxbox.main.ui.shapes] [uxbox.main.ui.workspace :as workspace] [uxbox.util.i18n :refer [tr]] - [uxbox.util.messages :as uum] [uxbox.util.timers :as ts])) (def route-iref @@ -171,12 +171,12 @@ (and (map? error) (= :unexpected type) (= :abort code)) - (ts/schedule 100 #(st/emit! (uum/error (tr "errors.network")))) + (ts/schedule 100 #(st/emit! (dm/error (tr "errors.network")))) ;; Something else :else (do (js/console.error error) - (ts/schedule 100 #(st/emit! (uum/error (tr "errors.generic"))))))) + (ts/schedule 100 #(st/emit! (dm/error (tr "errors.generic"))))))) (set! st/*on-error* on-error) diff --git a/frontend/src/uxbox/main/ui/dashboard.cljs b/frontend/src/uxbox/main/ui/dashboard.cljs index b43578142..6c610d266 100644 --- a/frontend/src/uxbox/main/ui/dashboard.cljs +++ b/frontend/src/uxbox/main/ui/dashboard.cljs @@ -21,7 +21,7 @@ [uxbox.main.ui.dashboard.recent-files :refer [recent-files-page]] [uxbox.main.ui.dashboard.library :refer [library-page]] [uxbox.main.ui.dashboard.profile :refer [profile-section]] - [uxbox.main.ui.messages :refer [messages-widget]])) + [uxbox.main.ui.messages :refer [messages]])) (defn ^boolean uuid-str? [s] @@ -64,8 +64,8 @@ page (get-in route [:data :name]) {:keys [search-term team-id project-id library-id library-section] :as params} (parse-params route profile)] - [:main.dashboard-main - [:& messages-widget] + [:* + [:& messages] [:section.dashboard-layout [:div.main-logo i/logo-icon] [:& profile-section {:profile profile}] diff --git a/frontend/src/uxbox/main/ui/dashboard/sidebar.cljs b/frontend/src/uxbox/main/ui/dashboard/sidebar.cljs index 58fbc5870..8341100d4 100644 --- a/frontend/src/uxbox/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/uxbox/main/ui/dashboard/sidebar.cljs @@ -24,7 +24,6 @@ [uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.confirm :refer [confirm-dialog]] [uxbox.main.ui.dashboard.common :as common] - [uxbox.main.ui.messages :refer [messages-widget]] [uxbox.util.dom :as dom] [uxbox.util.i18n :as i18n :refer [t tr]] [uxbox.util.router :as rt] diff --git a/frontend/src/uxbox/main/ui/login.cljs b/frontend/src/uxbox/main/ui/login.cljs index 2ba8241a0..0bcb40a9d 100644 --- a/frontend/src/uxbox/main/ui/login.cljs +++ b/frontend/src/uxbox/main/ui/login.cljs @@ -17,7 +17,7 @@ [uxbox.config :as cfg] [uxbox.main.data.auth :as da] [uxbox.main.store :as st] - [uxbox.main.ui.messages :refer [messages-widget]] + [uxbox.main.ui.messages :refer [messages]] [uxbox.util.dom :as dom] [uxbox.util.forms :as fm] [uxbox.util.i18n :refer [tr]] @@ -94,6 +94,6 @@ [] [:div.login [:div.login-body - [:& messages-widget] + [:& messages] [:a i/logo] [:& login-form]]]) diff --git a/frontend/src/uxbox/main/ui/messages.cljs b/frontend/src/uxbox/main/ui/messages.cljs index 6b2e263a8..cfe0e7075 100644 --- a/frontend/src/uxbox/main/ui/messages.cljs +++ b/frontend/src/uxbox/main/ui/messages.cljs @@ -2,16 +2,56 @@ (:require [lentes.core :as l] [rumext.alpha :as mf] + [uxbox.builtins.icons :as i] + [uxbox.main.data.messages :as dm] [uxbox.main.store :as st] - [uxbox.util.messages :as um])) + [uxbox.util.dom :as dom] + [uxbox.util.timers :as ts] + [uxbox.util.i18n :as i18n :refer [t]] + [uxbox.util.data :refer [classnames]])) + +;; --- Main Component (entry point) + +(declare notification) (def ^:private message-iref (-> (l/key :message) (l/derive st/state))) +(mf/defc messages + [] + (let [message (mf/deref message-iref) + ;; message {:type :error + ;; :content "Hello world!"} + ] + (when message + [:& notification {:type (:type message) + :status (:status message) + :content (:content message)}]))) + (mf/defc messages-widget [] (let [message (mf/deref message-iref) - on-close #(st/emit! (um/hide))] - [:& um/messages-widget {:message message - :on-close on-close}])) + message {:type :error + :content "Hello world!"}] + + [:& notification {:type (:type message) + :status (:status message) + :content (:content message)}])) + +;; --- Notification Component + +(mf/defc notification + [{:keys [type status content] :as props}] + (let [on-close #(st/emit! dm/hide) + klass (classnames + :error (= type :error) + :info (= type :info) + :hide-message (= status :hide) + :success (= type :success) + :quick false)] + [:div.message {:class klass} + [:a.close-button {:on-click on-close} i/close] + [:div.message-content + [:span content]]])) + diff --git a/frontend/src/uxbox/main/ui/profile/recovery.cljs b/frontend/src/uxbox/main/ui/profile/recovery.cljs index db07a5e52..b221f455e 100644 --- a/frontend/src/uxbox/main/ui/profile/recovery.cljs +++ b/frontend/src/uxbox/main/ui/profile/recovery.cljs @@ -17,10 +17,10 @@ [uxbox.builtins.icons :as i] [uxbox.common.spec :as us] [uxbox.main.data.auth :as uda] + [uxbox.main.data.messages :as dm] [uxbox.main.store :as st] - [uxbox.main.ui.messages :refer [messages-widget]] + [uxbox.main.ui.messages :refer [messages]] [uxbox.main.ui.navigation :as nav] - [uxbox.util.messages :as um] [uxbox.util.dom :as dom] [uxbox.util.forms :as fm] [uxbox.util.i18n :as i18n :refer [t]] @@ -37,12 +37,12 @@ on-success (fn [] - (st/emit! (um/info (t locale "profile.recovery.password-changed")) + (st/emit! (dm/info (t locale "profile.recovery.password-changed")) (rt/nav :login))) on-error (fn [] - (st/emit! (um/error (t locale "profile.recovery.invalid-token")))) + (st/emit! (dm/error (t locale "profile.recovery.invalid-token")))) on-submit (fn [event] @@ -86,6 +86,6 @@ [] [:div.login [:div.login-body - [:& messages-widget] + [:& messages] [:a i/logo] [:& recovery-form]]]) diff --git a/frontend/src/uxbox/main/ui/profile/recovery_request.cljs b/frontend/src/uxbox/main/ui/profile/recovery_request.cljs index 3f654c3ae..3db6352f5 100644 --- a/frontend/src/uxbox/main/ui/profile/recovery_request.cljs +++ b/frontend/src/uxbox/main/ui/profile/recovery_request.cljs @@ -17,10 +17,10 @@ [uxbox.builtins.icons :as i] [uxbox.common.spec :as us] [uxbox.main.data.auth :as uda] + [uxbox.main.data.messages :as dm] [uxbox.main.store :as st] - [uxbox.main.ui.messages :refer [messages-widget]] + [uxbox.main.ui.messages :refer [messages]] [uxbox.main.ui.navigation :as nav] - [uxbox.util.messages :as um] [uxbox.util.dom :as dom] [uxbox.util.forms :as fm] [uxbox.util.i18n :as i18n :refer [t]] @@ -36,7 +36,7 @@ on-success (fn [] - (st/emit! (um/info (t locale "profile.recovery.recovery-token-sent")) + (st/emit! (dm/info (t locale "profile.recovery.recovery-token-sent")) (rt/nav :profile-recovery))) on-submit @@ -70,6 +70,6 @@ [] [:div.login [:div.login-body - [:& messages-widget] + [:& messages] [:a i/logo] [:& recovery-form]]]) diff --git a/frontend/src/uxbox/main/ui/profile/register.cljs b/frontend/src/uxbox/main/ui/profile/register.cljs index 03102b744..659ef6796 100644 --- a/frontend/src/uxbox/main/ui/profile/register.cljs +++ b/frontend/src/uxbox/main/ui/profile/register.cljs @@ -14,7 +14,7 @@ [uxbox.builtins.icons :as i] [uxbox.main.data.auth :as uda] [uxbox.main.store :as st] - [uxbox.main.ui.messages :refer [messages-widget]] + [uxbox.main.ui.messages :refer [messages]] [uxbox.main.ui.navigation :as nav] [uxbox.util.dom :as dom] [uxbox.util.forms :as fm] @@ -115,6 +115,6 @@ [props] [:div.login [:div.login-body - [:& messages-widget] + [:& messages] [:a i/logo] [:& register-form]]]) diff --git a/frontend/src/uxbox/main/ui/settings.cljs b/frontend/src/uxbox/main/ui/settings.cljs index 794ea37d5..d901f9222 100644 --- a/frontend/src/uxbox/main/ui/settings.cljs +++ b/frontend/src/uxbox/main/ui/settings.cljs @@ -15,7 +15,7 @@ [uxbox.main.store :as st] [uxbox.util.router :as rt] [uxbox.main.ui.dashboard.profile :refer [profile-section]] - [uxbox.main.ui.messages :refer [messages-widget]] + [uxbox.main.ui.messages :refer [messages]] [uxbox.main.ui.settings.header :refer [header]] [uxbox.main.ui.settings.password :refer [password-page]] [uxbox.main.ui.settings.profile :refer [profile-page]])) @@ -25,7 +25,7 @@ (let [section (get-in route [:data :name]) profile (mf/deref refs/profile)] [:main.settings-main - [:& messages-widget] + [:& messages] [:div.settings-content [:& header {:section section}] (case section diff --git a/frontend/src/uxbox/main/ui/settings/password.cljs b/frontend/src/uxbox/main/ui/settings/password.cljs index 90386e45b..bef226283 100644 --- a/frontend/src/uxbox/main/ui/settings/password.cljs +++ b/frontend/src/uxbox/main/ui/settings/password.cljs @@ -14,11 +14,11 @@ [cljs.spec.alpha :as s] [uxbox.builtins.icons :as i] [uxbox.main.data.users :as udu] + [uxbox.main.data.messages :as dm] [uxbox.main.store :as st] [uxbox.util.dom :as dom] [uxbox.util.forms :as fm] - [uxbox.util.i18n :refer [tr]] - [uxbox.util.messages :as um])) + [uxbox.util.i18n :refer [tr]])) (defn- on-error [form error] @@ -33,7 +33,7 @@ [event form] (dom/prevent-default event) (let [data (:clean-data form) - mdata {:on-success #(st/emit! (um/info (tr "settings.password.password-saved"))) + mdata {:on-success #(st/emit! (dm/info (tr "settings.password.password-saved"))) :on-error #(on-error form %)}] (st/emit! (udu/update-password (with-meta data mdata))))) diff --git a/frontend/src/uxbox/main/ui/settings/profile.cljs b/frontend/src/uxbox/main/ui/settings/profile.cljs index 97ff7e849..8cf691926 100644 --- a/frontend/src/uxbox/main/ui/settings/profile.cljs +++ b/frontend/src/uxbox/main/ui/settings/profile.cljs @@ -13,16 +13,12 @@ [rumext.alpha :as mf] [uxbox.builtins.icons :as i] [uxbox.main.data.users :as udu] + [uxbox.main.data.messages :as dm] [uxbox.main.store :as st] - [uxbox.util.data :refer [read-string]] + [uxbox.main.refs :as refs] [uxbox.util.dom :as dom] [uxbox.util.forms :as fm] - [uxbox.util.i18n :as i18n :refer [tr t]] - [uxbox.util.messages :as um])) - -(def ^:private profile-iref - (-> (l/key :profile) - (l/derive st/state))) + [uxbox.util.i18n :as i18n :refer [tr t]])) (s/def ::fullname ::fm/not-empty-string) (s/def ::lang (s/nilable ::fm/not-empty-string)) @@ -48,7 +44,7 @@ [event form] (dom/prevent-default event) (let [data (:clean-data form) - on-success #(st/emit! (um/info (tr "settings.profile.profile-saved"))) + on-success #(st/emit! (dm/info (tr "settings.profile.profile-saved"))) on-error #(on-error % form)] (st/emit! (udu/update-profile (with-meta data {:on-success on-success @@ -59,7 +55,7 @@ (mf/defc profile-form [props] (let [locale (i18n/use-locale) - form (fm/use-form ::profile-form #(deref profile-iref)) + form (fm/use-form ::profile-form #(deref refs/profile)) data (:data form)] (prn "data" form) [:form.profile-form {:on-submit #(on-submit % form)} @@ -108,7 +104,7 @@ (mf/defc profile-photo-form [props] - (let [profile (mf/deref profile-iref) + (let [profile (mf/deref refs/profile) photo (:photo-uri profile) photo (if (or (str/empty? photo) (nil? photo)) "images/avatar.jpg" diff --git a/frontend/src/uxbox/main/ui/viewer.cljs b/frontend/src/uxbox/main/ui/viewer.cljs index f9a71c21b..d74ac94d1 100644 --- a/frontend/src/uxbox/main/ui/viewer.cljs +++ b/frontend/src/uxbox/main/ui/viewer.cljs @@ -15,19 +15,18 @@ [lentes.core :as l] [rumext.alpha :as mf] [uxbox.builtins.icons :as i] - [uxbox.main.store :as st] [uxbox.common.exceptions :as ex] - [uxbox.main.ui.keyboard :as kbd] - [uxbox.main.ui.components.dropdown :refer [dropdown]] [uxbox.main.data.viewer :as dv] + [uxbox.main.store :as st] + [uxbox.main.ui.components.dropdown :refer [dropdown]] + [uxbox.main.ui.hooks :as hooks] + [uxbox.main.ui.keyboard :as kbd] + [uxbox.main.ui.messages :refer [messages]] [uxbox.main.ui.viewer.header :refer [header]] [uxbox.main.ui.viewer.thumbnails :refer [thumbnails-panel frame-svg]] - [uxbox.util.dom :as dom] - [uxbox.main.ui.hooks :as hooks] [uxbox.util.data :refer [classnames]] - [uxbox.util.i18n :as i18n :refer [t tr]] - [uxbox.util.math :as mth] - [uxbox.util.router :as rt]) + [uxbox.util.dom :as dom] + [uxbox.util.i18n :as i18n :refer [t tr]]) (:import goog.events.EventType goog.events.KeyCodes)) @@ -68,21 +67,23 @@ (mf/use-effect on-mount) (hooks/use-shortcuts dv/shortcuts) - [:div.viewer-layout {:class (classnames :fullscreen fullscreen?) - :ref container} + [:* + [:& messages] + [:div.viewer-layout {:class (classnames :fullscreen fullscreen?) + :ref container} - [:& header {:data data - :toggle-fullscreen toggle-fullscreen - :fullscreen? fullscreen? - :local local - :index index}] - [:div.viewer-content - (when (:show-thumbnails local) - [:& thumbnails-panel {:index index - :data data}]) - [:& main-panel {:data data - :zoom (:zoom local) - :index index}]]])) + [:& header {:data data + :toggle-fullscreen toggle-fullscreen + :fullscreen? fullscreen? + :local local + :index index}] + [:div.viewer-content + (when (:show-thumbnails local) + [:& thumbnails-panel {:index index + :data data}]) + [:& main-panel {:data data + :zoom (:zoom local) + :index index}]]]])) ;; --- Component: Viewer Page diff --git a/frontend/src/uxbox/main/ui/viewer/header.cljs b/frontend/src/uxbox/main/ui/viewer/header.cljs index f4377ab1f..254b1c199 100644 --- a/frontend/src/uxbox/main/ui/viewer/header.cljs +++ b/frontend/src/uxbox/main/ui/viewer/header.cljs @@ -9,25 +9,20 @@ (ns uxbox.main.ui.viewer.header (:require - [beicon.core :as rx] - [goog.events :as events] - [goog.object :as gobj] - [lentes.core :as l] [rumext.alpha :as mf] [uxbox.builtins.icons :as i] + [uxbox.main.data.messages :as dm] + [uxbox.main.data.viewer :as dv] + [uxbox.main.refs :as refs] [uxbox.main.store :as st] [uxbox.main.ui.components.dropdown :refer [dropdown]] [uxbox.main.ui.workspace.header :refer [zoom-widget]] - [uxbox.main.data.viewer :as dv] - [uxbox.main.refs :as refs] [uxbox.util.data :refer [classnames]] [uxbox.util.dom :as dom] + [uxbox.util.i18n :as i18n :refer [t]] + [uxbox.util.router :as rt] [uxbox.util.uuid :as uuid] - [uxbox.util.i18n :as i18n :refer [t tr]] - [uxbox.util.math :as mth] - [uxbox.util.router :as rt]) - (:import goog.events.EventType - goog.events.KeyCodes)) + [uxbox.util.webapi :as wapi])) (mf/defc share-link @@ -36,30 +31,45 @@ dropdown-ref (mf/use-ref) token (:share-token page) + locale (i18n/use-locale) + create #(st/emit! dv/create-share-link) delete #(st/emit! dv/delete-share-link) - href (.-href js/location)] + + href (.-href js/location) + link (str href "&token=" token) + + copy-link + (fn [event] + (wapi/write-to-clipboard link) + (st/emit! (dm/show {:type :info + :content "Link copied successfuly!" + :timeout 2000})))] [:* [:span.btn-primary.btn-small - {:alt "Share link" + {:alt (t locale "viewer.header.share.title") :on-click #(swap! show-dropdown? not)} - "Share link"] + (t locale "viewer.header.share.title")] [:& dropdown {:show @show-dropdown? :on-close #(swap! show-dropdown? not) :container dropdown-ref} [:div.share-link-dropdown {:ref dropdown-ref} - [:span.share-link-title "Share link"] + [:span.share-link-title (t locale "viewer.header.share.title")] [:div.share-link-input (if (string? token) - [:span.link (str href "&token=" token)] - [:span.link-placeholder "Share link will apear here"]) - [:span.link-button "Copy link"]] - [:span.share-link-subtitle "Anyone with the link will have access"] + [:span.link link] + [:span.link-placeholder (t locale "viewer.header.share.placeholder")]) + [:span.link-button {:on-click copy-link} + (t locale "viewer.header.share.copy-link")]] + + [:span.share-link-subtitle (t locale "viewer.header.share.subtitle")] [:div.share-link-buttons (if (string? token) - [:button.btn-delete {:on-click delete} "Remove link"] - [:button.btn-primary {:on-click create} "Create link"])]]]])) + [:button.btn-delete {:on-click delete} + (t locale "viewer.header.share.remove-link")] + [:button.btn-primary {:on-click create} + (t locale "viewer.header.share.create-link")])]]]])) (mf/defc header [{:keys [data index local fullscreen? toggle-fullscreen] :as props}] @@ -67,6 +77,8 @@ total (count frames) on-click #(st/emit! dv/toggle-thumbnails-panel) + locale (i18n/use-locale) + profile (mf/deref refs/profile) anonymous? (= uuid/zero (:id profile)) @@ -82,7 +94,7 @@ [:div.main-icon [:a {:on-click on-edit} i/logo-icon]] - [:div.sitemap-zone {:alt (tr "header.sitemap") + [:div.sitemap-zone {:alt (t locale "viewer.header.sitemap") :on-click on-click} [:span.project-name (:name project)] [:span "/"] @@ -96,7 +108,8 @@ (when-not anonymous? [:& share-link {:page (:page data)}]) (when-not anonymous? - [:a {:on-click on-edit} "Edit page"]) + [:a {:on-click on-edit} + (t locale "viewer.header.edit-page")]) [:& zoom-widget {:zoom (:zoom local) @@ -107,7 +120,7 @@ :on-zoom-to-200 #(st/emit! dv/zoom-to-200)}] [:span.btn-fullscreen.tooltip.tooltip-bottom - {:alt "Full Screen" + {:alt (t locale "viewer.header.fullscreen") :on-click toggle-fullscreen} (if fullscreen? i/full-screen-off diff --git a/frontend/src/uxbox/main/ui/workspace.cljs b/frontend/src/uxbox/main/ui/workspace.cljs index 108a33e0f..e4f68b35f 100644 --- a/frontend/src/uxbox/main/ui/workspace.cljs +++ b/frontend/src/uxbox/main/ui/workspace.cljs @@ -20,7 +20,7 @@ [uxbox.main.ui.confirm] [uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.hooks :as hooks] - [uxbox.main.ui.messages :refer [messages-widget]] + [uxbox.main.ui.messages :refer [messages]] [uxbox.main.ui.workspace.viewport :refer [viewport]] [uxbox.main.ui.workspace.colorpalette :refer [colorpalette]] [uxbox.main.ui.workspace.context-menu :refer [context-menu]] @@ -68,33 +68,34 @@ (when (:colorpalette layout) [:& colorpalette {:left-sidebar? left-sidebar?}]) - [:main.main-content - [:& context-menu {}] - [:section.workspace-content - {:class classes - :on-scroll on-scroll - :on-wheel #(on-wheel % frame)} + [:& messages] + [:& context-menu {}] - [:& history-dialog] + [:section.workspace-content + {:class classes + :on-scroll on-scroll + :on-wheel #(on-wheel % frame)} - ;; Rules - (when (contains? layout :rules) - [:* - [:& horizontal-rule] - [:& vertical-rule]]) + [:& history-dialog] - [:section.workspace-viewport {:id "workspace-viewport" - :ref frame} - [:& viewport {:page page :file file}]]] + ;; Rules + (when (contains? layout :rules) + [:* + [:& horizontal-rule] + [:& vertical-rule]]) - [:& left-toolbar {:page page - :layout layout}] + [:section.workspace-viewport {:id "workspace-viewport" + :ref frame} + [:& viewport {:page page :file file}]]] - ;; Aside - (when left-sidebar? - [:& left-sidebar {:file file :page page :layout layout}]) - (when right-sidebar? - [:& right-sidebar {:page page :layout layout}])]])) + [:& left-toolbar {:page page + :layout layout}] + + ;; Aside + (when left-sidebar? + [:& left-sidebar {:file file :page page :layout layout}]) + (when right-sidebar? + [:& right-sidebar {:page page :layout layout}])])) (mf/defc workspace @@ -121,7 +122,6 @@ project (mf/deref refs/workspace-project) layout (mf/deref refs/workspace-layout)] [:> rdnd/provider {:backend rdnd/html5} - [:& messages-widget] [:& header {:page page :file file :project project diff --git a/frontend/src/uxbox/main/ui/workspace/header.cljs b/frontend/src/uxbox/main/ui/workspace/header.cljs index 425fcec7b..36ecd055a 100644 --- a/frontend/src/uxbox/main/ui/workspace/header.cljs +++ b/frontend/src/uxbox/main/ui/workspace/header.cljs @@ -178,5 +178,6 @@ [:a.preview-button {;; :target "__blank" + :alt (t locale "workspace.header.viewer") :href (str "#" view-url)} i/play]]])) diff --git a/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs b/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs index af84435fc..a8871b59b 100644 --- a/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs +++ b/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs @@ -16,6 +16,7 @@ [uxbox.main.store :as st] [uxbox.main.ui.modal :as modal] [uxbox.main.ui.workspace.images :refer [import-image-modal]] + [uxbox.util.i18n :as i18n :refer [t]] [uxbox.builtins.icons :as i])) ;; --- Component: Left toolbar @@ -25,41 +26,42 @@ (let [selected-drawtool (mf/deref refs/selected-drawing-tool) select-drawtool #(st/emit! :interrupt (dw/select-for-drawing %)) + locale (i18n/use-locale) on-image #(modal/show! import-image-modal {})] - [:div.left-toolbar + [:aside.left-toolbar [:div.left-toolbar-inside [:ul.left-toolbar-options [:li.tooltip.tooltip-right - {:alt "Artboard" + {:alt (t locale "workspace.toolbar.frame") :class (when (= selected-drawtool :frame) "selected") :on-click (partial select-drawtool :frame)} i/artboard] [:li.tooltip.tooltip-right - {:alt "Box" + {:alt (t locale "workspace.toolbar.rect") :class (when (= selected-drawtool :rect) "selected") :on-click (partial select-drawtool :rect)} i/box] [:li.tooltip.tooltip-right - {:alt "Circle" + {:alt (t locale "workspace.toolbar.circle") :class (when (= selected-drawtool :circle) "selected") :on-click (partial select-drawtool :circle)} i/circle] [:li.tooltip.tooltip-right - {:alt "Text" + {:alt (t locale "workspace.toolbar.text") :class (when (= selected-drawtool :text) "selected") :on-click (partial select-drawtool :text)} i/text] [:li.tooltip.tooltip-right - {:alt "Insert image" + {:alt (t locale "workspace.toolbar.image") :on-click on-image} i/image] [:li.tooltip.tooltip-right - {:alt "Pencil tool" + {:alt (t locale "workspace.toolbar.curve") :class (when (= selected-drawtool :curve) "selected") :on-click (partial select-drawtool :curve)} i/pencil] [:li.tooltip.tooltip-right - {:alt "Curves tool" + {:alt (t locale "workspace.toolbar.path") :class (when (= selected-drawtool :path) "selected") :on-click (partial select-drawtool :path)} i/curve]] @@ -71,7 +73,7 @@ :on-click #(st/emit! (dw/toggle-layout-flag :layers))} i/layers] [:li.tooltip.tooltip-right - {:alt "Libraries" + {:alt (t locale "workspace.toolbar.libraries") :class (when (contains? layout :libraries) "selected") :on-click #(st/emit! (dw/toggle-layout-flag :libraries))} i/icon-set] @@ -79,7 +81,7 @@ {:alt "History"} i/undo-history] [:li.tooltip.tooltip-right - {:alt "Palette" + {:alt (t locale "workspace.toolbar.color-palette") :class (when (contains? layout :colorpalette) "selected") :on-click #(st/emit! (dw/toggle-layout-flag :colorpalette))} i/palette]]]])) diff --git a/frontend/src/uxbox/util/messages.cljs b/frontend/src/uxbox/util/messages.cljs deleted file mode 100644 index f5ff97a5c..000000000 --- a/frontend/src/uxbox/util/messages.cljs +++ /dev/null @@ -1,145 +0,0 @@ -;; 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) 2016-2017 Andrey Antukh - -(ns uxbox.util.messages - "Messages notifications." - (:require - [beicon.core :as rx] - [cuerdas.core :as str] - [lentes.core :as l] - [potok.core :as ptk] - [rumext.alpha :as mf] - [uxbox.builtins.icons :as i] - [uxbox.util.data :refer [classnames]] - [uxbox.util.dom :as dom] - [uxbox.util.timers :as ts] - [uxbox.util.i18n :refer [tr]])) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Data Events -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; --- Constants - -(def +animation-timeout+ 600) - -;; --- Main API - -(declare hide) -(declare show) -(declare show?) - -(defn error - [message & {:keys [timeout] :or {timeout 3000}}] - (show {:content message - :type :error - :timeout timeout})) - -(defn info - [message & {:keys [timeout] :or {timeout 3000}}] - (show {:content message - :type :info - :timeout timeout})) - -(defn dialog - [message & {:keys [on-accept on-cancel]}] - (show {:content message - :on-accept on-accept - :on-cancel on-cancel - :timeout js/Number.MAX_SAFE_INTEGER - :type :dialog})) - -;; --- Show Event - -(defn show - [data] - (ptk/reify ::show - ptk/UpdateEvent - (update [_ state] - (let [message (assoc data :state :visible)] - (assoc state :message message))) - - ptk/WatchEvent - (watch [_ state s] - (let [stoper (->> (rx/filter show? s) - (rx/take 1))] - (->> (rx/of (hide)) - (rx/delay (:timeout data)) - (rx/take-until stoper)))))) - -(defn show? - [v] - (= ::show (ptk/type v))) - -;; --- Hide Event - -(defn hide - [] - (reify - ptk/UpdateEvent - (update [_ state] - (update state :message assoc :state :hide)) - - ptk/WatchEvent - (watch [_ state stream] - (->> (rx/of #(dissoc % :message)) - (rx/delay +animation-timeout+))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; UI Components -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; --- Notification Component - -(mf/defc notification-box - [{:keys [message on-close] :as message}] - (let [type (:type message) - classes (classnames :error (= type :error) - :info (= type :info) - :hide-message (= (:state message) :hide) - :quick true)] - [:div.message {:class classes} - [:div.message-body - [:span.close {:on-click on-close} i/close] - [:span (:content message)]]])) - -;; --- Dialog Component - -(mf/defc dialog-box - [{:keys [on-accept on-cancel on-close message] :as props}] - (let [classes (classnames :info true - :hide-message (= (:state message) :hide))] - (letfn [(accept [event] - (dom/prevent-default event) - (on-accept) - (ts/schedule 0 on-close)) - - (cancel [event] - (dom/prevent-default event) - (when on-cancel - (on-cancel)) - (ts/schedule 0 on-close))] - [:div.message {:class classes} - [:div.message-body - [:span.close {:on-click cancel} i/close] - [:span (:content message)] - [:div.message-action - [:a.btn-transparent.btn-small - {:on-click accept} - (tr "ds.accept")] - [:a.btn-transparent.btn-small - {:on-click cancel} - (tr "ds.cancel")]]]]))) - -;; --- Main Component (entry point) - -(mf/defc messages-widget - [{:keys [message] :as props}] - (case (:type message) - :error (mf/element notification-box props) - :info (mf/element notification-box props) - :dialog (mf/element dialog-box props) - nil))