♻️ Refactor messages component.

This commit is contained in:
Andrey Antukh 2020-04-08 16:39:54 +02:00
parent a0b70b7bbd
commit 02170a156e
24 changed files with 298 additions and 374 deletions

View file

@ -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);

View file

@ -75,6 +75,7 @@
@import "main/partials/viewer-header";
@import "main/partials/viewer-thumbnails";
@import "main/partials/viewer";
@import "main/partials/messages";
//#################################################
// Resources

View 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);
}
}

View file

@ -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]))

View file

@ -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))))))

View 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+)))))

View file

@ -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

View file

@ -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)

View file

@ -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}]

View file

@ -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]

View file

@ -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]]])

View file

@ -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]]]))

View file

@ -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]]])

View file

@ -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]]])

View file

@ -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]]])

View file

@ -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

View file

@ -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)))))

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -178,5 +178,6 @@
[:a.preview-button
{;; :target "__blank"
:alt (t locale "workspace.header.viewer")
:href (str "#" view-url)} i/play]]]))

View file

@ -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]]]]))

View file

@ -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))