mirror of
https://github.com/penpot/penpot.git
synced 2025-06-02 02:11:41 +02:00
♻️ Refactor messages component.
This commit is contained in:
parent
a0b70b7bbd
commit
02170a156e
24 changed files with 298 additions and 374 deletions
|
@ -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);
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
@import "main/partials/viewer-header";
|
||||
@import "main/partials/viewer-thumbnails";
|
||||
@import "main/partials/viewer";
|
||||
@import "main/partials/messages";
|
||||
|
||||
//#################################################
|
||||
// Resources
|
||||
|
|
74
frontend/resources/styles/main/partials/messages.scss
Normal file
74
frontend/resources/styles/main/partials/messages.scss
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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]))
|
||||
|
|
|
@ -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))))))
|
||||
|
|
50
frontend/src/uxbox/main/data/messages.cljs
Normal file
50
frontend/src/uxbox/main/data/messages.cljs
Normal file
|
@ -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+)))))
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]]])
|
||||
|
|
|
@ -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]]]))
|
||||
|
||||
|
|
|
@ -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]]])
|
||||
|
|
|
@ -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]]])
|
||||
|
|
|
@ -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]]])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))))
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -178,5 +178,6 @@
|
|||
|
||||
[:a.preview-button
|
||||
{;; :target "__blank"
|
||||
:alt (t locale "workspace.header.viewer")
|
||||
:href (str "#" view-url)} i/play]]]))
|
||||
|
||||
|
|
|
@ -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]]]]))
|
||||
|
|
|
@ -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 <niwi@niwi.nz>
|
||||
|
||||
(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))
|
Loading…
Add table
Add a link
Reference in a new issue