diff --git a/backend/src/uxbox/http/handlers.clj b/backend/src/uxbox/http/handlers.clj
index eb83d69df..b1403d8ab 100644
--- a/backend/src/uxbox/http/handlers.clj
+++ b/backend/src/uxbox/http/handlers.clj
@@ -17,26 +17,25 @@
[vertx.web :as vw]
[vertx.eventbus :as ve]))
-(def mutation-types-hierarchy
- (-> (make-hierarchy)
- (derive :login ::unauthenticated)
- (derive :logout ::unauthenticated)
- (derive :register-profile ::unauthenticated)
- (derive :request-profile-recovery ::unauthenticated)
- (derive :recover-profile ::unauthenticated)
- (derive :create-demo-profile ::unauthenticated)))
-
-(def query-types-hierarchy
- (make-hierarchy))
+(def unauthorized-services
+ #{:create-demo-profile
+ :logout
+ :profile
+ :recover-profile
+ :register-profile
+ :request-profile-recovery
+ :viewer-bundle
+ :login})
(defn query-handler
[req]
(let [type (keyword (get-in req [:path-params :type]))
data (merge (:params req)
- {::sq/type type
- :profile-id (:profile-id req)})]
+ {::sq/type type})
+ data (cond-> data
+ (:profile-id req) (assoc :profile-id (:profile-id req)))]
(if (or (:profile-id req)
- (isa? query-types-hierarchy type ::unauthenticated))
+ (contains? unauthorized-services type))
(-> (sq/handle (with-meta data {:req req}))
(p/then' (fn [result]
{:status 200
@@ -51,10 +50,11 @@
data (merge (:params req)
(:body-params req)
(:uploads req)
- {::sm/type type
- :profile-id (:profile-id req)})]
+ {::sm/type type})
+ data (cond-> data
+ (:profile-id req) (assoc :profile-id (:profile-id req)))]
(if (or (:profile-id req)
- (isa? mutation-types-hierarchy type ::unauthenticated))
+ (contains? unauthorized-services type))
(-> (sm/handle (with-meta data {:req req}))
(p/then' (fn [result]
{:status 200 :body result})))
diff --git a/backend/src/uxbox/services/mutations/profile.clj b/backend/src/uxbox/services/mutations/profile.clj
index 5e30d5108..c5b00e599 100644
--- a/backend/src/uxbox/services/mutations/profile.clj
+++ b/backend/src/uxbox/services/mutations/profile.clj
@@ -91,15 +91,6 @@
(db/query-one conn [sql:profile-by-email email]))
-;; --- Mutation: Add additional email
-;; TODO
-
-;; --- Mutation: Mark email as main email
-;; TODO
-
-;; --- Mutation: Verify email (or maybe query?)
-;; TODO
-
;; --- Mutation: Update Profile (own)
(def ^:private sql:update-profile
@@ -158,6 +149,7 @@
(update-password conn params)))
+
;; --- Mutation: Update Photo
(declare upload-photo)
diff --git a/backend/src/uxbox/services/queries/profile.clj b/backend/src/uxbox/services/queries/profile.clj
index d15e19b44..c7a75aab4 100644
--- a/backend/src/uxbox/services/queries/profile.clj
+++ b/backend/src/uxbox/services/queries/profile.clj
@@ -15,6 +15,7 @@
[uxbox.images :as images]
[uxbox.services.queries :as sq]
[uxbox.services.util :as su]
+ [uxbox.util.uuid :as uuid]
[uxbox.util.blob :as blob]))
;; --- Helpers & Specs
@@ -32,11 +33,19 @@
;; --- Query: Profile (own)
-(defn retrieve-profile
- [conn id]
- (let [sql "select * from profile where id=$1 and deleted_at is null"]
- (db/query-one db/pool [sql id])))
+(declare retrieve-profile)
+(declare retrieve-additional-data)
+(s/def ::profile
+ (s/keys :opt-un [::profile-id]))
+
+(sq/defquery ::profile
+ [{:keys [profile-id] :as params}]
+ (if profile-id
+ (db/with-atomic [conn db/pool]
+ (retrieve-profile conn profile-id))
+ {:id uuid/zero
+ :fullname "Anonymous User"}))
;; NOTE: this query make the assumption that union all preserves the
;; order so the first id will always be the team id and the second the
@@ -65,18 +74,19 @@
{:default-team-id (:id team)
:default-project-id (:id project)}))))
-(s/def ::profile
- (s/keys :req-un [::profile-id]))
+(defn retrieve-profile-data
+ [conn id]
+ (let [sql "select * from profile where id=$1 and deleted_at is null"]
+ (db/query-one conn [sql id])))
-(sq/defquery ::profile
- [{:keys [profile-id] :as params}]
- (db/with-atomic [conn db/pool]
- (p/let [prof (-> (retrieve-profile conn profile-id)
- (p/then' su/raise-not-found-if-nil)
- (p/then' strip-private-attrs)
- (p/then' #(images/resolve-media-uris % [:photo :photo-uri])))
- addt (retrieve-additional-data conn profile-id)]
- (merge prof addt))))
+(defn retrieve-profile
+ [conn id]
+ (p/let [prof (-> (retrieve-profile-data conn id)
+ (p/then' su/raise-not-found-if-nil)
+ (p/then' strip-private-attrs)
+ (p/then' #(images/resolve-media-uris % [:photo :photo-uri])))
+ addt (retrieve-additional-data conn id)]
+ (merge prof addt)))
;; --- Attrs Helpers
diff --git a/frontend/resources/images/icons/full-screen-off.svg b/frontend/resources/images/icons/full-screen-off.svg
new file mode 100644
index 000000000..47e7db42c
--- /dev/null
+++ b/frontend/resources/images/icons/full-screen-off.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/frontend/resources/images/icons/full-screen.svg b/frontend/resources/images/icons/full-screen.svg
index 47e7db42c..252357a17 100644
--- a/frontend/resources/images/icons/full-screen.svg
+++ b/frontend/resources/images/icons/full-screen.svg
@@ -1,3 +1,3 @@
\ No newline at end of file
diff --git a/frontend/resources/styles/common/framework.scss b/frontend/resources/styles/common/framework.scss
index 3cfb82e03..80db6b5fc 100644
--- a/frontend/resources/styles/common/framework.scss
+++ b/frontend/resources/styles/common/framework.scss
@@ -25,7 +25,7 @@
flex-shrink: 0;
}
&.btn-small {
- font-size: $fs12;
+ font-size: $fs13;
padding: .7rem 1rem;
line-height: 1.15;
}
diff --git a/frontend/resources/styles/main.scss b/frontend/resources/styles/main.scss
index 545e75779..6ea6dd0bf 100644
--- a/frontend/resources/styles/main.scss
+++ b/frontend/resources/styles/main.scss
@@ -45,7 +45,7 @@
@import 'main/partials/main-bar';
@import 'main/partials/workspace';
-@import 'main/partials/workspace-bar';
+@import 'main/partials/workspace-header';
@import 'main/partials/workspace-libraries';
@import 'main/partials/tool-bar';
@import 'main/partials/project-bar';
@@ -71,6 +71,7 @@
@import 'main/partials/debug-icons-preview';
@import 'main/partials/editable-label';
@import 'main/partials/tab-container';
+@import "main/partials/zoom-widget";
@import "main/partials/viewer-header";
@import "main/partials/viewer-thumbnails";
@import "main/partials/viewer";
diff --git a/frontend/resources/styles/main/partials/viewer-header.scss b/frontend/resources/styles/main/partials/viewer-header.scss
index 130274e78..4372e4837 100644
--- a/frontend/resources/styles/main/partials/viewer-header.scss
+++ b/frontend/resources/styles/main/partials/viewer-header.scss
@@ -9,6 +9,10 @@
z-index: 12;
justify-content: space-between;
+ a {
+ font-size: $fs13;
+ }
+
.main-icon {
align-items: center;
background-color: $color-gray-60;
@@ -85,9 +89,13 @@
align-items: center;
display: flex;
width: 300px;
- justify-content: space-between;
+ justify-content: flex-end;
position: relative;
+ > * {
+ margin-left: $big;
+ }
+
.btn-share {
display: flex;
align-items: center;
@@ -107,6 +115,10 @@
padding: 0.4rem 1rem;
}
+ .btn-primary.btn-small {
+ height: 25px;
+ }
+
.btn-fullscreen {
align-items: center;
background-color: $color-gray-60;
@@ -134,23 +146,25 @@
}
.share-link-dropdown {
- position: absolute;
- left: -180px;
- top: 45px;
-
- background-color: $color-gray-50;
+ background-color: $color-white;
+ border-radius: $br-small;
+ box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
display: flex;
flex-direction: column;
-
+ left: -180px;
+ position: absolute;
padding: 1rem;
+ top: 45px;
width: 400px;
.share-link-title {
- font-size: 18px;
+ color: $color-black;
+ font-size: $fs15;
padding-bottom: 1rem;
}
.share-link-subtitle {
+ color: $color-gray-40;
padding-bottom: 1rem;
}
@@ -168,111 +182,50 @@
}
.share-link-input {
- display: flex;
- justify-content: space-between;
- padding: $small;
- align-items: center;
- border: 1px solid $color-gray-30;
+ border: 1px solid $color-gray-20;
border-radius: 3px;
+ display: flex;
+ height: 40px;
+ justify-content: space-between;
margin-bottom: 1rem;
+ padding: 9px $small;
+ overflow: hidden;
.link {
+ color: $color-gray-50;
+ line-height: 1.5;
user-select: all;
+ overflow: hidden;
}
- svg {
- width: 20px;
- height: 20px;
- fill: $color-gray-20;
- stroke: $color-gray-20;
+ .link-button {
+ color: $color-primary-dark;
+ cursor: pointer;
+ flex-shrink: 0;
+ font-size: $fs15;
+
+ &:hover {
+ color: $color-black;
+ }
}
}
+ &:before {
+ background-color: $color-white;
+ content: "";
+ height: 16px;
+ left: 53%;
+ position: absolute;
+ transform: rotate(45deg);
+ top: -5px;
+ width: 16px;
+ }
+
}
- .zoom-widget {
- cursor: pointer;
-
- align-items: center;
- display: flex;
- position: relative;
-
- .input-container {
- display: flex;
- }
-
- span {
- color: $color-gray-10;
- font-size: $fs15;
- margin-left: $x-small;
- }
-
- .dropdown-button svg {
- fill: $color-gray-10;
- height: 10px;
- width: 10px;
- }
-
- .zoom-dropdown {
- position: absolute;
- right: -25px;
- top: 45px;
- z-index: 12;
- width: 150px;
-
- background-color: $color-white;
- border-radius: $br-small;
- box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
-
- li {
- color: $color-gray-60;
- cursor: pointer;
- font-size: $fs12;
- display: flex;
- padding: $small;
-
- span {
- color: $color-gray-40;
- font-size: $fs12;
- margin-left: auto;
- }
-
- &:hover {
- background-color: $color-primary-lighter;
- }
-
- }
- }
-
- .add-zoom,
- .remove-zoom {
- align-items: center;
- background-color: $color-gray-60;
- border-radius: $br-small;
- cursor: pointer;
- color: $color-gray-20;
- display: flex;
- opacity: 0;
- flex-shrink: 0;
- font-size: $fs20;
- font-weight: bold;
- height: 20px;
- justify-content: center;
- width: 20px;
-
- &:hover {
- color: $color-primary;
- }
-
- }
-
- &:hover {
- .add-zoom,
- .remove-zoom {
- opacity: 100%;
- }
- }
-
+ .zoom-dropdown {
+ left : 150px;
+ top: 45px;
}
.users-zone {
diff --git a/frontend/resources/styles/main/partials/workspace-bar.scss b/frontend/resources/styles/main/partials/workspace-bar.scss
deleted file mode 100644
index 52c129cd5..000000000
--- a/frontend/resources/styles/main/partials/workspace-bar.scss
+++ /dev/null
@@ -1,386 +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) 2015-2016 Andrey Antukh
-// Copyright (c) 2015-2016 Juan de la Cruz
-
-.workspace-bar {
- align-items: center;
- background-color: $color-gray-50;
- border-bottom: 1px solid $color-gray-60;
- display: flex;
- height: 40px;
- padding: $x-small $medium $x-small 55px;
- position: relative;
- z-index: 12;
-
- .preview {
- align-items: center;
- background-color: $color-gray-60;
- border-radius: $br-small;
- cursor: pointer;
- display: flex;
- height: 25px;
- justify-content: center;
- width: 25px;
-
- svg {
- fill: $color-gray-20;
- width: 15px;
- height: 15px;
- }
-
- &:hover {
- background-color: $color-primary;
-
- svg {
- fill: $color-gray-60;
- }
- }
- }
-
- .workspace-menu {
- position: absolute;
- top: 40px;
- left: 40px;
- width: 230px;
- z-index: 12;
- @include animation(0,.2s,fadeInDown);
-
- background-color: $color-white;
- border-radius: $br-small;
- box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
-
- li {
- cursor: pointer;
- font-size: $fs12;
- padding: $small $x-small;
-
- svg {
- fill: $color-gray-60;
- height: 12px;
- width: 12px;
- }
-
- span {
- color: $color-gray-60;
- margin: 0 $x-small;
- }
-
- &:hover {
- background-color: $color-primary-lighter;
- }
- }
- }
-
-
- .main-icon {
- align-items: center;
- background-color: $color-gray-60;
- cursor: pointer;
- display: flex;
- height: 100%;
- justify-content: center;
- left: 0;
- position: absolute;
- top: 0;
- width: 40px;
-
- a {
- height: 30px;
-
- svg {
- fill: $color-gray-30;
- height: 30px;
- width: 28px;
-
- }
-
- &:hover {
-
- svg {
- fill: $color-primary;
- }
-
- }
-
- }
-
- }
-
- .menu-btn {
- align-items: center;
- background-color: $color-gray-60;
- cursor: pointer;
- border-radius: $br-small;
- display: flex;
- margin-right: $x-small;
- padding: $x-small;
-
- svg {
- height: 15px;
- fill: $color-gray-20;
- width: 15px;
- }
-
- &:hover {
- background-color: $color-primary;
-
- svg {
- fill: $color-gray-60;
- }
- }
- }
-
- .project-tree-btn {
- align-items: center;
- cursor: pointer;
- display: flex;
- padding: $x-small;
-
- svg {
- fill: $color-gray-20;
- height: 20px;
- margin-right: $small;
- width: 20px;
- }
-
- span {
- color: $color-white;
- font-size: $fs14;
- overflow-x: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-
- &.project-name {
- color: $color-gray-20;
- margin-right: $x-small;
- }
- }
-
- }
-
- .workspace-options {
- display: flex;
- margin: auto;
- }
-
-}
-
-.zoom-input {
- align-items: center;
- display: flex;
- position: relative;
-
- span {
- color: $color-gray-10;
- font-size: $fs15;
- margin-left: $x-small;
- }
-
- .dropdown-button {
- svg {
- fill: $color-gray-10;
- height: 10px;
- width: 10px;
- }
- }
-
- .zoom-dropdown {
- position: absolute;
- right: 0;
- z-index: 12;
- width: 150px;
- @include animation(0,.2s,fadeInDown);
-
- background-color: $color-white;
- border-radius: $br-small;
- box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
-
- li {
- color: $color-gray-60;
- cursor: pointer;
- font-size: $fs12;
- display: flex;
- padding: $small;
-
- span {
- color: $color-gray-40;
- font-size: $fs12;
- margin-left: auto;
- }
-
- &:hover {
- background-color: $color-primary-lighter;
- }
-
- }
- }
-
- .add-zoom,
- .remove-zoom {
- align-items: center;
- background-color: $color-gray-60;
- border-radius: $br-small;
- cursor: pointer;
- color: $color-gray-20;
- display: flex;
- opacity: 0;
- flex-shrink: 0;
- font-size: $fs20;
- font-weight: bold;
- height: 20px;
- justify-content: center;
- width: 20px;
-
- &:hover {
- color: $color-primary;
- }
-
- }
-
- &:hover {
- .add-zoom,
- .remove-zoom {
- opacity: 100%;
- }
- }
-
-}
-
-.options-btn {
- align-items: center;
- border-right: 4px double $color-gray-60;
- display: flex;
- margin: 0;
-
- &:last-child {
- border: none;
- }
-
- li {
- align-items: center;
- background-color: $color-gray-60;
- border: 1px solid transparent;
- border-radius: $br-small;
- cursor: pointer;
- display: flex;
- flex-shrink: 0;
- height: 30px;
- justify-content: center;
- margin: 0 $small;
- position: relative;
- width: 30px;
-
- a {
- padding-top: 6px;
- }
-
- svg {
- fill: $color-gray-20;
- height: 18px;
- width: 18px;
- }
-
- &:hover {
- background-color: $color-gray-10;
- border-color: $color-gray-60;
- }
-
- &.selected {
- background-color: $color-primary;
-
- svg {
- fill: $color-white;
- }
-
- }
-
- }
-
-}
-
-.secondary-options {
- align-items: center;
- display: flex;
-
- .view-mode {
- background-color: $color-gray-20;
- align-items: center;
- border-radius: $br-small;
- cursor: pointer;
- display: flex;
- flex-shrink: 0;
- height: 30px;
- justify-content: center;
- margin: 0 $small;
- position: relative;
- width: 30px;
-
- a {
- padding-top: 6px;
- }
-
- svg {
- fill: $color-gray-60;
- height: 18px;
- width: 18px;
- }
-
- &:hover {
- background-color: $color-primary;
-
- svg {
- fill: $color-gray-60;
- }
-
- }
-
- }
-
-}
-
-.user-multi {
- align-items: center;
- cursor: pointer;
- display: flex;
- margin: 0;
-
- li {
- margin-left: $small;
- position: relative;
-
- img {
- border: 3px solid #f3dd14;
- border-radius: 50%;
- flex-shrink: 0;
- height: 25px;
- width: 25px;
- }
- }
-}
-
-.multiuser-cursor {
- align-items: center;
- display: flex;
- left: 0;
- position: absolute;
- top: 0;
- z-index: 10000;
-
- svg {
- height: 15px;
- fill: #f3dd14;
- width: 15px;
- }
-
- span {
- background-color: #f3dd14;
- border-radius: $br-small;
- color: $color-black;
- font-size: $fs12;
- margin-left: $small;
- padding: $x-small;
- }
-}
diff --git a/frontend/resources/styles/main/partials/workspace-header.scss b/frontend/resources/styles/main/partials/workspace-header.scss
new file mode 100644
index 000000000..638d0849f
--- /dev/null
+++ b/frontend/resources/styles/main/partials/workspace-header.scss
@@ -0,0 +1,209 @@
+// 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) 2015-2016 Andrey Antukh
+// Copyright (c) 2015-2016 Juan de la Cruz
+
+.workspace-header {
+ align-items: center;
+ background-color: $color-gray-50;
+ border-bottom: 1px solid $color-gray-60;
+ display: flex;
+ height: 40px;
+ padding: $x-small $medium $x-small 55px;
+ position: relative;
+ z-index: 12;
+ justify-content: space-between;
+
+ .main-icon {
+ align-items: center;
+ background-color: $color-gray-60;
+ cursor: pointer;
+ display: flex;
+ height: 100%;
+ justify-content: center;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 40px;
+
+ a {
+ height: 30px;
+
+ svg {
+ fill: $color-gray-30;
+ height: 30px;
+ width: 28px;
+
+ }
+
+ &:hover {
+
+ svg {
+ fill: $color-primary;
+ }
+
+ }
+
+ }
+ }
+
+ .menu-section {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ }
+
+ .users-section {
+ display: flex;
+ }
+
+ .options-section {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ position: relative;
+
+ > * {
+ margin-left: $big;
+ }
+
+ .zoom-dropdown {
+ top: 45px;
+ left: -30px;
+ }
+ }
+
+ .menu-button {
+ align-items: center;
+ background-color: $color-gray-60;
+ cursor: pointer;
+ border-radius: $br-small;
+ display: flex;
+ margin-right: $x-small;
+ padding: $x-small;
+ width: 25px;
+ height: 25px;
+
+ svg {
+ height: 15px;
+ fill: $color-gray-20;
+ width: 15px;
+ }
+
+ &:hover {
+ background-color: $color-primary;
+
+ svg {
+ fill: $color-gray-60;
+ }
+ }
+ }
+
+ .project-tree {
+ align-items: center;
+ cursor: pointer;
+ display: flex;
+ padding: $x-small;
+
+ svg {
+ fill: $color-gray-20;
+ height: 20px;
+ margin-right: $small;
+ width: 20px;
+ }
+
+ span {
+ color: $color-white;
+ font-size: $fs14;
+ overflow-x: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ &.project-name {
+ color: $color-gray-20;
+ margin-right: $x-small;
+ }
+ }
+ }
+
+ .preview-button {
+ align-items: center;
+ background-color: $color-gray-60;
+ border-radius: $br-small;
+ cursor: pointer;
+ display: flex;
+ height: 25px;
+ justify-content: center;
+ width: 25px;
+
+ svg {
+ fill: $color-gray-20;
+ width: 15px;
+ height: 15px;
+ }
+
+ &:hover {
+ background-color: $color-primary;
+
+ svg {
+ fill: $color-gray-60;
+ }
+ }
+ }
+
+ .menu {
+ position: absolute;
+ top: 40px;
+ left: 40px;
+ width: 230px;
+ z-index: 12;
+ @include animation(0,.2s,fadeInDown);
+
+ background-color: $color-white;
+ border-radius: $br-small;
+ box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
+
+ li {
+ cursor: pointer;
+ font-size: $fs12;
+ padding: $small $x-small;
+
+ svg {
+ fill: $color-gray-60;
+ height: 12px;
+ width: 12px;
+ }
+
+ span {
+ color: $color-gray-60;
+ margin: 0 $x-small;
+ }
+
+ &:hover {
+ background-color: $color-primary-lighter;
+ }
+ }
+ }
+
+ .active-users {
+ align-items: center;
+ cursor: pointer;
+ display: flex;
+ margin: 0;
+
+ li {
+ margin-left: $small;
+ position: relative;
+
+ img {
+ border: 3px solid #f3dd14;
+ border-radius: 50%;
+ flex-shrink: 0;
+ height: 25px;
+ width: 25px;
+ }
+ }
+ }
+}
diff --git a/frontend/resources/styles/main/partials/workspace.scss b/frontend/resources/styles/main/partials/workspace.scss
index ff623ca27..b7ab8f403 100644
--- a/frontend/resources/styles/main/partials/workspace.scss
+++ b/frontend/resources/styles/main/partials/workspace.scss
@@ -183,3 +183,28 @@
fill: $color-primary-dark;
}
+
+
+.multiuser-cursor {
+ align-items: center;
+ display: flex;
+ left: 0;
+ position: absolute;
+ top: 0;
+ z-index: 10000;
+
+ svg {
+ height: 15px;
+ fill: #f3dd14;
+ width: 15px;
+ }
+
+ span {
+ background-color: #f3dd14;
+ border-radius: $br-small;
+ color: $color-black;
+ font-size: $fs12;
+ margin-left: $small;
+ padding: $x-small;
+ }
+}
diff --git a/frontend/resources/styles/main/partials/zoom-widget.scss b/frontend/resources/styles/main/partials/zoom-widget.scss
new file mode 100644
index 000000000..95bd8788b
--- /dev/null
+++ b/frontend/resources/styles/main/partials/zoom-widget.scss
@@ -0,0 +1,45 @@
+.zoom-widget {
+ cursor: pointer;
+ display: flex;
+
+ span {
+ color: $color-gray-10;
+ font-size: $fs14;
+ margin-left: $x-small;
+ }
+
+ .dropdown-button svg {
+ fill: $color-gray-10;
+ height: 10px;
+ width: 10px;
+ }
+
+ .zoom-dropdown {
+ position: absolute;
+ z-index: 12;
+ width: 150px;
+
+ background-color: $color-white;
+ border-radius: $br-small;
+ box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
+
+ li {
+ color: $color-gray-60;
+ cursor: pointer;
+ font-size: $fs12;
+ display: flex;
+ padding: $small;
+
+ span {
+ color: $color-gray-40;
+ font-size: $fs12;
+ margin-left: auto;
+ }
+
+ &:hover {
+ background-color: $color-primary-lighter;
+ }
+
+ }
+ }
+}
diff --git a/frontend/src/uxbox/builtins/icons.cljs b/frontend/src/uxbox/builtins/icons.cljs
index 069f01f84..5636956f1 100644
--- a/frontend/src/uxbox/builtins/icons.cljs
+++ b/frontend/src/uxbox/builtins/icons.cljs
@@ -39,6 +39,7 @@
(def folder (icon-xref :folder))
(def folder-zip (icon-xref :folder-zip))
(def full-screen (icon-xref :full-screen))
+(def full-screen-off (icon-xref :full-screen-off))
(def grid (icon-xref :grid))
(def grid-snap (icon-xref :grid-snap))
(def icon-set (icon-xref :icon-set))
@@ -103,7 +104,7 @@
{::mf/wrap-props false}
[props]
[:section.debug-icons-preview
- (for [[key val] (ns-publics 'uxbox.builtins.icons)]
+ (for [[key val] (sort-by first (ns-publics 'uxbox.builtins.icons))]
(when (not= key 'debug-icons-preview)
[:div.icon-item {:key key}
(deref val)
diff --git a/frontend/src/uxbox/main/data/users.cljs b/frontend/src/uxbox/main/data/users.cljs
index f12dd1656..0a6e4158e 100644
--- a/frontend/src/uxbox/main/data/users.cljs
+++ b/frontend/src/uxbox/main/data/users.cljs
@@ -18,23 +18,25 @@
;; --- Common Specs
-(s/def ::id uuid?)
-(s/def ::fullname string?)
+(s/def ::id ::us/uuid)
+(s/def ::fullname ::us/string)
(s/def ::email ::us/email)
-(s/def ::password string?)
-(s/def ::language string?)
-(s/def ::photo string?)
-(s/def ::created-at inst?)
-(s/def ::password-1 string?)
-(s/def ::password-2 string?)
-(s/def ::password-old string?)
+(s/def ::password ::us/string)
+(s/def ::language ::us/string)
+(s/def ::photo ::us/string)
+(s/def ::created-at ::us/inst)
+(s/def ::password-1 ::us/string)
+(s/def ::password-2 ::us/string)
+(s/def ::password-old ::us/string)
+(s/def ::lang (s/nilable ::us/string))
(s/def ::profile
- (s/keys :req-un [::id
+ (s/keys :req-un [::id]
+ :opt-un [::created-at
::fullname
+ ::photo
::email
- ::created-at
- ::photo]))
+ ::lang]))
;; --- Profile Fetched
diff --git a/frontend/src/uxbox/main/data/viewer.cljs b/frontend/src/uxbox/main/data/viewer.cljs
index 26fe30479..d3ad06487 100644
--- a/frontend/src/uxbox/main/data/viewer.cljs
+++ b/frontend/src/uxbox/main/data/viewer.cljs
@@ -41,7 +41,7 @@
(declare bundle-fetched)
(defn initialize
- [page-id]
+ [page-id share-token]
(ptk/reify ::initialize
ptk/UpdateEvent
(update [_ state]
@@ -49,18 +49,21 @@
ptk/WatchEvent
(watch [_ state stream]
- (rx/of (fetch-bundle page-id)))))
+ (rx/of (fetch-bundle page-id share-token)))))
;; --- Data Fetching
(defn fetch-bundle
- [page-id]
+ [page-id share-token]
(ptk/reify ::fetch-file
ptk/WatchEvent
(watch [_ state stream]
- (->> (rp/query :viewer-bundle {:page-id page-id})
- (rx/map bundle-fetched)))))
-
+ (let [params (cond-> {:page-id page-id}
+ (string? share-token) (assoc :share-token share-token))]
+ (->> (rp/query :viewer-bundle params)
+ (rx/map bundle-fetched)
+ (rx/catch (fn [error-data]
+ (rx/of (rt/nav :not-found)))))))))
(defn- extract-frames
[page]
diff --git a/frontend/src/uxbox/main/refs.cljs b/frontend/src/uxbox/main/refs.cljs
index 19da8d924..2a8fab50c 100644
--- a/frontend/src/uxbox/main/refs.cljs
+++ b/frontend/src/uxbox/main/refs.cljs
@@ -5,7 +5,7 @@
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
-;; Copyright (c) 2017-2019 Andrey Antukh
+;; Copyright (c) 2020 UXBOX Labs SL
(ns uxbox.main.refs
"A collection of derived refs."
diff --git a/frontend/src/uxbox/main/ui.cljs b/frontend/src/uxbox/main/ui.cljs
index 8eb0cb911..7a0cf1602 100644
--- a/frontend/src/uxbox/main/ui.cljs
+++ b/frontend/src/uxbox/main/ui.cljs
@@ -101,12 +101,6 @@
:profile-recovery
[:& profile-recovery-page]
- :viewer
- (let [index (d/parse-integer (get-in route [:params :query :index]))
- page-id (uuid (get-in route [:params :path :page-id]))]
- [:& viewer-page {:page-id page-id
- :index index}])
-
(:settings-profile
:settings-password)
[:& settings/settings {:route route}]
@@ -126,6 +120,14 @@
:dashboard-library-palettes-index)
[:& dashboard {:route route}]
+ :viewer
+ (let [index (d/parse-integer (get-in route [:params :query :index]))
+ token (get-in route [:params :query :token])
+ page-id (uuid (get-in route [:params :path :page-id]))]
+ [:& viewer-page {:page-id page-id
+ :index index
+ :token token}])
+
:workspace
(let [project-id (uuid (get-in route [:params :path :project-id]))
file-id (uuid (get-in route [:params :path :file-id]))
diff --git a/frontend/src/uxbox/main/ui/viewer.cljs b/frontend/src/uxbox/main/ui/viewer.cljs
index 87ac9f540..f9a71c21b 100644
--- a/frontend/src/uxbox/main/ui/viewer.cljs
+++ b/frontend/src/uxbox/main/ui/viewer.cljs
@@ -96,8 +96,11 @@
(l/derive st/state)))
(mf/defc viewer-page
- [{:keys [page-id index] :as props}]
- (mf/use-effect (mf/deps page-id) #(st/emit! (dv/initialize page-id)))
+ [{:keys [page-id index token] :as props}]
+ (mf/use-effect
+ (mf/deps page-id token)
+ #(st/emit! (dv/initialize page-id token)))
+
(let [data (mf/deref viewer-data-ref)
local (mf/deref viewer-local-ref)]
(when data
diff --git a/frontend/src/uxbox/main/ui/viewer/header.cljs b/frontend/src/uxbox/main/ui/viewer/header.cljs
index 4964ed707..f4377ab1f 100644
--- a/frontend/src/uxbox/main/ui/viewer/header.cljs
+++ b/frontend/src/uxbox/main/ui/viewer/header.cljs
@@ -17,43 +17,18 @@
[uxbox.builtins.icons :as i]
[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.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))
-(mf/defc zoom-widget
- {:wrap [mf/memo]}
- [{:keys [zoom] :as props}]
- (let [show-dropdown? (mf/use-state false)
- increase #(st/emit! dv/increase-zoom)
- decrease #(st/emit! dv/decrease-zoom)
- zoom-to-50 #(st/emit! dv/zoom-to-50)
- zoom-to-100 #(st/emit! dv/reset-zoom)
- zoom-to-200 #(st/emit! dv/zoom-to-200)]
- [:div.zoom-widget
- [:span.add-zoom {:on-click decrease} "-"]
- [:div.input-container {:on-click #(reset! show-dropdown? true)}
- [:span {} (str (mth/round (* 100 zoom)) "%")]
- [:span.dropdown-button i/arrow-down]
- [:& dropdown {:show @show-dropdown?
- :on-close #(reset! show-dropdown? false)}
- [:ul.zoom-dropdown
- [:li {:on-click increase}
- "Zoom in" [:span "+"]]
- [:li {:on-click decrease}
- "Zoom out" [:span "-"]]
- [:li {:on-click zoom-to-50}
- "Zoom to 50%"]
- [:li {:on-click zoom-to-100}
- "Zoom to 100%" [:span "Shift + 0"]]
- [:li {:on-click zoom-to-200}
- "Zoom to 200%"]]]]
- [:span.remove-zoom {:on-click increase} "+"]]))
(mf/defc share-link
[{:keys [page] :as props}]
@@ -64,12 +39,11 @@
create #(st/emit! dv/create-share-link)
delete #(st/emit! dv/delete-share-link)
href (.-href js/location)]
-
[:*
- [:span.btn-share.tooltip.tooltip-bottom
+ [:span.btn-primary.btn-small
{:alt "Share link"
:on-click #(swap! show-dropdown? not)}
- i/exit]
+ "Share link"]
[:& dropdown {:show @show-dropdown?
:on-close #(swap! show-dropdown? not)
@@ -78,28 +52,35 @@
[:span.share-link-title "Share link"]
[:div.share-link-input
(if (string? token)
- [:span.link (str href "&" token)]
- [:span "Share link will apear here"])
- i/chain]
+ [: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"]
[:div.share-link-buttons
(if (string? token)
[:button.btn-delete {:on-click delete} "Remove link"]
[:button.btn-primary {:on-click create} "Create link"])]]]]))
-
(mf/defc header
[{:keys [data index local fullscreen? toggle-fullscreen] :as props}]
(let [{:keys [project file page frames]} data
total (count frames)
on-click #(st/emit! dv/toggle-thumbnails-panel)
+
+ profile (mf/deref refs/profile)
+ anonymous? (= uuid/zero (:id profile))
+
+ project-id (get-in data [:project :id])
+ file-id (get-in data [:file :id])
+ page-id (get-in data [:page :id])
+
on-edit #(st/emit! (rt/nav :workspace
- {:project-id (get-in data [:project :id])
- :file-id (get-in data [:file :id])}
- {:page-id (get-in data [:page :id])}))]
+ {:project-id project-id
+ :file-id file-id}
+ {:page-id page-id}))]
[:header.viewer-header
[:div.main-icon
- [:a i/logo-icon]]
+ [:a {:on-click on-edit} i/logo-icon]]
[:div.sitemap-zone {:alt (tr "header.sitemap")
:on-click on-click}
@@ -112,13 +93,25 @@
[:span.counters (str (inc index) " / " total)]]
[:div.options-zone
- [:& share-link {:page (:page data)}]
- [:span.btn-primary {:on-click on-edit} "Edit page"]
- [:& zoom-widget {:zoom (:zoom local)}]
+ (when-not anonymous?
+ [:& share-link {:page (:page data)}])
+ (when-not anonymous?
+ [:a {:on-click on-edit} "Edit page"])
+
+ [:& zoom-widget
+ {:zoom (:zoom local)
+ :on-increase #(st/emit! dv/increase-zoom)
+ :on-decrease #(st/emit! dv/decrease-zoom)
+ :on-zoom-to-50 #(st/emit! dv/zoom-to-50)
+ :on-zoom-to-100 #(st/emit! dv/reset-zoom)
+ :on-zoom-to-200 #(st/emit! dv/zoom-to-200)}]
+
[:span.btn-fullscreen.tooltip.tooltip-bottom
- {:alt "Full screen"
+ {:alt "Full Screen"
:on-click toggle-fullscreen}
- i/full-screen]
+ (if fullscreen?
+ i/full-screen-off
+ i/full-screen)]
]]))
diff --git a/frontend/src/uxbox/main/ui/workspace/header.cljs b/frontend/src/uxbox/main/ui/workspace/header.cljs
index 10bd1dc65..425fcec7b 100644
--- a/frontend/src/uxbox/main/ui/workspace/header.cljs
+++ b/frontend/src/uxbox/main/ui/workspace/header.cljs
@@ -30,33 +30,38 @@
(mf/defc zoom-widget
{:wrap [mf/memo]}
- [props]
- (let [zoom (mf/deref refs/selected-zoom)
- show-dropdown? (mf/use-state false)
- increase #(st/emit! dw/increase-zoom)
- decrease #(st/emit! dw/decrease-zoom)
- zoom-to-50 #(st/emit! dw/zoom-to-50)
- zoom-to-100 #(st/emit! dw/reset-zoom)
- zoom-to-200 #(st/emit! dw/zoom-to-200)]
- [:div.zoom-input
- [:span.add-zoom {:on-click decrease} "-"]
- [:div {:on-click #(reset! show-dropdown? true)}
- [:span {} (str (mth/round (* 100 zoom)) "%")]
- [:span.dropdown-button i/arrow-down]
- [:& dropdown {:show @show-dropdown?
- :on-close #(reset! show-dropdown? false)}
- [:ul.zoom-dropdown
- [:li {:on-click increase}
- "Zoom in" [:span "+"]]
- [:li {:on-click decrease}
- "Zoom out" [:span "-"]]
- [:li {:on-click zoom-to-50}
- "Zoom to 50%" [:span "Shift + 0"]]
- [:li {:on-click zoom-to-100}
- "Zoom to 100%" [:span "Shift + 1"]]
- [:li {:on-click zoom-to-200}
- "Zoom to 200%" [:span "Shift + 2"]]]]]
- [:span.remove-zoom {:on-click increase} "+"]]))
+ [{:keys [zoom
+ on-increase
+ on-decrease
+ on-zoom-to-50
+ on-zoom-to-100
+ on-zoom-to-200]
+ :as props}]
+ (let [show-dropdown? (mf/use-state false)
+ ;; increase #(st/emit! dv/increase-zoom)
+ ;; decrease #(st/emit! dv/decrease-zoom)
+ ;; zoom-to-50 #(st/emit! dv/zoom-to-50)
+ ;; zoom-to-100 #(st/emit! dv/reset-zoom)
+ ;; zoom-to-200 #(st/emit! dv/zoom-to-200)
+ ]
+ [:div.zoom-widget {:on-click #(reset! show-dropdown? true)}
+ [:span {} (str (mth/round (* 100 zoom)) "%")]
+ [:span.dropdown-button i/arrow-down]
+ [:& dropdown {:show @show-dropdown?
+ :on-close #(reset! show-dropdown? false)}
+ [:ul.zoom-dropdown
+ [:li {:on-click on-increase}
+ "Zoom in" [:span "+"]]
+ [:li {:on-click on-decrease}
+ "Zoom out" [:span "-"]]
+ [:li {:on-click on-zoom-to-50}
+ "Zoom to 50%"]
+ [:li {:on-click on-zoom-to-100}
+ "Zoom to 100%" [:span "Shift + 0"]]
+ [:li {:on-click on-zoom-to-200}
+ "Zoom to 200%"]]]]))
+
+
;; --- Header Users
@@ -77,7 +82,7 @@
[props]
(let [profile (mf/deref refs/profile)
users (mf/deref refs/workspace-users)]
- [:ul.user-multi
+ [:ul.active-users
[:& user-widget {:user profile :self? true}]
(for [id (->> (:active users)
(remove #(= % (:id profile))))]
@@ -85,16 +90,22 @@
:key id}])]))
(mf/defc menu
- [{:keys [layout] :as props}]
+ [{:keys [layout project file] :as props}]
(let [show-menu? (mf/use-state false)
+ toggle-sitemap #(st/emit! (dw/toggle-layout-flag :sitemap))
locale (i18n/use-locale)]
- [:*
- [:div.menu-btn {:on-click #(reset! show-menu? true)} i/actions]
+ [:div.menu-section
+ [:div.menu-button {:on-click #(reset! show-menu? true)} i/actions]
+ [:div.project-tree {:alt (t locale "header.sitemap")
+ :class (classnames :selected (contains? layout :sitemap))
+ :on-click toggle-sitemap}
+ [:span.project-name (:name project) " /"]
+ [:span (:name file)]]
[:& dropdown {:show @show-menu?
:on-close #(reset! show-menu? false)}
- [:ul.workspace-menu
+ [:ul.menu
[:li {:on-click #(st/emit! (dw/toggle-layout-flag :rules))}
[:span i/ruler]
[:span
@@ -139,28 +150,33 @@
(mf/defc header
[{:keys [page file layout project] :as props}]
- (let [go-to-dashboard #(st/emit! (rt/nav :dashboard-team {:team-id "self"}))
- toggle-sitemap #(st/emit! (dw/toggle-layout-flag :sitemap))
+ (let [locale (i18n/use-locale)
+ go-to-dashboard #(st/emit! (rt/nav :dashboard-team {:team-id "self"}))
+ zoom (mf/deref refs/selected-zoom)
locale (i18n/use-locale)
router (mf/deref router-ref)
view-url (rt/resolve router :viewer {:page-id (:id page)} {:index 0})]
- [:header.workspace-bar
+ [:header.workspace-header
[:div.main-icon
[:a {:on-click go-to-dashboard} i/logo-icon]]
- [:& menu {:layout layout}]
+ [:& menu {:layout layout
+ :project project
+ :file file}]
- [:div.project-tree-btn {:alt (tr "header.sitemap")
- :class (classnames :selected (contains? layout :sitemap))
- :on-click toggle-sitemap}
- [:span.project-name (:name project) " /"]
- [:span (:name file)]]
-
- [:div.workspace-options
+ [:div.users-section
[:& active-users]]
- [:& zoom-widget]
+ [:div.options-section
+ [:& zoom-widget
+ {:zoom zoom
+ :on-increase #(st/emit! dw/increase-zoom)
+ :on-decrease #(st/emit! dw/decrease-zoom)
+ :on-zoom-to-50 #(st/emit! dw/zoom-to-50)
+ :on-zoom-to-100 #(st/emit! dw/reset-zoom)
+ :on-zoom-to-200 #(st/emit! dw/zoom-to-200)}]
+
+ [:a.preview-button
+ {;; :target "__blank"
+ :href (str "#" view-url)} i/play]]]))
- [:a.preview {
- ;; :target "__blank"
- :href (str "#" view-url)} i/play]]))