diff --git a/backend/src/uxbox/services/queries/colors.clj b/backend/src/uxbox/services/queries/colors.clj
index b1deb3dfb7..afe78209d5 100644
--- a/backend/src/uxbox/services/queries/colors.clj
+++ b/backend/src/uxbox/services/queries/colors.clj
@@ -50,7 +50,7 @@
(sq/defquery ::color-libraries
[{:keys [profile-id team-id]}]
(db/with-atomic [conn db/pool]
- (teams/check-edition-permissions! conn profile-id team-id)
+ (teams/check-read-permissions! conn profile-id team-id)
(db/query conn [sql:libraries team-id])))
@@ -66,7 +66,7 @@
[{:keys [profile-id id]}]
(db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn id)]
- (teams/check-edition-permissions! conn profile-id (:team-id lib))
+ (teams/check-read-permissions! conn profile-id (:team-id lib))
lib)))
(def ^:private sql:single-library
@@ -94,7 +94,7 @@
[{:keys [profile-id library-id] :as params}]
(db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn library-id)]
- (teams/check-edition-permissions! conn profile-id (:team-id lib))
+ (teams/check-read-permissions! conn profile-id (:team-id lib))
(retrieve-colors conn library-id))))
(def ^:private sql:colors
@@ -123,7 +123,7 @@
[{:keys [profile-id id] :as params}]
(db/with-atomic [conn db/pool]
(p/let [color (retrieve-color conn id)]
- (teams/check-edition-permissions! conn profile-id (:team-id color))
+ (teams/check-read-permissions! conn profile-id (:team-id color))
color)))
(def ^:private sql:single-color
diff --git a/backend/src/uxbox/services/queries/icons.clj b/backend/src/uxbox/services/queries/icons.clj
index b1922f37fe..deddf82b6e 100644
--- a/backend/src/uxbox/services/queries/icons.clj
+++ b/backend/src/uxbox/services/queries/icons.clj
@@ -56,8 +56,10 @@
(sq/defquery ::icon-libraries
[{:keys [profile-id team-id]}]
+ (println profile-id)
+ (println team-id)
(db/with-atomic [conn db/pool]
- (teams/check-edition-permissions! conn profile-id team-id)
+ (teams/check-read-permissions! conn profile-id team-id)
(db/query conn [sql:libraries team-id])))
@@ -73,7 +75,7 @@
[{:keys [profile-id id]}]
(db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn id)]
- (teams/check-edition-permissions! conn profile-id (:team-id lib))
+ (teams/check-read-permissions! conn profile-id (:team-id lib))
lib)))
(def ^:private sql:single-library
@@ -101,7 +103,7 @@
[{:keys [profile-id library-id] :as params}]
(db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn library-id)]
- (teams/check-edition-permissions! conn profile-id (:team-id lib))
+ (teams/check-read-permissions! conn profile-id (:team-id lib))
(-> (retrieve-icons conn library-id)
(p/then' (fn [rows] (mapv decode-row rows)))))))
@@ -131,7 +133,7 @@
[{:keys [profile-id id] :as params}]
(db/with-atomic [conn db/pool]
(p/let [icon (retrieve-icon conn id)]
- (teams/check-edition-permissions! conn profile-id (:team-id icon))
+ (teams/check-read-permissions! conn profile-id (:team-id icon))
(decode-row icon))))
(def ^:private sql:single-icon
diff --git a/backend/src/uxbox/services/queries/images.clj b/backend/src/uxbox/services/queries/images.clj
index a690a5cc1d..c6cd106a8f 100644
--- a/backend/src/uxbox/services/queries/images.clj
+++ b/backend/src/uxbox/services/queries/images.clj
@@ -40,7 +40,7 @@
(sq/defquery ::image-libraries
[{:keys [profile-id team-id]}]
(db/with-atomic [conn db/pool]
- (teams/check-edition-permissions! conn profile-id team-id)
+ (teams/check-read-permissions! conn profile-id team-id)
(db/query conn [sql:libraries team-id])))
@@ -55,7 +55,7 @@
[{:keys [profile-id id]}]
(db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn id)]
- (teams/check-edition-permissions! conn profile-id (:team-id lib))
+ (teams/check-read-permissions! conn profile-id (:team-id lib))
lib)))
(def ^:private sql:single-library
@@ -86,7 +86,7 @@
[{:keys [profile-id library-id] :as params}]
(db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn library-id)]
- (teams/check-edition-permissions! conn profile-id (:team-id lib))
+ (teams/check-read-permissions! conn profile-id (:team-id lib))
(-> (retrieve-images conn library-id)
(p/then' (fn [rows]
(->> rows
@@ -120,7 +120,7 @@
[{:keys [profile-id id] :as params}]
(db/with-atomic [conn db/pool]
(p/let [img (retrieve-image conn id)]
- (teams/check-edition-permissions! conn profile-id (:team-id img))
+ (teams/check-read-permissions! conn profile-id (:team-id img))
(-> img
(images/resolve-urls :path :uri)
(images/resolve-urls :thumb-path :thumb-uri)))))
diff --git a/backend/src/uxbox/services/queries/projects.clj b/backend/src/uxbox/services/queries/projects.clj
index ffd1ffb4dd..45d495b4cc 100644
--- a/backend/src/uxbox/services/queries/projects.clj
+++ b/backend/src/uxbox/services/queries/projects.clj
@@ -47,16 +47,37 @@
where team_id = $2
order by modified_at desc")
+(def ^:private sql:project-by-id
+ "select p.*
+ from project as p
+ inner join project_profile_rel as ppr on (ppr.project_id = p.id)
+ where ppr.profile_id = $1
+ and p.id = $2
+ and p.deleted_at is null
+ and (ppr.is_admin = true or
+ ppr.is_owner = true or
+ ppr.can_edit = true)")
+
(s/def ::team-id ::us/uuid)
(s/def ::profile-id ::us/uuid)
+(s/def ::project-id ::us/uuid)
(s/def ::projects-by-team
(s/keys :req-un [::profile-id ::team-id]))
+(s/def ::project-by-id
+ (s/keys :req-un [::profile-id ::project-id]))
+
(defn projects-by-team [profile-id team-id]
(db/query db/pool [sql:projects profile-id team-id]))
+(defn project-by-id [profile-id project-id]
+ (db/query-one db/pool [sql:project-by-id profile-id project-id]))
+
(sq/defquery ::projects-by-team
[{:keys [profile-id team-id]}]
(projects-by-team profile-id team-id))
+(sq/defquery ::project-by-id
+ [{:keys [profile-id project-id]}]
+ (project-by-id profile-id project-id))
diff --git a/backend/src/uxbox/services/queries/teams.clj b/backend/src/uxbox/services/queries/teams.clj
index efce8203a3..b3b32d58d3 100644
--- a/backend/src/uxbox/services/queries/teams.clj
+++ b/backend/src/uxbox/services/queries/teams.clj
@@ -40,5 +40,14 @@
(ex/raise :type :validation
:code :not-authorized))))))
-
-
+(defn check-read-permissions!
+ [conn profile-id team-id]
+ (-> (db/query-one conn [sql:team-permissions profile-id team-id])
+ (p/then' (fn [row]
+ (when-not (or (:can-edit row)
+ (:is-admin row)
+ (:is-owner row)
+ ;; We can read global-project owned items
+ (= team-id #uuid "00000000-0000-0000-0000-000000000000"))
+ (ex/raise :type :validation
+ :code :not-authorized))))))
diff --git a/common/uxbox/common/spec.cljc b/common/uxbox/common/spec.cljc
index 10af336cf7..179d3bac6a 100644
--- a/common/uxbox/common/spec.cljc
+++ b/common/uxbox/common/spec.cljc
@@ -24,7 +24,7 @@
#"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
(def uuid-rx
- #"^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
+ #"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
;; --- Conformers
diff --git a/frontend/resources/images/icons/tick.svg b/frontend/resources/images/icons/tick.svg
new file mode 100644
index 0000000000..88d3be0aa3
--- /dev/null
+++ b/frontend/resources/images/icons/tick.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json
index 155778fed6..3f9f493395 100644
--- a/frontend/resources/locales.json
+++ b/frontend/resources/locales.json
@@ -1,18 +1,18 @@
{
"dashboard.grid.delete" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:73", "src/uxbox/main/ui/dashboard/grid.cljs:91" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:72", "src/uxbox/main/ui/dashboard/grid.cljs:92" ],
"translations" : {
"en" : "Delete"
}
},
"dashboard.grid.edit" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:72", "src/uxbox/main/ui/dashboard/grid.cljs:90" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:71", "src/uxbox/main/ui/dashboard/grid.cljs:91" ],
"translations" : {
"en" : "Edit"
}
},
"dashboard.grid.empty-files" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:113" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:114" ],
"translations" : {
"en" : "You still have no files here"
}
@@ -25,7 +25,7 @@
"unused" : true
},
"dashboard.header.draft" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:58" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:57" ],
"translations" : {
"en" : "Draft"
}
@@ -45,40 +45,40 @@
"unused" : true
},
"dashboard.header.new-file" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:78" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:77" ],
"translations" : {
"en" : "+ New file"
}
},
"dashboard.header.new-project" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/recent_files.cljs:54" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/recent_files.cljs:53" ],
"translations" : {
"en" : "+ New project"
}
},
"dashboard.header.profile-menu.logout" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/profile.cljs:59", "src/uxbox/main/ui/workspace/header.cljs:93" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/profile.cljs:59" ],
"translations" : {
"en" : "Exit",
"fr" : "Quitter"
}
},
"dashboard.header.profile-menu.password" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/profile.cljs:56", "src/uxbox/main/ui/workspace/header.cljs:92" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/profile.cljs:56" ],
"translations" : {
"en" : "Password",
"fr" : "Mot de passe"
}
},
"dashboard.header.profile-menu.profile" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/profile.cljs:53", "src/uxbox/main/ui/workspace/header.cljs:91" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/profile.cljs:53" ],
"translations" : {
"en" : "Profile",
"fr" : "Profil"
}
},
"dashboard.header.project" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:74" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:73" ],
"translations" : {
"en" : "Project %s"
}
@@ -127,25 +127,25 @@
"unused" : true
},
"dashboard.library.menu.icons" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:103" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:96" ],
"translations" : {
"en" : "Icons"
}
},
"dashboard.library.menu.images" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:107" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:100" ],
"translations" : {
"en" : "Images"
}
},
"dashboard.library.menu.palettes" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:111" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:104" ],
"translations" : {
"en" : "Palettes"
}
},
"dashboard.search.no-matches-for" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/search.cljs:47" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/search.cljs:48" ],
"translations" : {
"en" : "No matches found for \"%s\""
}
@@ -157,13 +157,13 @@
"unused" : true
},
"dashboard.search.searching-for" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/search.cljs:43" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/search.cljs:44" ],
"translations" : {
"en" : "Searching for %s..."
}
},
"dashboard.search.type-something" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/search.cljs:39" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/search.cljs:40" ],
"translations" : {
"en" : "Type to search results"
}
@@ -200,19 +200,19 @@
}
},
"ds.button.delete" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:147", "src/uxbox/main/ui/dashboard/library.cljs:192", "src/uxbox/main/ui/dashboard/library.cljs:216", "src/uxbox/main/ui/dashboard/library.cljs:243" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:152", "src/uxbox/main/ui/dashboard/library.cljs:220", "src/uxbox/main/ui/dashboard/library.cljs:257", "src/uxbox/main/ui/dashboard/library.cljs:296" ],
"translations" : {
"en" : "Delete"
}
},
"ds.button.rename" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:146" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:149" ],
"translations" : {
"en" : "Rename"
}
},
"ds.button.save" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:51" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:54" ],
"translations" : {
"en" : "Save"
}
@@ -253,21 +253,21 @@
"unused" : true
},
"ds.confirm-cancel" : {
- "used-in" : [ "src/uxbox/main/ui/confirm.cljs:38" ],
+ "used-in" : [ "src/uxbox/main/ui/confirm.cljs:19" ],
"translations" : {
"en" : "Cancel",
"fr" : "Annuler"
}
},
"ds.confirm-ok" : {
- "used-in" : [ "src/uxbox/main/ui/confirm.cljs:34" ],
+ "used-in" : [ "src/uxbox/main/ui/confirm.cljs:20" ],
"translations" : {
"en" : "Ok",
"fr" : "Ok"
}
},
"ds.confirm-title" : {
- "used-in" : [ "src/uxbox/main/ui/confirm.cljs:28" ],
+ "used-in" : [ "src/uxbox/main/ui/confirm.cljs:18" ],
"translations" : {
"en" : "Are you sure?",
"fr" : "Êtes-vous sûr ?"
@@ -380,7 +380,7 @@
"unused" : true
},
"ds.new-file" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:109", "src/uxbox/main/ui/dashboard/grid.cljs:115" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:110", "src/uxbox/main/ui/dashboard/grid.cljs:116" ],
"translations" : {
"en" : "+ New File",
"fr" : null
@@ -450,7 +450,7 @@
"unused" : true
},
"ds.store-images-title" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:181" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:180" ],
"translations" : {
"en" : "IMAGES STORE",
"fr" : "BOUTIQUE"
@@ -499,7 +499,7 @@
"unused" : true
},
"ds.your-images-title" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:178" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:177" ],
"translations" : {
"en" : "YOUR IMAGES",
"fr" : "VOS IMAGES"
@@ -534,21 +534,21 @@
}
},
"errors.generic" : {
- "used-in" : [ "src/uxbox/main/ui.cljs:160" ],
+ "used-in" : [ "src/uxbox/main/ui.cljs:162" ],
"translations" : {
"en" : "Something wrong has happened.",
"fr" : "Quelque chose c'est mal passé."
}
},
"errors.network" : {
- "used-in" : [ "src/uxbox/main/ui.cljs:154" ],
+ "used-in" : [ "src/uxbox/main/ui.cljs:156" ],
"translations" : {
"en" : "Unable to connect to backend server.",
"fr" : "Impossible de se connecter au serveur principal."
}
},
"header.sitemap" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:96" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:154" ],
"translations" : {
"en" : null,
"fr" : null
@@ -562,28 +562,28 @@
}
},
"image.import-library" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:170" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:169" ],
"translations" : {
"en" : "Import image from library",
"fr" : "Importer une image depuis une librairie"
}
},
"image.new" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:84" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:83" ],
"translations" : {
"en" : "New image",
"fr" : "Nouvelle image"
}
},
"image.select" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:90", "src/uxbox/main/ui/workspace/images.cljs:95" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:89", "src/uxbox/main/ui/workspace/images.cljs:94" ],
"translations" : {
"en" : "Select from library",
"fr" : "Choisir depuis une librairie"
}
},
"image.upload" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:102" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:101" ],
"translations" : {
"en" : "Upload file",
"fr" : "Envoyer un fichier"
@@ -645,7 +645,7 @@
"unused" : true
},
"modal.create-color.new-color" : {
- "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:45" ],
+ "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:48" ],
"translations" : {
"en" : "New Color"
}
@@ -658,7 +658,7 @@
}
},
"profile.recovery.go-to-login" : {
- "used-in" : [ "src/uxbox/main/ui/profile/recovery_request.cljs:65", "src/uxbox/main/ui/profile/recovery.cljs:81" ],
+ "used-in" : [ "src/uxbox/main/ui/profile/recovery.cljs:81", "src/uxbox/main/ui/profile/recovery_request.cljs:65" ],
"translations" : {
"en" : "Go back!",
"fr" : "Retour!"
@@ -798,23 +798,12 @@
}
},
"settings.password" : {
- "used-in" : [ "src/uxbox/main/ui/settings/header.cljs:37" ],
+ "used-in" : [ "src/uxbox/main/ui/settings/header.cljs:34" ],
"translations" : {
"en" : "PASSWORD",
"fr" : "MOT DE PASSE"
}
},
- "workspace.header.menu.hide-rules": "Hide rules",
- "workspace.header.menu.show-rules": "Show rules",
- "workspace.header.menu.hide-grid": "Hide grid",
- "workspace.header.menu.show-grid": "Show grid",
- "workspace.header.menu.hide-layers": "Hide layers",
- "workspace.header.menu.show-layers": "Show layers",
- "workspace.header.menu.hide-palette": "Hide color palette",
- "workspace.header.menu.show-palette": "Show color palette",
- "workspace.header.menu.hide-libraries": "Hide libraries",
- "workspace.header.menu.show-libraries": "Show libraries",
-
"settings.password.change-password" : {
"used-in" : [ "src/uxbox/main/ui/settings/password.cljs:64" ],
"translations" : {
@@ -851,14 +840,14 @@
}
},
"settings.profile" : {
- "used-in" : [ "src/uxbox/main/ui/settings/header.cljs:34" ],
+ "used-in" : [ "src/uxbox/main/ui/settings/header.cljs:30" ],
"translations" : {
"en" : "PROFILE",
"fr" : "PROFIL"
}
},
"settings.profile.lang" : {
- "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:91" ],
+ "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:92" ],
"translations" : {
"en" : "Default language",
"fr" : "Langue par défaut"
@@ -872,28 +861,28 @@
}
},
"settings.profile.section-basic-data" : {
- "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:64" ],
+ "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:66" ],
"translations" : {
"en" : "Name, username and email",
"fr" : "Nom, nom d'utilisateur et adresse email"
}
},
"settings.profile.your-avatar" : {
- "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:135" ],
+ "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:138" ],
"translations" : {
"en" : "Your avatar",
"fr" : "Votre avatar"
}
},
"settings.profile.your-email" : {
- "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:85" ],
+ "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:87" ],
"translations" : {
"en" : null,
"fr" : null
}
},
"settings.profile.your-name" : {
- "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:72" ],
+ "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:75" ],
"translations" : {
"en" : "Your name",
"fr" : "Votre nom complet"
@@ -907,7 +896,7 @@
"unused" : true
},
"settings.update-settings" : {
- "used-in" : [ "src/uxbox/main/ui/settings/notifications.cljs:42", "src/uxbox/main/ui/settings/password.cljs:102", "src/uxbox/main/ui/settings/profile.cljs:104" ],
+ "used-in" : [ "src/uxbox/main/ui/settings/notifications.cljs:42", "src/uxbox/main/ui/settings/password.cljs:102", "src/uxbox/main/ui/settings/profile.cljs:105" ],
"translations" : {
"en" : "Update settings",
"fr" : "Mettre à jour les paramètres"
@@ -990,6 +979,66 @@
},
"unused" : true
},
+ "workspace.header.menu.hide-grid" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:104" ],
+ "translations" : {
+ "en" : "Hide grid"
+ }
+ },
+ "workspace.header.menu.hide-layers" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:111" ],
+ "translations" : {
+ "en" : "Hide layers"
+ }
+ },
+ "workspace.header.menu.hide-libraries" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:125" ],
+ "translations" : {
+ "en" : "Hide libraries"
+ }
+ },
+ "workspace.header.menu.hide-palette" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:118" ],
+ "translations" : {
+ "en" : "Hide color palette"
+ }
+ },
+ "workspace.header.menu.hide-rules" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:97" ],
+ "translations" : {
+ "en" : "Hide rules"
+ }
+ },
+ "workspace.header.menu.show-grid" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:105" ],
+ "translations" : {
+ "en" : "Show grid"
+ }
+ },
+ "workspace.header.menu.show-layers" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:112" ],
+ "translations" : {
+ "en" : "Show layers"
+ }
+ },
+ "workspace.header.menu.show-libraries" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:126" ],
+ "translations" : {
+ "en" : "Show libraries"
+ }
+ },
+ "workspace.header.menu.show-palette" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:119" ],
+ "translations" : {
+ "en" : "Show color palette"
+ }
+ },
+ "workspace.header.menu.show-rules" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:98" ],
+ "translations" : {
+ "en" : "Show rules"
+ }
+ },
"workspace.header.path" : {
"translations" : {
"en" : "Path",
@@ -1025,29 +1074,65 @@
},
"unused" : true
},
+ "workspace.library.all" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/libraries.cljs:106" ],
+ "translations" : {
+ "en" : "All libraries"
+ }
+ },
+ "workspace.library.icons" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/libraries.cljs:156" ],
+ "translations" : {
+ "en" : "Icons"
+ }
+ },
+ "workspace.library.images" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/libraries.cljs:161" ],
+ "translations" : {
+ "en" : "Images"
+ }
+ },
+ "workspace.library.libraries" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/libraries.cljs:138" ],
+ "translations" : {
+ "en" : "Libraries"
+ }
+ },
+ "workspace.library.own" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/libraries.cljs:107" ],
+ "translations" : {
+ "en" : "My libraries"
+ }
+ },
+ "workspace.library.store" : {
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/libraries.cljs:108" ],
+ "translations" : {
+ "en" : "Store libraries"
+ }
+ },
"workspace.options.color" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/page.cljs:124", "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:47", "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:81" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:47", "src/uxbox/main/ui/workspace/sidebar/options/page.cljs:124", "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:81" ],
"translations" : {
"en" : "Color",
"fr" : "Couleur"
}
},
"workspace.options.font-family" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:203" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:202" ],
"translations" : {
"en" : "Font Family",
"fr" : "Police de caractères"
}
},
"workspace.options.font-options" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:201" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:200" ],
"translations" : {
"en" : "Fonts & Font Size",
"fr" : "TODO"
}
},
"workspace.options.font-weight" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:212" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:211" ],
"translations" : {
"en" : "Font Size & Weight",
"fr" : "Taille et graisse"
@@ -1061,14 +1146,14 @@
}
},
"workspace.options.line-height-letter-spacing" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:244" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:243" ],
"translations" : {
"en" : "Line height and Letter spacing",
"fr" : "Hauteur de ligne et Espacement de caractères"
}
},
"workspace.options.measures" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:69", "src/uxbox/main/ui/workspace/sidebar/options/icon.cljs:66", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:62", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:64", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:55", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:66" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:64", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:55", "src/uxbox/main/ui/workspace/sidebar/options/icon.cljs:66", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:62", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:66", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:68" ],
"translations" : {
"en" : "Size, position & rotation",
"fr" : "Taille, position et rotation"
@@ -1082,21 +1167,21 @@
}
},
"workspace.options.position" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:98", "src/uxbox/main/ui/workspace/sidebar/options/icon.cljs:95", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:91", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:92", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:84", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:95" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:92", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:84", "src/uxbox/main/ui/workspace/sidebar/options/icon.cljs:95", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:91", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:95", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:97" ],
"translations" : {
"en" : "Position",
"fr" : "Position"
}
},
"workspace.options.rotation-radius" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:115", "src/uxbox/main/ui/workspace/sidebar/options/icon.cljs:112", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:108", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:107", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:112" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:107", "src/uxbox/main/ui/workspace/sidebar/options/icon.cljs:112", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:108", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:112", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:114" ],
"translations" : {
"en" : "Rotation & Radius",
"fr" : "TODO"
}
},
"workspace.options.size" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/page.cljs:114", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:71", "src/uxbox/main/ui/workspace/sidebar/options/icon.cljs:68", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:64", "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:68", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:57", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:68" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/circle.cljs:68", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:57", "src/uxbox/main/ui/workspace/sidebar/options/icon.cljs:68", "src/uxbox/main/ui/workspace/sidebar/options/image.cljs:64", "src/uxbox/main/ui/workspace/sidebar/options/page.cljs:114", "src/uxbox/main/ui/workspace/sidebar/options/rect.cljs:68", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:70" ],
"translations" : {
"en" : "Size",
"fr" : "Taille"
@@ -1152,7 +1237,7 @@
}
},
"workspace.options.text-align" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:263" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:262" ],
"translations" : {
"en" : "Text Alignment",
"fr" : "Alignement de texte"
@@ -1180,7 +1265,7 @@
}
},
"workspace.viewport.click-to-close-path" : {
- "used-in" : [ "src/uxbox/main/ui/workspace/drawarea.cljs:334" ],
+ "used-in" : [ "src/uxbox/main/ui/workspace/drawarea.cljs:335" ],
"translations" : {
"en" : "Click to close the path"
}
diff --git a/frontend/resources/styles/main.scss b/frontend/resources/styles/main.scss
index d6748e9472..cb43312a55 100644
--- a/frontend/resources/styles/main.scss
+++ b/frontend/resources/styles/main.scss
@@ -42,8 +42,9 @@
//#################################################
@import 'main/partials/main-bar';
-@import 'main/partials/workspace-bar';
@import 'main/partials/workspace';
+@import 'main/partials/workspace-bar';
+@import 'main/partials/workspace-libraries';
@import 'main/partials/tool-bar';
@import 'main/partials/project-bar';
@import 'main/partials/sidebar';
@@ -67,6 +68,7 @@
@import 'main/partials/context-menu';
@import 'main/partials/debug-icons-preview';
@import 'main/partials/editable-label';
+@import 'main/partials/tab-container';
//#################################################
// Resources
diff --git a/frontend/resources/styles/main/partials/color-palette.scss b/frontend/resources/styles/main/partials/color-palette.scss
index 3039e78e0f..42a7f3a589 100644
--- a/frontend/resources/styles/main/partials/color-palette.scss
+++ b/frontend/resources/styles/main/partials/color-palette.scss
@@ -11,21 +11,23 @@
background-color: $color-gray-50;
border-top: 1px solid $color-gray-60;
display: flex;
- padding: 1rem;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: 11;
- .right-arrow,
- .left-arrow {
- cursor: pointer;
+
+ & .right-arrow,
+ & .left-arrow {
+ cursor: pointer;
+
svg {
fill: $color-gray-light;
- height: 30px;
+ height: 1rem;
margin: 0 .5rem;
- width: 30px;
+ width: 1rem;
}
+
&:hover {
svg {
fill: $color-gray-darker;
@@ -35,25 +37,54 @@
display: none;
}
}
+
+
.left-arrow {
- transform: rotate(180deg);
+ transform: rotate(180deg);
+ padding-top: 10px;
}
+
&.fade-out-down {
@include animation(0,.5s,fadeOutDown);
}
+
+ &.left-sidebar-open {
+ left: 280px;
+ width: calc(100% - 280px);
+ }
+
+ & .context-menu-items {
+ bottom: 1.5rem;
+ top: initial;
+ min-width: 10rem;
+ }
}
.color-palette-actions {
- display: flex;
- flex-direction: column;
- flex-shrink: 0;
- margin-right: .5rem;
- width: 200px;
- .color-palette-buttons {
- align-items: center;
+ align-self: stretch;
+ border: 1px solid #1F1F1F;
+ cursor: pointer;
display: flex;
- justify-content: space-around;
- }
+ flex-direction: column;
+ flex-shrink: 0;
+ justify-content: center;
+ margin-right: .5rem;
+ padding: 0.5rem;
+
+ .color-palette-buttons {
+ align-items: center;
+ display: flex;
+ justify-content: space-around;
+ }
+}
+
+.color-palette-actions-button {
+ cursor: pointer;
+ & svg {
+ width: 1rem;
+ height: 1rem;
+ fill: #AFB2BF;
+ }
}
.btn-palette {
@@ -90,6 +121,8 @@
display: flex;
overflow: hidden;
width: 100%;
+ height: 4.8rem;
+ padding: 0.25rem;
}
.color-palette-inside {
@@ -106,15 +139,14 @@
display: flex;
flex-direction: column;
flex-shrink: 0;
- margin: 0 10px;
position: relative;
flex-basis: 66px;
+
.color {
background-color: $color-gray-lighter;
border: 2px solid $color-gray-60;
border-radius: 50%;
flex-shrink: 0;
- margin-bottom: .4rem;
padding: 1.5rem;
}
.color-text {
diff --git a/frontend/resources/styles/main/partials/context-menu.scss b/frontend/resources/styles/main/partials/context-menu.scss
index e6acef56b2..58735efef9 100644
--- a/frontend/resources/styles/main/partials/context-menu.scss
+++ b/frontend/resources/styles/main/partials/context-menu.scss
@@ -17,7 +17,9 @@
border-radius: $br-small;
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
left: -$size-4;
+ max-height: 30rem;
min-width: 7rem;
+ overflow: auto;
position: absolute;
top: $size-3;
}
@@ -27,9 +29,25 @@
display: block;
font-size: $fs12;
padding: $size-2 $size-4;
+ white-space: nowrap;
&:hover {
color: $color-black;
- background: $color-primary-lighter;
+ background-color: $color-primary-lighter;
}
}
+
+.context-menu.is-selectable {
+ & .context-menu-action {
+ padding-left: 1.5rem;
+ }
+
+ & .context-menu-item.is-selected .context-menu-action {
+ background-image: url(/images/icons/tick.svg);
+ background-repeat: no-repeat;
+ background-position: 5% 48%;
+ background-size: 10px;
+ font-weight: bold;
+ }
+}
+
diff --git a/frontend/resources/styles/main/partials/sidebar-sitemap.scss b/frontend/resources/styles/main/partials/sidebar-sitemap.scss
index b2c63b6f48..00eae95a61 100644
--- a/frontend/resources/styles/main/partials/sidebar-sitemap.scss
+++ b/frontend/resources/styles/main/partials/sidebar-sitemap.scss
@@ -6,8 +6,6 @@
// Copyright (c) 2015-2016 Juan de la Cruz
.sitemap {
- max-height: 180px;
-
.tool-window-bar {
.add-page {
diff --git a/frontend/resources/styles/main/partials/sidebar.scss b/frontend/resources/styles/main/partials/sidebar.scss
index 1c0fe1aeac..0200bfda2e 100644
--- a/frontend/resources/styles/main/partials/sidebar.scss
+++ b/frontend/resources/styles/main/partials/sidebar.scss
@@ -11,7 +11,7 @@
height: 100%;
position: fixed;
right: 0;
- width: 230px;
+ width: 15rem;
z-index: 10;
&.settings-bar-left {
@@ -20,10 +20,23 @@
.settings-bar-inside {
align-items: center;
- display: flex;
+ display: grid;
+ grid-template-columns: 100%;
+
+ &[data-layout*='layers'] {
+ grid-template-rows: 30% 70%;
+ }
+
+ &[data-layout*='libraries'] {
+ grid-template-rows: 100%;
+ }
+
+ &[data-layout*='layers'][data-layout*='libraries'] {
+ grid-template-rows: 15% 25% 60%;
+ }
+
flex-direction: column;
- overflow-y: auto;
- overflow-x: hidden;
+ overflow: hidden;
padding-top: 40px;
height: 100%;
@@ -33,12 +46,14 @@
flex-direction: column;
flex: 1;
width: 100%;
+ height: 100%;
.tool-window-bar {
align-items: center;
display: flex;
flex-shrink: 0;
padding: $small;
+ overflow: hidden;
svg {
fill: $color-gray-20;
@@ -78,14 +93,8 @@
flex-wrap: wrap;
overflow-y: auto;
padding-bottom: $medium;
+ height: 100%;
}
-
- layers {
- padding-bottom: 30px;
- }
-
}
-
}
-
}
diff --git a/frontend/resources/styles/main/partials/tab-container.scss b/frontend/resources/styles/main/partials/tab-container.scss
new file mode 100644
index 0000000000..601f394ea8
--- /dev/null
+++ b/frontend/resources/styles/main/partials/tab-container.scss
@@ -0,0 +1,43 @@
+
+.tab-container {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%;
+}
+
+.tab-container-tabs {
+ background: $color-gray-60;
+ cursor: pointer;
+ display: flex;
+ flex-direction: row;
+ font-size: 12px;
+ height: 2.5rem;
+ padding: 0 0.25rem;
+}
+
+.tab-container-tab-title {
+ align-items: center;
+ background: $color-gray-60;
+ border-radius: 2px 2px 0px 0px;
+ color: $color-white;
+ display: flex;
+ justify-content: center;
+ margin: 0.5rem 0.25rem 0 0.25rem ;
+ width: 100%;
+
+ &.current{
+ background: $color-gray-50;
+ }
+}
+
+.tab-container-content {
+ flex: 1;
+ height: 100%;
+ max-height: 100%;
+ overflow: hidden;
+}
+
+.tab-element, .tab-element-content {
+ height: 100%;
+}
diff --git a/frontend/resources/styles/main/partials/workspace-libraries.scss b/frontend/resources/styles/main/partials/workspace-libraries.scss
new file mode 100644
index 0000000000..fe4a8c2f31
--- /dev/null
+++ b/frontend/resources/styles/main/partials/workspace-libraries.scss
@@ -0,0 +1,127 @@
+.libraries-window-bar {
+ display: grid;
+ grid-template-columns: repeat(2, 50%);
+ padding: 0.5rem;
+ align-items: center;
+
+ & .context-menu-items {
+ left: initial;
+ right: 0;
+ }
+}
+
+.libraries-window-bar-title {
+ color: #F0F0F0;
+}
+
+.libraries-window-bar-options {
+ font-size: 12px;
+ display: flex;
+ justify-content: space-between;
+ padding: 0 0.5rem;
+
+ button {
+ border: none;
+ padding: 0;
+ margin: 0;
+ background: transparent;
+ cursor: pointer;
+ }
+ & svg {
+ width: 0.5rem;
+ height: 0.5rem;
+ fill: #F0F0F0;
+ transform: rotate(90deg);
+ }
+}
+
+.library-tab {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ padding: 0.25rem;
+}
+
+.library-tab-content {
+ display: grid;
+ flex-direction: row;
+ flex-wrap: wrap;
+ padding: 0.25rem;
+ overflow-y: scroll;
+
+ .icons-tab & {
+ grid-template-columns: repeat(3, 1fr);
+ }
+
+ .images-tab & {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+.library-tab-element {
+ border-radius: 4px;
+ border: 1px solid #1F1F1F;
+ box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
+ box-sizing: border-box;
+ cursor: pointer;
+ display: flex;
+ margin: 0.25rem;
+ overflow: hidden;
+ position: relative;
+ text-align: center;
+
+ & svg, & img {
+ height: auto;
+ margin: auto;
+ max-height: 100%;
+ max-width: 100%;
+ width: auto;
+ }
+
+ &:hover {
+ border-color: $color-primary;
+
+ & .library-tab-element-name {
+ display: inline;
+ }
+ }
+
+ .icons-tab & {
+ background: $color-white;
+ color: $color-black;
+ height: 4rem;
+ width: 4rem;
+ padding: $size-3;
+ }
+
+ .images-tab & {
+ height: 4rem;
+ width: 6.2rem;
+ color: $color-white;
+ padding: $size-2 0;
+ }
+}
+
+.library-tab-element-name {
+ display: none;
+ position: absolute;
+ font-size: 9px;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+}
+
+.library-tab-libraries {
+ background-color: #303236;
+ margin: 0.5rem;
+ width: 90%;
+ padding: 0.5rem;
+ box-sizing: border-box;
+ color: #AFB2BF;
+ font-size: 12px;
+ border: 1px solid #7c7c7c;
+}
+
+.library-tab-libraries-item {
+ padding: 1rem;
+}
diff --git a/frontend/src/uxbox/main/data/colors.cljs b/frontend/src/uxbox/main/data/colors.cljs
index 812844ab01..5639ab5e85 100644
--- a/frontend/src/uxbox/main/data/colors.cljs
+++ b/frontend/src/uxbox/main/data/colors.cljs
@@ -266,4 +266,4 @@
ptk/UpdateEvent
(update [_ state]
(-> state
- (update-in [:library :selected-items library-id] #(into [item] %) )))))
+ (update-in [:library-items :palettes library-id] #(into [item] %) )))))
diff --git a/frontend/src/uxbox/main/data/icons.cljs b/frontend/src/uxbox/main/data/icons.cljs
index 132f881fb6..ee0d5717f2 100644
--- a/frontend/src/uxbox/main/data/icons.cljs
+++ b/frontend/src/uxbox/main/data/icons.cljs
@@ -203,7 +203,7 @@
(update [_ state]
(let [{:keys [id] :as item} (assoc item :type :icon)]
(-> state
- (update-in [:library :selected-items library-id] #(into [item] %)))))))
+ (update-in [:library-items :icons library-id] #(into [item] %)))))))
;; ;; --- Icon Persisted
;;
diff --git a/frontend/src/uxbox/main/data/images.cljs b/frontend/src/uxbox/main/data/images.cljs
index d9a5614a4f..38dfcb8c9f 100644
--- a/frontend/src/uxbox/main/data/images.cljs
+++ b/frontend/src/uxbox/main/data/images.cljs
@@ -395,5 +395,5 @@
ptk/UpdateEvent
(update [_ state]
(-> state
- (update-in [:library :selected-items library-id] #(into [item] %))))))
+ (update-in [:library-items :images library-id] #(into [item] %))))))
diff --git a/frontend/src/uxbox/main/data/library.cljs b/frontend/src/uxbox/main/data/library.cljs
index ff9805d121..9c716ee850 100644
--- a/frontend/src/uxbox/main/data/library.cljs
+++ b/frontend/src/uxbox/main/data/library.cljs
@@ -14,30 +14,33 @@
[uxbox.util.router :as r]
[uxbox.util.uuid :as uuid]))
+(defn initialize-workspace-libraries []
+ ())
;; Retrieve libraries
(declare retrieve-libraries-result)
(defn retrieve-libraries
- [type team-id]
- (s/assert ::us/uuid team-id)
- (let [method (case type
- :icons :icon-libraries
- :images :image-libraries
- :palettes :color-libraries)]
- (ptk/reify ::retrieve-libraries
- ptk/WatchEvent
- (watch [_ state stream]
- (->> (rp/query! method {:team-id team-id})
- (rx/map (partial retrieve-libraries-result type)))))))
+ ([type] (retrieve-libraries type uuid/zero))
+ ([type team-id]
+ (s/assert ::us/uuid team-id)
+ (let [method (case type
+ :icons :icon-libraries
+ :images :image-libraries
+ :palettes :color-libraries)]
+ (ptk/reify ::retrieve-libraries
+ ptk/WatchEvent
+ (watch [_ state stream]
+ (->> (rp/query! method {:team-id team-id})
+ (rx/map (partial retrieve-libraries-result type team-id))))))))
-(defn retrieve-libraries-result [type result]
+(defn retrieve-libraries-result [type team-id result]
(ptk/reify ::retrieve-libraries-result
ptk/UpdateEvent
(update [_ state]
(-> state
- (assoc-in [:library type] result)))))
+ (assoc-in [:library type team-id] result)))))
;; Retrieve library data
@@ -53,15 +56,15 @@
:images :images
:palettes :colors)]
(->> (rp/query! method {:library-id library-id})
- (rx/map (partial retrieve-library-data-result library-id)))))))
+ (rx/map (partial retrieve-library-data-result type library-id)))))))
(defn retrieve-library-data-result
- [library-id data]
+ [type library-id data]
(ptk/reify ::retrieve-library-data-result
ptk/UpdateEvent
(update [_ state]
(-> state
- (assoc-in [:library :selected-items library-id] data)))))
+ (assoc-in [:library-items type library-id] data)))))
;; Create library
@@ -78,23 +81,23 @@
:images :create-image-library
:palettes :create-color-library)]
(->> (rp/mutation! method {:team-id team-id
- :name name})
- (rx/map (partial create-library-result type)))))))
+ :name name})
+ (rx/map (partial create-library-result type team-id)))))))
(defn create-library-result
- [type result]
+ [type team-id result]
(ptk/reify ::create-library-result
ptk/UpdateEvent
(update [_ state]
(-> state
- (update-in [:library type] #(into [result] %))))))
+ (update-in [:library type team-id] #(into [result] %))))))
;; Rename library
(declare rename-library-result)
(defn rename-library
- [type library-id name]
+ [type team-id library-id name]
(ptk/reify ::rename-library
ptk/WatchEvent
(watch [_ state stream]
@@ -104,10 +107,10 @@
:palettes :rename-color-library)]
(->> (rp/mutation! method {:id library-id
:name name})
- (rx/map #(rename-library-result type library-id name)))))))
+ (rx/map #(rename-library-result type team-id library-id name)))))))
(defn rename-library-result
- [type library-id name]
+ [type team-id library-id name]
(ptk/reify ::rename-library-result
ptk/UpdateEvent
(update [_ state]
@@ -118,14 +121,14 @@
(update-fn [libraries] (map change-name libraries))]
(-> state
- (update-in [:library type] update-fn))))))
+ (update-in [:library type team-id] update-fn))))))
;; Delete library
(declare delete-library-result)
(defn delete-library
- [type library-id]
+ [type team-id library-id]
(ptk/reify ::delete-library
ptk/UpdateEvent
(update [_ state]
@@ -139,17 +142,17 @@
:images :delete-image-library
:palettes :delete-color-library)]
(->> (rp/mutation! method {:id library-id})
- (rx/map #(delete-library-result type library-id)))))))
+ (rx/map #(delete-library-result type team-id library-id)))))))
(defn delete-library-result
- [type library-id]
+ [type team-id library-id]
(ptk/reify ::create-library-result
ptk/UpdateEvent
(update [_ state]
(let [update-fn (fn [libraries]
(filterv #(not= library-id (:id %)) libraries))]
(-> state
- (update-in [:library type] update-fn))))))
+ (update-in [:library type team-id] update-fn))))))
;; Delete library item
@@ -175,7 +178,7 @@
(let [update-fn (fn [items]
(filterv #(not= item-id (:id %)) items))]
(-> state
- (update-in [:library :selected-items library-id] update-fn))))))
+ (update-in [:library-items type library-id] update-fn))))))
;; Batch delete
@@ -204,4 +207,25 @@
update-fn (fn [items]
(filterv #(not (item-ids-set (:id %))) items))]
(-> state
- (update-in [:library :selected-items library-id] update-fn))))))
+ (update-in [:library-items type library-id] update-fn))))))
+
+;; Workspace - select library
+
+(defn select-library
+ [type library-id]
+ (ptk/reify ::select-library
+ ptk/UpdateEvent
+ (update [_ state]
+ (-> state
+ (assoc-in [:library-selected type] library-id)))))
+
+
+;; Workspace - change library filter
+
+(defn change-library-filter
+ [type filter]
+ (ptk/reify ::change-library-filter
+ ptk/UpdateEvent
+ (update [_ state]
+ (-> state
+ (assoc-in [:library-filter type] filter)))))
diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs
index f1016a9792..f633fb0bd9 100644
--- a/frontend/src/uxbox/main/data/workspace.cljs
+++ b/frontend/src/uxbox/main/data/workspace.cljs
@@ -66,6 +66,7 @@
(declare fetch-users)
(declare fetch-images)
+(declare fetch-project)
(declare handle-who)
(declare handle-pointer-update)
(declare handle-pointer-send)
@@ -294,7 +295,8 @@
(defn initialize
"Initialize the workspace state."
- [file-id page-id]
+ [project-id file-id page-id]
+ (us/verify ::us/uuid project-id)
(us/verify ::us/uuid file-id)
(us/verify ::us/uuid page-id)
(ptk/reify ::initialize
@@ -305,9 +307,11 @@
(rx/merge
(rx/of (fetch-file-with-users file-id)
(fetch-pages file-id)
- (fetch-images file-id))
+ (fetch-images file-id)
+ (fetch-project project-id))
(->> (rx/zip (rx/filter (ptk/type? ::pages-fetched) stream)
- (rx/filter (ptk/type? ::file-fetched) stream))
+ (rx/filter (ptk/type? ::file-fetched) stream)
+ (rx/filter (ptk/type? ::project-fetched) stream))
(rx/take 1)
(rx/do (fn [_]
(uxbox.util.timers/schedule 500 #(reset! st/loader false))))
@@ -355,7 +359,8 @@
(rx/of (initialize-page-persistence page-id)))))
(defn finalize
- [file-id page-id]
+ [project-id file-id page-id]
+ (us/verify ::us/uuid project-id)
(us/verify ::us/uuid file-id)
(us/verify ::us/uuid page-id)
(ptk/reify ::finalize
@@ -493,6 +498,7 @@
(s/def ::data ::cp/data)
(s/def ::file ::dd/file)
+(s/def ::project ::dd/project)
(s/def ::page
(s/keys :req-un [::id
::name
@@ -546,6 +552,25 @@
state
users))))
+;; --- Fetch Project data
+(declare project-fetched)
+
+(defn fetch-project
+ [id]
+ (us/verify ::us/uuid id)
+ (ptk/reify ::fetch-project
+ ptk/WatchEvent
+ (watch [_ state stream]
+ (->> (rp/query :project-by-id {:project-id id})
+ (rx/map project-fetched)))))
+
+(defn project-fetched
+ [project]
+ (us/verify ::project project)
+ (ptk/reify ::project-fetched
+ ptk/UpdateEvent
+ (update [_ state]
+ (assoc state :workspace-project project))))
;; --- Fetch Pages
@@ -770,16 +795,20 @@
;; --- Toggle layout flag
(defn toggle-layout-flag
- [flag]
- (us/verify keyword? flag)
+ [& flags]
+ ;; Verify all?
+ #_(us/verify keyword? flag)
(ptk/reify ::toggle-layout-flag
ptk/UpdateEvent
(update [_ state]
- (update state :workspace-layout
- (fn [flags]
- (if (contains? flags flag)
- (disj flags flag)
- (conj flags flag)))))))
+ (let [reduce-fn
+ (fn [state flag]
+ (update state :workspace-layout
+ (fn [flags]
+ (if (contains? flags flag)
+ (disj flags flag)
+ (conj flags flag)))))]
+ (reduce reduce-fn state flags)))))
;; --- Tooltip
@@ -1103,6 +1132,7 @@
(rx/empty))))))
+
;; --- Toggle shape's selection status (selected or deselected)
(defn select-shape
@@ -1924,7 +1954,8 @@
(ptk/reify ::go-to-page
ptk/WatchEvent
(watch [_ state stream]
- (let [file-id (get-in state [:workspace-page :file-id])
+ (let [project-id (get-in state [:workspace-project :id])
+ file-id (get-in state [:workspace-page :file-id])
path-params {:file-id file-id}
query-params {:page-id page-id}]
(rx/of (rt/nav :workspace path-params query-params))))))
@@ -1935,8 +1966,9 @@
(ptk/reify ::go-to-file
ptk/WatchEvent
(watch [_ state stream]
- (let [page-ids (get-in state [:files file-id :pages])
- path-params {:file-id file-id}
+ (let [project-id (get-in state [:workspace-project :id])
+ page-ids (get-in state [:files file-id :pages])
+ path-params {:project-id project-id :file-id file-id}
query-params {:page-id (first page-ids)}]
(rx/of (rt/nav :workspace path-params query-params))))))
diff --git a/frontend/src/uxbox/main/ui.cljs b/frontend/src/uxbox/main/ui.cljs
index 312cba7593..38d44ccf9c 100644
--- a/frontend/src/uxbox/main/ui.cljs
+++ b/frontend/src/uxbox/main/ui.cljs
@@ -73,7 +73,7 @@
]]]
- ["/workspace/:file-id" :workspace]])
+ ["/workspace/:project-id/:file-id" :workspace]])
(mf/defc app-error
[{:keys [error] :as props}]
@@ -119,9 +119,11 @@
(mf/element dashboard #js {:route route})
:workspace
- (let [file-id (uuid (get-in route [:params :path :file-id]))
+ (let [project-id (uuid (get-in route [:params :path :project-id]))
+ file-id (uuid (get-in route [:params :path :file-id]))
page-id (uuid (get-in route [:params :query :page-id]))]
- [:& workspace/workspace {:file-id file-id
+ [:& workspace/workspace {:project-id project-id
+ :file-id file-id
:page-id page-id
:key file-id}])
nil)))
diff --git a/frontend/src/uxbox/main/ui/components/context_menu.cljs b/frontend/src/uxbox/main/ui/components/context_menu.cljs
index 2c7d85a2fd..928baebba7 100644
--- a/frontend/src/uxbox/main/ui/components/context_menu.cljs
+++ b/frontend/src/uxbox/main/ui/components/context_menu.cljs
@@ -3,7 +3,8 @@
[rumext.alpha :as mf]
[goog.object :as gobj]
[uxbox.main.ui.components.dropdown :refer [dropdown-container]]
- [uxbox.util.uuid :as uuid]))
+ [uxbox.util.uuid :as uuid]
+ [uxbox.util.data :refer [classnames]]))
(mf/defc context-menu
{::mf/wrap-props false}
@@ -13,12 +14,16 @@
(assert (vector? (gobj/get props "options")) "missing `options` prop")
(let [open? (gobj/get props "show")
- options (gobj/get props "options")]
+ options (gobj/get props "options")
+ is-selectable (gobj/get props "selectable")
+ selected (gobj/get props "selected")]
(when open?
[:> dropdown-container props
- [:div.context-menu {:class (when open? "is-open")}
+ [:div.context-menu {:class (classnames :is-open open?
+ :is-selectable is-selectable)}
[:ul.context-menu-items
(for [[action-name action-handler] options]
- [:li.context-menu-item {:key action-name}
+ [:li.context-menu-item {:class (classnames :is-selected (and selected (= action-name selected)))
+ :key action-name}
[:a.context-menu-action {:on-click action-handler}
action-name]])]]])))
diff --git a/frontend/src/uxbox/main/ui/components/tab_container.cljs b/frontend/src/uxbox/main/ui/components/tab_container.cljs
new file mode 100644
index 0000000000..78accbbcc9
--- /dev/null
+++ b/frontend/src/uxbox/main/ui/components/tab_container.cljs
@@ -0,0 +1,27 @@
+(ns uxbox.main.ui.components.tab-container
+ (:require [rumext.alpha :as mf]))
+
+(mf/defc tab-element
+ [{:keys [children id title]}]
+ [:div.tab-element
+ [:div.tab-element-content children]])
+
+(mf/defc tab-container
+ [{:keys [children selected on-change-tab]}]
+ (let [first-id (-> children first .-props .-id)
+ state (mf/use-state {:selected first-id})
+ selected (or selected (:selected @state))
+ handle-select (fn [tab]
+ (let [id (-> tab .-props .-id)]
+ (swap! state assoc :selected id)
+ (when on-change-tab (on-change-tab id))))]
+ [:div.tab-container
+ [:div.tab-container-tabs
+ (for [tab children]
+ [:div.tab-container-tab-title
+ {:key (str "tab-" (-> tab .-props .-id))
+ :on-click (partial handle-select tab)
+ :class (when (= selected (-> tab .-props .-id)) "current")}
+ (-> tab .-props .-title)])]
+ [:div.tab-container-content
+ (filter #(= selected (-> % .-props .-id)) children)]]))
diff --git a/frontend/src/uxbox/main/ui/dashboard/grid.cljs b/frontend/src/uxbox/main/ui/dashboard/grid.cljs
index b933c3b7e1..eb9146adf7 100644
--- a/frontend/src/uxbox/main/ui/dashboard/grid.cljs
+++ b/frontend/src/uxbox/main/ui/dashboard/grid.cljs
@@ -41,8 +41,9 @@
:edition false})
locale (i18n/use-locale)
on-navigate #(st/emit! (rt/nav :workspace
- {:file-id (:id file)}
- {:page-id (first (:pages file))}))
+ {:project-id (:project-id file)
+ :file-id (:id file)}
+ {:page-id (first (:pages file))}))
delete-fn #(st/emit! nil (dsh/delete-file (:id file)))
on-delete #(do
(dom/stop-propagation %)
@@ -75,7 +76,7 @@
[:h3 (:name file)])
[:& grid-item-metadata {:modified-at (:modified-at file)}]]
[:div.project-th-actions {:class (classnames
- :force-display (:menu-open @local))}
+ :force-display (:menu-open @local))}
;; [:div.project-th-icon.pages
;; i/page
;; #_[:span (:total-pages project)]]
diff --git a/frontend/src/uxbox/main/ui/dashboard/library.cljs b/frontend/src/uxbox/main/ui/dashboard/library.cljs
index a3d52aadc6..d432d6eb56 100644
--- a/frontend/src/uxbox/main/ui/dashboard/library.cljs
+++ b/frontend/src/uxbox/main/ui/dashboard/library.cljs
@@ -122,7 +122,7 @@
(dlib/retrieve-libraries :icons (:id item))
(st/emit! (rt/nav path {:team-id team-id :library-id (:id item)}))))}
[:& editable-label {:value (:name item)
- :on-change #(st/emit! (dlib/rename-library section library-id %))}]
+ :on-change #(st/emit! (dlib/rename-library section team-id library-id %))}]
])]]))
(mf/defc library-top-menu
@@ -136,7 +136,7 @@
[:& editable-label {:edit (:editing-name @state)
:on-change #(do
(stop-editing)
- (st/emit! (dlib/rename-library section library-id %)))
+ (st/emit! (dlib/rename-library section team-id library-id %)))
:on-cancel #(swap! state assoc :editing-name false)
:class-name "library-top-menu-current-element-name"
:value (:name selected)}]
@@ -155,7 +155,7 @@
(modal/show!
confirm-dialog
{:on-accept #(do
- (st/emit! (dlib/delete-library section library-id))
+ (st/emit! (dlib/delete-library section team-id library-id))
(st/emit! (rt/nav path {:team-id team-id})))
:message "Are you sure you want to delete this library?"
:accept-text "Delete"})))]]}]]
@@ -301,12 +301,12 @@
:message "Are you sure you want to delete this color?"
:accept-text "Delete"}))]]}]]])))
-(defn libraries-ref [section]
- (-> (comp (l/key :library) (l/key section))
+(defn libraries-ref [section team-id]
+ (-> (comp (l/key :library) (l/key section) (l/key team-id))
(l/derive st/state)))
-(defn selected-items-ref [library-id]
- (-> (comp (l/key :library) (l/key :selected-items) (l/key library-id))
+(defn selected-items-ref [section library-id]
+ (-> (comp (l/key :library-items) (l/key section) (l/key library-id))
(l/derive st/state)))
(def last-deleted-library-ref
@@ -316,8 +316,8 @@
(mf/defc library-page
[{:keys [team-id library-id section]}]
(let [state (mf/use-state {:selected #{}})
- libraries (mf/deref (libraries-ref section))
- items (mf/deref (selected-items-ref library-id))
+ libraries (mf/deref (libraries-ref section team-id))
+ items (mf/deref (selected-items-ref section library-id))
last-deleted-library (mf/deref last-deleted-library-ref)
selected-library (first (filter #(= (:id %) library-id) libraries))]
diff --git a/frontend/src/uxbox/main/ui/workspace.cljs b/frontend/src/uxbox/main/ui/workspace.cljs
index 92d132cd34..403d2a5b32 100644
--- a/frontend/src/uxbox/main/ui/workspace.cljs
+++ b/frontend/src/uxbox/main/ui/workspace.cljs
@@ -60,16 +60,14 @@
(mf/defc workspace-content
[{:keys [page file layout] :as params}]
(let [frame (mf/use-ref nil)
- left-sidebar? (not (empty? (keep layout [:layers :sitemap
- :document-history])))
- right-sidebar? (not (empty? (keep layout [:icons :drawtools
- :element-options])))
+ left-sidebar? (not (empty? (keep layout [:layers :sitemap :document-history :libraries])))
+ right-sidebar? (not (empty? (keep layout [:icons :drawtools :element-options])))
classes (classnames
:no-tool-bar-right (not right-sidebar?)
:no-tool-bar-left (not left-sidebar?))]
[:*
(when (:colorpalette layout)
- [:& colorpalette])
+ [:& colorpalette {:left-sidebar? left-sidebar?}])
[:main.main-content
[:& context-menu {}]
@@ -101,13 +99,13 @@
(mf/defc workspace
- [{:keys [file-id page-id] :as props}]
+ [{:keys [project-id file-id page-id] :as props}]
(-> (mf/deps file-id page-id)
(mf/use-effect
(fn []
- (st/emit! (dw/initialize file-id page-id))
- #(st/emit! (dw/finalize file-id page-id)))))
+ (st/emit! (dw/initialize project-id file-id page-id))
+ #(st/emit! (dw/finalize project-id file-id page-id)))))
(-> (mf/deps file-id)
(mf/use-effect
diff --git a/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs b/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs
index 742717575b..cfb8522e28 100644
--- a/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs
+++ b/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs
@@ -13,16 +13,30 @@
[uxbox.builtins.icons :as i]
[uxbox.main.data.colors :as udc]
[uxbox.main.data.workspace :as udw]
+ [uxbox.main.data.library :as dlib]
[uxbox.main.store :as st]
[uxbox.main.ui.keyboard :as kbd]
[uxbox.util.color :refer [hex->rgb]]
[uxbox.util.data :refer [read-string seek]]
- [uxbox.util.dom :as dom]))
+ [uxbox.util.dom :as dom]
+ [uxbox.main.ui.components.context-menu :refer [context-menu]]))
;; --- Refs
-(def collections-iref
- (-> (l/key :colors-collections)
+(def project-ref
+ (-> (l/key :workspace-project)
+ (l/derive st/state)))
+
+(def libraries-ref
+ (-> (comp (l/key :library) (l/key :palettes))
+ (l/derive st/state)))
+
+(defn selected-items-ref [library-id]
+ (-> (comp (l/key :library-items) (l/key :palettes) (l/key library-id))
+ (l/derive st/state)))
+
+(def selected-library-ref
+ (-> (comp (l/key :library-selected) (l/key :palettes))
(l/derive st/state)))
;; --- Components
@@ -30,8 +44,6 @@
(mf/defc palette-item
[{:keys [color] :as props}]
(let [rgb-vec (hex->rgb color)
- rgb-color (apply str "" (interpose ", " rgb-vec))
-
select-color
(fn [event]
(if (kbd/shift? event)
@@ -41,89 +53,86 @@
[:div.color-cell {:key (str color)
:on-click select-color}
[:span.color {:style {:background color}}]
- [:span.color-text color]
- [:span.color-text rgb-color]]))
+ [:span.color-text color]]))
(mf/defc palette
- [{:keys [colls] :as props}]
- (let [local (mf/use-state {})
- colls (->> colls
- (filter :id)
- (sort-by :name))
+ [{:keys [libraries left-sidebar?] :as props}]
- coll (or (:selected @local)
- (first colls))
+ (when (and libraries (-> libraries count (> 0)))
+ (let [current-selection (or (mf/deref selected-library-ref) (-> libraries first :id))
+ state (mf/use-state {:show-menu false })]
+ (mf/use-effect
+ (mf/deps current-selection)
+ #(st/emit! (dlib/retrieve-library-data :palettes current-selection)))
+
+ (let [items (-> current-selection selected-items-ref mf/deref)
+ doc-width (.. js/document -documentElement -clientWidth)
+ width (:width @state (* doc-width 0.84))
+ offset (:offset @state 0)
+ visible (/ width 86)
+ invisible (- (count items) visible)
+ close #(st/emit! (udw/toggle-layout-flag :colorpalette))
+ container (mf/use-ref nil)
+ container-child (mf/use-ref nil)
- doc-width (.. js/document -documentElement -clientWidth)
- width (:width @local (* doc-width 0.84))
- offset (:offset @local 0)
- visible (/ width 86)
- invisible (- (count (:colors coll)) visible)
- close #(st/emit! (udw/toggle-layout-flag :colorpalette))
+ on-left-arrow-click
+ (fn [event]
+ (when (> offset 0)
+ (let [element (mf/ref-val container-child)]
+ (swap! state update :offset dec))))
- container (mf/use-ref nil)
- container-child (mf/use-ref nil)
+ on-right-arrow-click
+ (fn [event]
+ (when (< offset invisible)
+ (let [element (mf/ref-val container-child)]
+ (swap! state update :offset inc))))
- select-coll
- (fn [event]
- (let [id (read-string (dom/event->value event))
- selected (seek #(= id (:id %)) colls)]
- (swap! local assoc :selected selected :position 0)))
+ on-scroll
+ (fn [event]
+ (if (pos? (.. event -nativeEvent -deltaY))
+ (on-right-arrow-click event)
+ (on-left-arrow-click event)))
- on-left-arrow-click
- (fn [event]
- (when (> offset 0)
- (let [element (mf/ref-val container-child)]
- (swap! local update :offset dec))))
+ after-render
+ (fn []
+ (let [dom (mf/ref-val container)
+ width (.-clientWidth dom)]
+ (when (not= (:width @state) width)
+ (swap! state assoc :width width))))
- on-right-arrow-click
- (fn [event]
- (when (< offset invisible)
- (let [element (mf/ref-val container-child)]
- (swap! local update :offset inc))))
+ handle-click
+ (fn [library]
+ (st/emit! (dlib/select-library :palettes (:id library))))]
- on-scroll
- (fn [event]
- (if (pos? (.. event -nativeEvent -deltaY))
- (on-right-arrow-click event)
- (on-left-arrow-click event)))
+ (mf/use-effect nil after-render)
- after-render
- (fn []
- (let [dom (mf/ref-val container)
- width (.-clientWidth dom)]
- (when (not= (:width @local) width)
- (swap! local assoc :width width))))]
+ [:div.color-palette {:class (when left-sidebar? "left-sidebar-open")}
+ [:& context-menu {:selectable true
+ :selected (->> libraries (filter #(= (:id %) current-selection)) first :name)
+ :show (:show-menu @state)
+ :on-close #(swap! state assoc :show-menu false)
+ :options (mapv #(vector (:name %) (partial handle-click %)) libraries)} ]
+ [:div.color-palette-actions
+ {:on-click #(swap! state assoc :show-menu true)}
+ [:div.color-palette-actions-button i/actions]]
- (mf/use-effect nil after-render)
+ [:span.left-arrow {:on-click on-left-arrow-click} i/arrow-slide]
- [:div.color-palette
- [:div.color-palette-actions
- [:select.input-select {:on-change select-coll
- :default-value (pr-str (:id coll))}
- (for [item colls]
- [:option {:key (:id item) :value (pr-str (:id item))}
- (:name item)])]
+ [:div.color-palette-content {:ref container :on-wheel on-scroll}
+ [:div.color-palette-inside {:ref container-child
+ :style {:position "relative"
+ :width (str (* 86 (count items)) "px")
+ :right (str (* 86 offset) "px")}}
+ (for [item items]
+ [:& palette-item {:color (:content item) :key (:id item)}])]]
- #_[:div.color-palette-buttons
- [:div.btn-palette.edit.current i/pencil]
- [:div.btn-palette.create i/close]]]
-
- [:span.left-arrow {:on-click on-left-arrow-click} i/arrow-slide]
-
- [:div.color-palette-content {:ref container :on-wheel on-scroll}
- [:div.color-palette-inside {:ref container-child
- :style {:position "relative"
- :width (str (* 86 (count (:colors coll))) "px")
- :right (str (* 86 offset) "px")}}
- (for [color (:colors coll)]
- [:& palette-item {:color color :key color}])]]
-
- [:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide]
- [:span.close-palette {:on-click close} i/close]]))
+ [:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide]]))))
(mf/defc colorpalette
- [props]
- (let [colls (mf/deref collections-iref)]
- #_(mf/use-effect #(st/emit! (udc/fetch-collections)))
- [:& palette {:colls (vals colls)}]))
+ [{:keys [left-sidebar?]}]
+ (let [team-id (-> project-ref mf/deref :team-id)
+ libraries (-> libraries-ref mf/deref vals flatten)]
+ (mf/use-effect #(st/emit! (dlib/retrieve-libraries :palettes)
+ (dlib/retrieve-libraries :palettes team-id)))
+ [:& palette {:left-sidebar? left-sidebar?
+ :libraries libraries}]))
diff --git a/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs b/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs
index 29048d0c15..3e3cdb29ec 100644
--- a/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs
+++ b/frontend/src/uxbox/main/ui/workspace/left_toolbar.cljs
@@ -68,10 +68,12 @@
[:li.tooltip.tooltip-right
{:alt "Layers"
:class (when (contains? layout :layers) "selected")
- :on-click #(st/emit! (dw/toggle-layout-flag :layers))}
+ :on-click #(st/emit! (dw/toggle-layout-flag :layers :sitemap))}
i/layers]
[:li.tooltip.tooltip-right
- {:alt "Libraries"}
+ {:alt "Libraries"
+ :class (when (contains? layout :libraries) "selected")
+ :on-click #(st/emit! (dw/toggle-layout-flag :libraries))}
i/icon-set]
[:li.tooltip.tooltip-right
{:alt "History"}
diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar.cljs
index bd18b669ea..f3fa789802 100644
--- a/frontend/src/uxbox/main/ui/workspace/sidebar.cljs
+++ b/frontend/src/uxbox/main/ui/workspace/sidebar.cljs
@@ -11,11 +11,13 @@
(ns uxbox.main.ui.workspace.sidebar
(:require
[rumext.alpha :as mf]
+ [cuerdas.core :as str]
[uxbox.main.ui.workspace.sidebar.history :refer [history-toolbox]]
[uxbox.main.ui.workspace.sidebar.icons :refer [icons-toolbox]]
[uxbox.main.ui.workspace.sidebar.layers :refer [layers-toolbox]]
[uxbox.main.ui.workspace.sidebar.options :refer [options-toolbox]]
- [uxbox.main.ui.workspace.sidebar.sitemap :refer [sitemap-toolbox]]))
+ [uxbox.main.ui.workspace.sidebar.sitemap :refer [sitemap-toolbox]]
+ [uxbox.main.ui.workspace.sidebar.libraries :refer [libraries-toolbox]]))
;; --- Left Sidebar (Component)
@@ -24,12 +26,15 @@
[{:keys [layout page file] :as props}]
[:aside.settings-bar.settings-bar-left
[:div.settings-bar-inside
+ {:data-layout (str/join "," layout)}
(when (contains? layout :sitemap)
[:& sitemap-toolbox {:file file :page page}])
(when (contains? layout :document-history)
[:& history-toolbox])
(when (contains? layout :layers)
- [:& layers-toolbox {:page page}])]])
+ [:& layers-toolbox {:page page}])
+ (when (contains? layout :libraries)
+ [:& libraries-toolbox])]])
;; --- Right Sidebar (Component)
diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs
new file mode 100644
index 0000000000..b84c3dfdb4
--- /dev/null
+++ b/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs
@@ -0,0 +1,165 @@
+;; 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.ui.workspace.sidebar.libraries
+ (:require
+ [lentes.core :as l]
+ [cuerdas.core :as str]
+ [rumext.alpha :as mf]
+ [uxbox.common.data :as d]
+ [uxbox.builtins.icons :as i]
+ [uxbox.main.data.workspace :as dw]
+ [uxbox.main.refs :as refs]
+ [uxbox.main.store :as st]
+ [uxbox.main.ui.keyboard :as kbd]
+ [uxbox.main.ui.shapes.icon :as icon]
+ [uxbox.main.ui.workspace.sortable :refer [use-sortable]]
+ [uxbox.util.dom :as dom]
+ [uxbox.util.uuid :as uuid]
+ [uxbox.util.i18n :as i18n :refer [tr]]
+ [uxbox.util.data :refer [classnames]]
+ [uxbox.main.ui.components.tab-container :refer [tab-container tab-element]]
+ [uxbox.main.data.library :as dlib]
+ [uxbox.main.ui.components.context-menu :refer [context-menu]]))
+
+;; --- Refs
+
+(def project-ref
+ (-> (l/key :workspace-project)
+ (l/derive st/state)))
+
+(defn libraries-ref [section]
+ (-> (comp (l/key :library) (l/key section))
+ (l/derive st/state)))
+
+(defn selected-items-ref [section library-id]
+ (-> (comp (l/key :library-items) (l/key section) (l/key library-id))
+ (l/derive st/state)))
+
+(defn selected-library-ref [section]
+ (-> (comp (l/key :library-selected) (l/key section))
+ (l/derive st/state)))
+
+(defn selected-filter-ref [section]
+ (-> (comp (l/key :library-filter) (l/key section))
+ (l/derive st/state)))
+
+;; --- Components
+
+(mf/defc library-tab [{:keys [libraries section]}]
+ (when (and libraries (-> libraries count (> 0)))
+ (let [first-id (-> libraries first :id)
+ current-selection (or (mf/deref (selected-library-ref section)) first-id)]
+
+ ;; Check if the current selection is in the list of libraries
+ (mf/use-effect
+ (mf/deps libraries)
+ #(when (not (some (fn [it] (= current-selection (-> it :id))) libraries))
+ (st/emit! (dlib/select-library section first-id))))
+
+ ;; Retrieve the library data given the current selected library
+ (mf/use-effect
+ (mf/deps current-selection)
+ #(st/emit! (dlib/retrieve-library-data section current-selection)))
+
+ [:div.library-tab
+ {:class (classnames :icons-tab (= section :icons)
+ :images-tab (= section :images))}
+ [:select.input-select.library-tab-libraries
+ {:on-change #(st/emit! (dlib/select-library section (-> % dom/get-target dom/get-value uuid)))}
+ (for [library libraries]
+ [:option.library-tab-libraries-item
+ {:key (:id library)
+ :value (:id library)
+ :selected (= current-selection (:id library))}
+ (:name library)])]
+ [:div.library-tab-content
+ (let [items (mf/deref (selected-items-ref section current-selection))]
+ (for [item items]
+ [:div.library-tab-element
+ {:key (:id item)
+ :on-click #(st/emit! (dw/select-for-drawing :icon item))}
+ (if (= section :icons)
+ [:* ;; ICONS
+ [:svg {:view-box (->> item :metadata :view-box (str/join " "))
+ :width (-> item :metadata :width)
+ :height (-> item :metadat :height)
+ :dangerouslySetInnerHTML {:__html (:content item)}}]
+ [:span.library-tab-element-name (:name item)]]
+
+ [:* ;; IMAGES
+ [:img {:src (:thumb-uri item)}]
+ [:span.library-tab-element-name (:name item)]])]))]])))
+
+(mf/defc libraries-toolbox
+ [{:keys [key]}]
+ (let [state (mf/use-state {:menu-open false})
+ selected-filter (fn [section] (or (mf/deref (selected-filter-ref section)) :all))
+ team-id (-> project-ref mf/deref :team-id)
+
+ filter-to-str {:all (tr "workspace.library.all")
+ :own (tr "workspace.library.own")
+ :store (tr "workspace.library.store")}
+
+ select-option
+ (fn [option]
+ (st/emit!
+ (dlib/change-library-filter :icons option)
+ (dlib/change-library-filter :images option)))
+
+ filter-libraries
+ (fn [section libraries]
+ (case (selected-filter section)
+ :all (-> libraries vals flatten)
+ :own (libraries team-id)
+ :store (libraries uuid/zero)))
+
+ get-libraries
+ (fn [section] (->> (libraries-ref section)
+ mf/deref
+ (filter-libraries section)))]
+
+ (mf/use-effect
+ (mf/deps team-id)
+ #(when team-id
+ (st/emit! (dlib/retrieve-libraries :icons)
+ (dlib/retrieve-libraries :images)
+ (dlib/retrieve-libraries :icons team-id)
+ (dlib/retrieve-libraries :images team-id))))
+
+ [:div#libraries.tool-window
+ [:div.libraries-window-bar
+ [:div.libraries-window-bar-title (tr "workspace.library.libraries")]
+ [:div.libraries-window-bar-options
+ {:on-click #(swap! state assoc :menu-open true)}
+ (filter-to-str (selected-filter :icons))
+ [:button
+ {
+ :type "button"}
+ i/arrow-slide
+ [:& context-menu
+ {:selectable true
+ :show (:menu-open @state)
+ :selected (filter-to-str (selected-filter :icons))
+ :on-close #(swap! state assoc :menu-open false)
+ :options (mapv (fn [[key val]] [val #(select-option key)]) filter-to-str)}]]]]
+
+ [:div.tool-window-content
+ [:& tab-container {}
+ [:& tab-element
+ {:id :icons :title (tr "workspace.library.icons")}
+ [:& library-tab {:section :icons
+ :libraries (get-libraries :icons) }]]
+
+ [:& tab-element
+ {:id :images :title (tr "workspace.library.images")}
+ [:& library-tab {:section :images
+ :libraries (get-libraries :images)}]]]]]))
+
+
diff --git a/frontend/src/uxbox/util/data.cljs b/frontend/src/uxbox/util/data.cljs
index 4dd2035f5c..61145306d8 100644
--- a/frontend/src/uxbox/util/data.cljs
+++ b/frontend/src/uxbox/util/data.cljs
@@ -205,3 +205,4 @@
;; (if (::some-interrupt (ex-data e#))
;; nil
;; (throw e#)))))))
+