Merge pull request #151 from uxbox/9/workspace-libraries

Workspace - New libraries panel and color palettes
This commit is contained in:
Andrey Antukh 2020-03-26 16:58:06 +01:00 committed by GitHub
commit 1e82573675
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 886 additions and 266 deletions

View file

@ -50,7 +50,7 @@
(sq/defquery ::color-libraries (sq/defquery ::color-libraries
[{:keys [profile-id team-id]}] [{:keys [profile-id team-id]}]
(db/with-atomic [conn db/pool] (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]))) (db/query conn [sql:libraries team-id])))
@ -66,7 +66,7 @@
[{:keys [profile-id id]}] [{:keys [profile-id id]}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn id)] (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))) lib)))
(def ^:private sql:single-library (def ^:private sql:single-library
@ -94,7 +94,7 @@
[{:keys [profile-id library-id] :as params}] [{:keys [profile-id library-id] :as params}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn library-id)] (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)))) (retrieve-colors conn library-id))))
(def ^:private sql:colors (def ^:private sql:colors
@ -123,7 +123,7 @@
[{:keys [profile-id id] :as params}] [{:keys [profile-id id] :as params}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(p/let [color (retrieve-color conn id)] (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))) color)))
(def ^:private sql:single-color (def ^:private sql:single-color

View file

@ -56,8 +56,10 @@
(sq/defquery ::icon-libraries (sq/defquery ::icon-libraries
[{:keys [profile-id team-id]}] [{:keys [profile-id team-id]}]
(println profile-id)
(println team-id)
(db/with-atomic [conn db/pool] (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]))) (db/query conn [sql:libraries team-id])))
@ -73,7 +75,7 @@
[{:keys [profile-id id]}] [{:keys [profile-id id]}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn id)] (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))) lib)))
(def ^:private sql:single-library (def ^:private sql:single-library
@ -101,7 +103,7 @@
[{:keys [profile-id library-id] :as params}] [{:keys [profile-id library-id] :as params}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn library-id)] (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) (-> (retrieve-icons conn library-id)
(p/then' (fn [rows] (mapv decode-row rows))))))) (p/then' (fn [rows] (mapv decode-row rows)))))))
@ -131,7 +133,7 @@
[{:keys [profile-id id] :as params}] [{:keys [profile-id id] :as params}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(p/let [icon (retrieve-icon conn id)] (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)))) (decode-row icon))))
(def ^:private sql:single-icon (def ^:private sql:single-icon

View file

@ -40,7 +40,7 @@
(sq/defquery ::image-libraries (sq/defquery ::image-libraries
[{:keys [profile-id team-id]}] [{:keys [profile-id team-id]}]
(db/with-atomic [conn db/pool] (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]))) (db/query conn [sql:libraries team-id])))
@ -55,7 +55,7 @@
[{:keys [profile-id id]}] [{:keys [profile-id id]}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn id)] (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))) lib)))
(def ^:private sql:single-library (def ^:private sql:single-library
@ -86,7 +86,7 @@
[{:keys [profile-id library-id] :as params}] [{:keys [profile-id library-id] :as params}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(p/let [lib (retrieve-library conn library-id)] (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) (-> (retrieve-images conn library-id)
(p/then' (fn [rows] (p/then' (fn [rows]
(->> rows (->> rows
@ -120,7 +120,7 @@
[{:keys [profile-id id] :as params}] [{:keys [profile-id id] :as params}]
(db/with-atomic [conn db/pool] (db/with-atomic [conn db/pool]
(p/let [img (retrieve-image conn id)] (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 (-> img
(images/resolve-urls :path :uri) (images/resolve-urls :path :uri)
(images/resolve-urls :thumb-path :thumb-uri))))) (images/resolve-urls :thumb-path :thumb-uri)))))

View file

@ -47,16 +47,37 @@
where team_id = $2 where team_id = $2
order by modified_at desc") 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 ::team-id ::us/uuid)
(s/def ::profile-id ::us/uuid) (s/def ::profile-id ::us/uuid)
(s/def ::project-id ::us/uuid)
(s/def ::projects-by-team (s/def ::projects-by-team
(s/keys :req-un [::profile-id ::team-id])) (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] (defn projects-by-team [profile-id team-id]
(db/query db/pool [sql:projects 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 (sq/defquery ::projects-by-team
[{:keys [profile-id team-id]}] [{:keys [profile-id team-id]}]
(projects-by-team 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))

View file

@ -40,5 +40,14 @@
(ex/raise :type :validation (ex/raise :type :validation
:code :not-authorized)))))) :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))))))

View file

@ -24,7 +24,7 @@
#"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$") #"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
(def uuid-rx (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 ;; --- Conformers

View file

@ -0,0 +1,3 @@
<svg width="500" height="500" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.99941 1.62266C8.01413 1.36698 7.74905 1.14313 7.49807 1.21294C7.35967 1.27903 7.02149 1.60601 7.02149 1.60601C7.02149 1.60601 3.82775 4.79865 2.80464 5.76808C2.68664 5.81588 2.6167 5.68421 2.54114 5.62249C1.48872 4.57167 1.68802 4.66986 0.628214 3.62654C0.403393 3.46589 0.0441303 3.61642 0.00630665 3.8924C-0.0278168 4.07137 0.0811424 4.23539 0.212762 4.34466C1.2602 5.45375 1.12484 5.34669 2.1814 6.44725C2.31167 6.56977 2.42611 6.71875 2.58163 6.80902C2.77403 6.89051 2.99255 6.79154 3.11096 6.63235C4.317 5.44398 6.72612 3.05828 7.90933 1.84723C7.96218 1.78479 8.00392 1.70675 7.99941 1.62266Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 731 B

View file

@ -1,18 +1,18 @@
{ {
"dashboard.grid.delete" : { "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" : { "translations" : {
"en" : "Delete" "en" : "Delete"
} }
}, },
"dashboard.grid.edit" : { "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" : { "translations" : {
"en" : "Edit" "en" : "Edit"
} }
}, },
"dashboard.grid.empty-files" : { "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" : { "translations" : {
"en" : "You still have no files here" "en" : "You still have no files here"
} }
@ -25,7 +25,7 @@
"unused" : true "unused" : true
}, },
"dashboard.header.draft" : { "dashboard.header.draft" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:58" ], "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:57" ],
"translations" : { "translations" : {
"en" : "Draft" "en" : "Draft"
} }
@ -45,40 +45,40 @@
"unused" : true "unused" : true
}, },
"dashboard.header.new-file" : { "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" : { "translations" : {
"en" : "+ New file" "en" : "+ New file"
} }
}, },
"dashboard.header.new-project" : { "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" : { "translations" : {
"en" : "+ New project" "en" : "+ New project"
} }
}, },
"dashboard.header.profile-menu.logout" : { "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" : { "translations" : {
"en" : "Exit", "en" : "Exit",
"fr" : "Quitter" "fr" : "Quitter"
} }
}, },
"dashboard.header.profile-menu.password" : { "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" : { "translations" : {
"en" : "Password", "en" : "Password",
"fr" : "Mot de passe" "fr" : "Mot de passe"
} }
}, },
"dashboard.header.profile-menu.profile" : { "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" : { "translations" : {
"en" : "Profile", "en" : "Profile",
"fr" : "Profil" "fr" : "Profil"
} }
}, },
"dashboard.header.project" : { "dashboard.header.project" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:74" ], "used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:73" ],
"translations" : { "translations" : {
"en" : "Project %s" "en" : "Project %s"
} }
@ -127,25 +127,25 @@
"unused" : true "unused" : true
}, },
"dashboard.library.menu.icons" : { "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" : { "translations" : {
"en" : "Icons" "en" : "Icons"
} }
}, },
"dashboard.library.menu.images" : { "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" : { "translations" : {
"en" : "Images" "en" : "Images"
} }
}, },
"dashboard.library.menu.palettes" : { "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" : { "translations" : {
"en" : "Palettes" "en" : "Palettes"
} }
}, },
"dashboard.search.no-matches-for" : { "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" : { "translations" : {
"en" : "No matches found for \"%s\"" "en" : "No matches found for \"%s\""
} }
@ -157,13 +157,13 @@
"unused" : true "unused" : true
}, },
"dashboard.search.searching-for" : { "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" : { "translations" : {
"en" : "Searching for %s..." "en" : "Searching for %s..."
} }
}, },
"dashboard.search.type-something" : { "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" : { "translations" : {
"en" : "Type to search results" "en" : "Type to search results"
} }
@ -200,19 +200,19 @@
} }
}, },
"ds.button.delete" : { "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" : { "translations" : {
"en" : "Delete" "en" : "Delete"
} }
}, },
"ds.button.rename" : { "ds.button.rename" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:146" ], "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:149" ],
"translations" : { "translations" : {
"en" : "Rename" "en" : "Rename"
} }
}, },
"ds.button.save" : { "ds.button.save" : {
"used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:51" ], "used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:54" ],
"translations" : { "translations" : {
"en" : "Save" "en" : "Save"
} }
@ -253,21 +253,21 @@
"unused" : true "unused" : true
}, },
"ds.confirm-cancel" : { "ds.confirm-cancel" : {
"used-in" : [ "src/uxbox/main/ui/confirm.cljs:38" ], "used-in" : [ "src/uxbox/main/ui/confirm.cljs:19" ],
"translations" : { "translations" : {
"en" : "Cancel", "en" : "Cancel",
"fr" : "Annuler" "fr" : "Annuler"
} }
}, },
"ds.confirm-ok" : { "ds.confirm-ok" : {
"used-in" : [ "src/uxbox/main/ui/confirm.cljs:34" ], "used-in" : [ "src/uxbox/main/ui/confirm.cljs:20" ],
"translations" : { "translations" : {
"en" : "Ok", "en" : "Ok",
"fr" : "Ok" "fr" : "Ok"
} }
}, },
"ds.confirm-title" : { "ds.confirm-title" : {
"used-in" : [ "src/uxbox/main/ui/confirm.cljs:28" ], "used-in" : [ "src/uxbox/main/ui/confirm.cljs:18" ],
"translations" : { "translations" : {
"en" : "Are you sure?", "en" : "Are you sure?",
"fr" : "Êtes-vous sûr ?" "fr" : "Êtes-vous sûr ?"
@ -380,7 +380,7 @@
"unused" : true "unused" : true
}, },
"ds.new-file" : { "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" : { "translations" : {
"en" : "+ New File", "en" : "+ New File",
"fr" : null "fr" : null
@ -450,7 +450,7 @@
"unused" : true "unused" : true
}, },
"ds.store-images-title" : { "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" : { "translations" : {
"en" : "IMAGES STORE", "en" : "IMAGES STORE",
"fr" : "BOUTIQUE" "fr" : "BOUTIQUE"
@ -499,7 +499,7 @@
"unused" : true "unused" : true
}, },
"ds.your-images-title" : { "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" : { "translations" : {
"en" : "YOUR IMAGES", "en" : "YOUR IMAGES",
"fr" : "VOS IMAGES" "fr" : "VOS IMAGES"
@ -534,21 +534,21 @@
} }
}, },
"errors.generic" : { "errors.generic" : {
"used-in" : [ "src/uxbox/main/ui.cljs:160" ], "used-in" : [ "src/uxbox/main/ui.cljs:162" ],
"translations" : { "translations" : {
"en" : "Something wrong has happened.", "en" : "Something wrong has happened.",
"fr" : "Quelque chose c'est mal passé." "fr" : "Quelque chose c'est mal passé."
} }
}, },
"errors.network" : { "errors.network" : {
"used-in" : [ "src/uxbox/main/ui.cljs:154" ], "used-in" : [ "src/uxbox/main/ui.cljs:156" ],
"translations" : { "translations" : {
"en" : "Unable to connect to backend server.", "en" : "Unable to connect to backend server.",
"fr" : "Impossible de se connecter au serveur principal." "fr" : "Impossible de se connecter au serveur principal."
} }
}, },
"header.sitemap" : { "header.sitemap" : {
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:96" ], "used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:154" ],
"translations" : { "translations" : {
"en" : null, "en" : null,
"fr" : null "fr" : null
@ -562,28 +562,28 @@
} }
}, },
"image.import-library" : { "image.import-library" : {
"used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:170" ], "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:169" ],
"translations" : { "translations" : {
"en" : "Import image from library", "en" : "Import image from library",
"fr" : "Importer une image depuis une librairie" "fr" : "Importer une image depuis une librairie"
} }
}, },
"image.new" : { "image.new" : {
"used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:84" ], "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:83" ],
"translations" : { "translations" : {
"en" : "New image", "en" : "New image",
"fr" : "Nouvelle image" "fr" : "Nouvelle image"
} }
}, },
"image.select" : { "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" : { "translations" : {
"en" : "Select from library", "en" : "Select from library",
"fr" : "Choisir depuis une librairie" "fr" : "Choisir depuis une librairie"
} }
}, },
"image.upload" : { "image.upload" : {
"used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:102" ], "used-in" : [ "src/uxbox/main/ui/workspace/images.cljs:101" ],
"translations" : { "translations" : {
"en" : "Upload file", "en" : "Upload file",
"fr" : "Envoyer un fichier" "fr" : "Envoyer un fichier"
@ -645,7 +645,7 @@
"unused" : true "unused" : true
}, },
"modal.create-color.new-color" : { "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" : { "translations" : {
"en" : "New Color" "en" : "New Color"
} }
@ -658,7 +658,7 @@
} }
}, },
"profile.recovery.go-to-login" : { "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" : { "translations" : {
"en" : "Go back!", "en" : "Go back!",
"fr" : "Retour!" "fr" : "Retour!"
@ -798,23 +798,12 @@
} }
}, },
"settings.password" : { "settings.password" : {
"used-in" : [ "src/uxbox/main/ui/settings/header.cljs:37" ], "used-in" : [ "src/uxbox/main/ui/settings/header.cljs:34" ],
"translations" : { "translations" : {
"en" : "PASSWORD", "en" : "PASSWORD",
"fr" : "MOT DE PASSE" "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" : { "settings.password.change-password" : {
"used-in" : [ "src/uxbox/main/ui/settings/password.cljs:64" ], "used-in" : [ "src/uxbox/main/ui/settings/password.cljs:64" ],
"translations" : { "translations" : {
@ -851,14 +840,14 @@
} }
}, },
"settings.profile" : { "settings.profile" : {
"used-in" : [ "src/uxbox/main/ui/settings/header.cljs:34" ], "used-in" : [ "src/uxbox/main/ui/settings/header.cljs:30" ],
"translations" : { "translations" : {
"en" : "PROFILE", "en" : "PROFILE",
"fr" : "PROFIL" "fr" : "PROFIL"
} }
}, },
"settings.profile.lang" : { "settings.profile.lang" : {
"used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:91" ], "used-in" : [ "src/uxbox/main/ui/settings/profile.cljs:92" ],
"translations" : { "translations" : {
"en" : "Default language", "en" : "Default language",
"fr" : "Langue par défaut" "fr" : "Langue par défaut"
@ -872,28 +861,28 @@
} }
}, },
"settings.profile.section-basic-data" : { "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" : { "translations" : {
"en" : "Name, username and email", "en" : "Name, username and email",
"fr" : "Nom, nom d'utilisateur et adresse email" "fr" : "Nom, nom d'utilisateur et adresse email"
} }
}, },
"settings.profile.your-avatar" : { "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" : { "translations" : {
"en" : "Your avatar", "en" : "Your avatar",
"fr" : "Votre avatar" "fr" : "Votre avatar"
} }
}, },
"settings.profile.your-email" : { "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" : { "translations" : {
"en" : null, "en" : null,
"fr" : null "fr" : null
} }
}, },
"settings.profile.your-name" : { "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" : { "translations" : {
"en" : "Your name", "en" : "Your name",
"fr" : "Votre nom complet" "fr" : "Votre nom complet"
@ -907,7 +896,7 @@
"unused" : true "unused" : true
}, },
"settings.update-settings" : { "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" : { "translations" : {
"en" : "Update settings", "en" : "Update settings",
"fr" : "Mettre à jour les paramètres" "fr" : "Mettre à jour les paramètres"
@ -990,6 +979,66 @@
}, },
"unused" : true "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" : { "workspace.header.path" : {
"translations" : { "translations" : {
"en" : "Path", "en" : "Path",
@ -1025,29 +1074,65 @@
}, },
"unused" : true "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" : { "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" : { "translations" : {
"en" : "Color", "en" : "Color",
"fr" : "Couleur" "fr" : "Couleur"
} }
}, },
"workspace.options.font-family" : { "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" : { "translations" : {
"en" : "Font Family", "en" : "Font Family",
"fr" : "Police de caractères" "fr" : "Police de caractères"
} }
}, },
"workspace.options.font-options" : { "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" : { "translations" : {
"en" : "Fonts & Font Size", "en" : "Fonts & Font Size",
"fr" : "TODO" "fr" : "TODO"
} }
}, },
"workspace.options.font-weight" : { "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" : { "translations" : {
"en" : "Font Size & Weight", "en" : "Font Size & Weight",
"fr" : "Taille et graisse" "fr" : "Taille et graisse"
@ -1061,14 +1146,14 @@
} }
}, },
"workspace.options.line-height-letter-spacing" : { "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" : { "translations" : {
"en" : "Line height and Letter spacing", "en" : "Line height and Letter spacing",
"fr" : "Hauteur de ligne et Espacement de caractères" "fr" : "Hauteur de ligne et Espacement de caractères"
} }
}, },
"workspace.options.measures" : { "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" : { "translations" : {
"en" : "Size, position & rotation", "en" : "Size, position & rotation",
"fr" : "Taille, position et rotation" "fr" : "Taille, position et rotation"
@ -1082,21 +1167,21 @@
} }
}, },
"workspace.options.position" : { "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" : { "translations" : {
"en" : "Position", "en" : "Position",
"fr" : "Position" "fr" : "Position"
} }
}, },
"workspace.options.rotation-radius" : { "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" : { "translations" : {
"en" : "Rotation & Radius", "en" : "Rotation & Radius",
"fr" : "TODO" "fr" : "TODO"
} }
}, },
"workspace.options.size" : { "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" : { "translations" : {
"en" : "Size", "en" : "Size",
"fr" : "Taille" "fr" : "Taille"
@ -1152,7 +1237,7 @@
} }
}, },
"workspace.options.text-align" : { "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" : { "translations" : {
"en" : "Text Alignment", "en" : "Text Alignment",
"fr" : "Alignement de texte" "fr" : "Alignement de texte"
@ -1180,7 +1265,7 @@
} }
}, },
"workspace.viewport.click-to-close-path" : { "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" : { "translations" : {
"en" : "Click to close the path" "en" : "Click to close the path"
} }

View file

@ -42,8 +42,9 @@
//################################################# //#################################################
@import 'main/partials/main-bar'; @import 'main/partials/main-bar';
@import 'main/partials/workspace-bar';
@import 'main/partials/workspace'; @import 'main/partials/workspace';
@import 'main/partials/workspace-bar';
@import 'main/partials/workspace-libraries';
@import 'main/partials/tool-bar'; @import 'main/partials/tool-bar';
@import 'main/partials/project-bar'; @import 'main/partials/project-bar';
@import 'main/partials/sidebar'; @import 'main/partials/sidebar';
@ -67,6 +68,7 @@
@import 'main/partials/context-menu'; @import 'main/partials/context-menu';
@import 'main/partials/debug-icons-preview'; @import 'main/partials/debug-icons-preview';
@import 'main/partials/editable-label'; @import 'main/partials/editable-label';
@import 'main/partials/tab-container';
//################################################# //#################################################
// Resources // Resources

View file

@ -11,21 +11,23 @@
background-color: $color-gray-50; background-color: $color-gray-50;
border-top: 1px solid $color-gray-60; border-top: 1px solid $color-gray-60;
display: flex; display: flex;
padding: 1rem;
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
z-index: 11; z-index: 11;
.right-arrow,
.left-arrow { & .right-arrow,
& .left-arrow {
cursor: pointer; cursor: pointer;
svg { svg {
fill: $color-gray-light; fill: $color-gray-light;
height: 30px; height: 1rem;
margin: 0 .5rem; margin: 0 .5rem;
width: 30px; width: 1rem;
} }
&:hover { &:hover {
svg { svg {
fill: $color-gray-darker; fill: $color-gray-darker;
@ -35,20 +37,40 @@
display: none; display: none;
} }
} }
.left-arrow { .left-arrow {
transform: rotate(180deg); transform: rotate(180deg);
padding-top: 10px;
} }
&.fade-out-down { &.fade-out-down {
@include animation(0,.5s,fadeOutDown); @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 { .color-palette-actions {
align-self: stretch;
border: 1px solid #1F1F1F;
cursor: pointer;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-shrink: 0; flex-shrink: 0;
justify-content: center;
margin-right: .5rem; margin-right: .5rem;
width: 200px; padding: 0.5rem;
.color-palette-buttons { .color-palette-buttons {
align-items: center; align-items: center;
display: flex; display: flex;
@ -56,6 +78,15 @@
} }
} }
.color-palette-actions-button {
cursor: pointer;
& svg {
width: 1rem;
height: 1rem;
fill: #AFB2BF;
}
}
.btn-palette { .btn-palette {
align-items: center; align-items: center;
border: 2px solid $color-gray-lighter; border: 2px solid $color-gray-lighter;
@ -90,6 +121,8 @@
display: flex; display: flex;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
height: 4.8rem;
padding: 0.25rem;
} }
.color-palette-inside { .color-palette-inside {
@ -106,15 +139,14 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-shrink: 0; flex-shrink: 0;
margin: 0 10px;
position: relative; position: relative;
flex-basis: 66px; flex-basis: 66px;
.color { .color {
background-color: $color-gray-lighter; background-color: $color-gray-lighter;
border: 2px solid $color-gray-60; border: 2px solid $color-gray-60;
border-radius: 50%; border-radius: 50%;
flex-shrink: 0; flex-shrink: 0;
margin-bottom: .4rem;
padding: 1.5rem; padding: 1.5rem;
} }
.color-text { .color-text {

View file

@ -17,7 +17,9 @@
border-radius: $br-small; border-radius: $br-small;
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25); box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
left: -$size-4; left: -$size-4;
max-height: 30rem;
min-width: 7rem; min-width: 7rem;
overflow: auto;
position: absolute; position: absolute;
top: $size-3; top: $size-3;
} }
@ -27,9 +29,25 @@
display: block; display: block;
font-size: $fs12; font-size: $fs12;
padding: $size-2 $size-4; padding: $size-2 $size-4;
white-space: nowrap;
&:hover { &:hover {
color: $color-black; 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;
}
}

View file

@ -6,8 +6,6 @@
// Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com> // Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
.sitemap { .sitemap {
max-height: 180px;
.tool-window-bar { .tool-window-bar {
.add-page { .add-page {

View file

@ -11,7 +11,7 @@
height: 100%; height: 100%;
position: fixed; position: fixed;
right: 0; right: 0;
width: 230px; width: 15rem;
z-index: 10; z-index: 10;
&.settings-bar-left { &.settings-bar-left {
@ -20,10 +20,23 @@
.settings-bar-inside { .settings-bar-inside {
align-items: center; 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; flex-direction: column;
overflow-y: auto; overflow: hidden;
overflow-x: hidden;
padding-top: 40px; padding-top: 40px;
height: 100%; height: 100%;
@ -33,12 +46,14 @@
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;
width: 100%; width: 100%;
height: 100%;
.tool-window-bar { .tool-window-bar {
align-items: center; align-items: center;
display: flex; display: flex;
flex-shrink: 0; flex-shrink: 0;
padding: $small; padding: $small;
overflow: hidden;
svg { svg {
fill: $color-gray-20; fill: $color-gray-20;
@ -78,14 +93,8 @@
flex-wrap: wrap; flex-wrap: wrap;
overflow-y: auto; overflow-y: auto;
padding-bottom: $medium; padding-bottom: $medium;
height: 100%;
} }
&#layers {
padding-bottom: 30px;
} }
} }
}
} }

View file

@ -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%;
}

View file

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

View file

@ -266,4 +266,4 @@
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(-> state (-> state
(update-in [:library :selected-items library-id] #(into [item] %) ))))) (update-in [:library-items :palettes library-id] #(into [item] %) )))))

View file

@ -203,7 +203,7 @@
(update [_ state] (update [_ state]
(let [{:keys [id] :as item} (assoc item :type :icon)] (let [{:keys [id] :as item} (assoc item :type :icon)]
(-> state (-> state
(update-in [:library :selected-items library-id] #(into [item] %))))))) (update-in [:library-items :icons library-id] #(into [item] %)))))))
;; ;; --- Icon Persisted ;; ;; --- Icon Persisted
;; ;;

View file

@ -395,5 +395,5 @@
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(-> state (-> state
(update-in [:library :selected-items library-id] #(into [item] %)))))) (update-in [:library-items :images library-id] #(into [item] %))))))

View file

@ -14,13 +14,16 @@
[uxbox.util.router :as r] [uxbox.util.router :as r]
[uxbox.util.uuid :as uuid])) [uxbox.util.uuid :as uuid]))
(defn initialize-workspace-libraries []
())
;; Retrieve libraries ;; Retrieve libraries
(declare retrieve-libraries-result) (declare retrieve-libraries-result)
(defn retrieve-libraries (defn retrieve-libraries
[type team-id] ([type] (retrieve-libraries type uuid/zero))
([type team-id]
(s/assert ::us/uuid team-id) (s/assert ::us/uuid team-id)
(let [method (case type (let [method (case type
:icons :icon-libraries :icons :icon-libraries
@ -30,14 +33,14 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(->> (rp/query! method {:team-id team-id}) (->> (rp/query! method {:team-id team-id})
(rx/map (partial retrieve-libraries-result type))))))) (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/reify ::retrieve-libraries-result
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(-> state (-> state
(assoc-in [:library type] result))))) (assoc-in [:library type team-id] result)))))
;; Retrieve library data ;; Retrieve library data
@ -53,15 +56,15 @@
:images :images :images :images
:palettes :colors)] :palettes :colors)]
(->> (rp/query! method {:library-id library-id}) (->> (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 (defn retrieve-library-data-result
[library-id data] [type library-id data]
(ptk/reify ::retrieve-library-data-result (ptk/reify ::retrieve-library-data-result
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(-> state (-> state
(assoc-in [:library :selected-items library-id] data))))) (assoc-in [:library-items type library-id] data)))))
;; Create library ;; Create library
@ -79,22 +82,22 @@
:palettes :create-color-library)] :palettes :create-color-library)]
(->> (rp/mutation! method {:team-id team-id (->> (rp/mutation! method {:team-id team-id
:name name}) :name name})
(rx/map (partial create-library-result type))))))) (rx/map (partial create-library-result type team-id)))))))
(defn create-library-result (defn create-library-result
[type result] [type team-id result]
(ptk/reify ::create-library-result (ptk/reify ::create-library-result
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(-> state (-> state
(update-in [:library type] #(into [result] %)))))) (update-in [:library type team-id] #(into [result] %))))))
;; Rename library ;; Rename library
(declare rename-library-result) (declare rename-library-result)
(defn rename-library (defn rename-library
[type library-id name] [type team-id library-id name]
(ptk/reify ::rename-library (ptk/reify ::rename-library
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
@ -104,10 +107,10 @@
:palettes :rename-color-library)] :palettes :rename-color-library)]
(->> (rp/mutation! method {:id library-id (->> (rp/mutation! method {:id library-id
:name name}) :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 (defn rename-library-result
[type library-id name] [type team-id library-id name]
(ptk/reify ::rename-library-result (ptk/reify ::rename-library-result
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
@ -118,14 +121,14 @@
(update-fn [libraries] (map change-name libraries))] (update-fn [libraries] (map change-name libraries))]
(-> state (-> state
(update-in [:library type] update-fn)))))) (update-in [:library type team-id] update-fn))))))
;; Delete library ;; Delete library
(declare delete-library-result) (declare delete-library-result)
(defn delete-library (defn delete-library
[type library-id] [type team-id library-id]
(ptk/reify ::delete-library (ptk/reify ::delete-library
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
@ -139,17 +142,17 @@
:images :delete-image-library :images :delete-image-library
:palettes :delete-color-library)] :palettes :delete-color-library)]
(->> (rp/mutation! method {:id library-id}) (->> (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 (defn delete-library-result
[type library-id] [type team-id library-id]
(ptk/reify ::create-library-result (ptk/reify ::create-library-result
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [update-fn (fn [libraries] (let [update-fn (fn [libraries]
(filterv #(not= library-id (:id %)) libraries))] (filterv #(not= library-id (:id %)) libraries))]
(-> state (-> state
(update-in [:library type] update-fn)))))) (update-in [:library type team-id] update-fn))))))
;; Delete library item ;; Delete library item
@ -175,7 +178,7 @@
(let [update-fn (fn [items] (let [update-fn (fn [items]
(filterv #(not= item-id (:id %)) items))] (filterv #(not= item-id (:id %)) items))]
(-> state (-> state
(update-in [:library :selected-items library-id] update-fn)))))) (update-in [:library-items type library-id] update-fn))))))
;; Batch delete ;; Batch delete
@ -204,4 +207,25 @@
update-fn (fn [items] update-fn (fn [items]
(filterv #(not (item-ids-set (:id %))) items))] (filterv #(not (item-ids-set (:id %))) items))]
(-> state (-> 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)))))

View file

@ -66,6 +66,7 @@
(declare fetch-users) (declare fetch-users)
(declare fetch-images) (declare fetch-images)
(declare fetch-project)
(declare handle-who) (declare handle-who)
(declare handle-pointer-update) (declare handle-pointer-update)
(declare handle-pointer-send) (declare handle-pointer-send)
@ -294,7 +295,8 @@
(defn initialize (defn initialize
"Initialize the workspace state." "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 file-id)
(us/verify ::us/uuid page-id) (us/verify ::us/uuid page-id)
(ptk/reify ::initialize (ptk/reify ::initialize
@ -305,9 +307,11 @@
(rx/merge (rx/merge
(rx/of (fetch-file-with-users file-id) (rx/of (fetch-file-with-users file-id)
(fetch-pages 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/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/take 1)
(rx/do (fn [_] (rx/do (fn [_]
(uxbox.util.timers/schedule 500 #(reset! st/loader false)))) (uxbox.util.timers/schedule 500 #(reset! st/loader false))))
@ -355,7 +359,8 @@
(rx/of (initialize-page-persistence page-id))))) (rx/of (initialize-page-persistence page-id)))))
(defn finalize (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 file-id)
(us/verify ::us/uuid page-id) (us/verify ::us/uuid page-id)
(ptk/reify ::finalize (ptk/reify ::finalize
@ -493,6 +498,7 @@
(s/def ::data ::cp/data) (s/def ::data ::cp/data)
(s/def ::file ::dd/file) (s/def ::file ::dd/file)
(s/def ::project ::dd/project)
(s/def ::page (s/def ::page
(s/keys :req-un [::id (s/keys :req-un [::id
::name ::name
@ -546,6 +552,25 @@
state state
users)))) 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 ;; --- Fetch Pages
@ -770,16 +795,20 @@
;; --- Toggle layout flag ;; --- Toggle layout flag
(defn toggle-layout-flag (defn toggle-layout-flag
[flag] [& flags]
(us/verify keyword? flag) ;; Verify all?
#_(us/verify keyword? flag)
(ptk/reify ::toggle-layout-flag (ptk/reify ::toggle-layout-flag
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [reduce-fn
(fn [state flag]
(update state :workspace-layout (update state :workspace-layout
(fn [flags] (fn [flags]
(if (contains? flags flag) (if (contains? flags flag)
(disj flags flag) (disj flags flag)
(conj flags flag))))))) (conj flags flag)))))]
(reduce reduce-fn state flags)))))
;; --- Tooltip ;; --- Tooltip
@ -1103,6 +1132,7 @@
(rx/empty)))))) (rx/empty))))))
;; --- Toggle shape's selection status (selected or deselected) ;; --- Toggle shape's selection status (selected or deselected)
(defn select-shape (defn select-shape
@ -1924,7 +1954,8 @@
(ptk/reify ::go-to-page (ptk/reify ::go-to-page
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (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} path-params {:file-id file-id}
query-params {:page-id page-id}] query-params {:page-id page-id}]
(rx/of (rt/nav :workspace path-params query-params)))))) (rx/of (rt/nav :workspace path-params query-params))))))
@ -1935,8 +1966,9 @@
(ptk/reify ::go-to-file (ptk/reify ::go-to-file
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [page-ids (get-in state [:files file-id :pages]) (let [project-id (get-in state [:workspace-project :id])
path-params {:file-id file-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)}] query-params {:page-id (first page-ids)}]
(rx/of (rt/nav :workspace path-params query-params)))))) (rx/of (rt/nav :workspace path-params query-params))))))

View file

@ -73,7 +73,7 @@
]]] ]]]
["/workspace/:file-id" :workspace]]) ["/workspace/:project-id/:file-id" :workspace]])
(mf/defc app-error (mf/defc app-error
[{:keys [error] :as props}] [{:keys [error] :as props}]
@ -119,9 +119,11 @@
(mf/element dashboard #js {:route route}) (mf/element dashboard #js {:route route})
:workspace :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]))] 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 :page-id page-id
:key file-id}]) :key file-id}])
nil))) nil)))

View file

@ -3,7 +3,8 @@
[rumext.alpha :as mf] [rumext.alpha :as mf]
[goog.object :as gobj] [goog.object :as gobj]
[uxbox.main.ui.components.dropdown :refer [dropdown-container]] [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/defc context-menu
{::mf/wrap-props false} {::mf/wrap-props false}
@ -13,12 +14,16 @@
(assert (vector? (gobj/get props "options")) "missing `options` prop") (assert (vector? (gobj/get props "options")) "missing `options` prop")
(let [open? (gobj/get props "show") (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? (when open?
[:> dropdown-container props [:> 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 [:ul.context-menu-items
(for [[action-name action-handler] options] (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} [:a.context-menu-action {:on-click action-handler}
action-name]])]]]))) action-name]])]]])))

View file

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

View file

@ -41,7 +41,8 @@
:edition false}) :edition false})
locale (i18n/use-locale) locale (i18n/use-locale)
on-navigate #(st/emit! (rt/nav :workspace on-navigate #(st/emit! (rt/nav :workspace
{:file-id (:id file)} {:project-id (:project-id file)
:file-id (:id file)}
{:page-id (first (:pages file))})) {:page-id (first (:pages file))}))
delete-fn #(st/emit! nil (dsh/delete-file (:id file))) delete-fn #(st/emit! nil (dsh/delete-file (:id file)))
on-delete #(do on-delete #(do

View file

@ -122,7 +122,7 @@
(dlib/retrieve-libraries :icons (:id item)) (dlib/retrieve-libraries :icons (:id item))
(st/emit! (rt/nav path {:team-id team-id :library-id (:id item)}))))} (st/emit! (rt/nav path {:team-id team-id :library-id (:id item)}))))}
[:& editable-label {:value (:name 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 (mf/defc library-top-menu
@ -136,7 +136,7 @@
[:& editable-label {:edit (:editing-name @state) [:& editable-label {:edit (:editing-name @state)
:on-change #(do :on-change #(do
(stop-editing) (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) :on-cancel #(swap! state assoc :editing-name false)
:class-name "library-top-menu-current-element-name" :class-name "library-top-menu-current-element-name"
:value (:name selected)}] :value (:name selected)}]
@ -155,7 +155,7 @@
(modal/show! (modal/show!
confirm-dialog confirm-dialog
{:on-accept #(do {: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}))) (st/emit! (rt/nav path {:team-id team-id})))
:message "Are you sure you want to delete this library?" :message "Are you sure you want to delete this library?"
:accept-text "Delete"})))]]}]] :accept-text "Delete"})))]]}]]
@ -301,12 +301,12 @@
:message "Are you sure you want to delete this color?" :message "Are you sure you want to delete this color?"
:accept-text "Delete"}))]]}]]]))) :accept-text "Delete"}))]]}]]])))
(defn libraries-ref [section] (defn libraries-ref [section team-id]
(-> (comp (l/key :library) (l/key section)) (-> (comp (l/key :library) (l/key section) (l/key team-id))
(l/derive st/state))) (l/derive st/state)))
(defn selected-items-ref [library-id] (defn selected-items-ref [section library-id]
(-> (comp (l/key :library) (l/key :selected-items) (l/key library-id)) (-> (comp (l/key :library-items) (l/key section) (l/key library-id))
(l/derive st/state))) (l/derive st/state)))
(def last-deleted-library-ref (def last-deleted-library-ref
@ -316,8 +316,8 @@
(mf/defc library-page (mf/defc library-page
[{:keys [team-id library-id section]}] [{:keys [team-id library-id section]}]
(let [state (mf/use-state {:selected #{}}) (let [state (mf/use-state {:selected #{}})
libraries (mf/deref (libraries-ref section)) libraries (mf/deref (libraries-ref section team-id))
items (mf/deref (selected-items-ref library-id)) items (mf/deref (selected-items-ref section library-id))
last-deleted-library (mf/deref last-deleted-library-ref) last-deleted-library (mf/deref last-deleted-library-ref)
selected-library (first (filter #(= (:id %) library-id) libraries))] selected-library (first (filter #(= (:id %) library-id) libraries))]

View file

@ -60,16 +60,14 @@
(mf/defc workspace-content (mf/defc workspace-content
[{:keys [page file layout] :as params}] [{:keys [page file layout] :as params}]
(let [frame (mf/use-ref nil) (let [frame (mf/use-ref nil)
left-sidebar? (not (empty? (keep layout [:layers :sitemap left-sidebar? (not (empty? (keep layout [:layers :sitemap :document-history :libraries])))
:document-history]))) right-sidebar? (not (empty? (keep layout [:icons :drawtools :element-options])))
right-sidebar? (not (empty? (keep layout [:icons :drawtools
:element-options])))
classes (classnames classes (classnames
:no-tool-bar-right (not right-sidebar?) :no-tool-bar-right (not right-sidebar?)
:no-tool-bar-left (not left-sidebar?))] :no-tool-bar-left (not left-sidebar?))]
[:* [:*
(when (:colorpalette layout) (when (:colorpalette layout)
[:& colorpalette]) [:& colorpalette {:left-sidebar? left-sidebar?}])
[:main.main-content [:main.main-content
[:& context-menu {}] [:& context-menu {}]
@ -101,13 +99,13 @@
(mf/defc workspace (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/deps file-id page-id)
(mf/use-effect (mf/use-effect
(fn [] (fn []
(st/emit! (dw/initialize file-id page-id)) (st/emit! (dw/initialize project-id file-id page-id))
#(st/emit! (dw/finalize file-id page-id))))) #(st/emit! (dw/finalize project-id file-id page-id)))))
(-> (mf/deps file-id) (-> (mf/deps file-id)
(mf/use-effect (mf/use-effect

View file

@ -13,16 +13,30 @@
[uxbox.builtins.icons :as i] [uxbox.builtins.icons :as i]
[uxbox.main.data.colors :as udc] [uxbox.main.data.colors :as udc]
[uxbox.main.data.workspace :as udw] [uxbox.main.data.workspace :as udw]
[uxbox.main.data.library :as dlib]
[uxbox.main.store :as st] [uxbox.main.store :as st]
[uxbox.main.ui.keyboard :as kbd] [uxbox.main.ui.keyboard :as kbd]
[uxbox.util.color :refer [hex->rgb]] [uxbox.util.color :refer [hex->rgb]]
[uxbox.util.data :refer [read-string seek]] [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 ;; --- Refs
(def collections-iref (def project-ref
(-> (l/key :colors-collections) (-> (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))) (l/derive st/state)))
;; --- Components ;; --- Components
@ -30,8 +44,6 @@
(mf/defc palette-item (mf/defc palette-item
[{:keys [color] :as props}] [{:keys [color] :as props}]
(let [rgb-vec (hex->rgb color) (let [rgb-vec (hex->rgb color)
rgb-color (apply str "" (interpose ", " rgb-vec))
select-color select-color
(fn [event] (fn [event]
(if (kbd/shift? event) (if (kbd/shift? event)
@ -41,46 +53,39 @@
[:div.color-cell {:key (str color) [:div.color-cell {:key (str color)
:on-click select-color} :on-click select-color}
[:span.color {:style {:background color}}] [:span.color {:style {:background color}}]
[:span.color-text color] [:span.color-text color]]))
[:span.color-text rgb-color]]))
(mf/defc palette (mf/defc palette
[{:keys [colls] :as props}] [{:keys [libraries left-sidebar?] :as props}]
(let [local (mf/use-state {})
colls (->> colls
(filter :id)
(sort-by :name))
coll (or (:selected @local) (when (and libraries (-> libraries count (> 0)))
(first colls)) (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) doc-width (.. js/document -documentElement -clientWidth)
width (:width @local (* doc-width 0.84)) width (:width @state (* doc-width 0.84))
offset (:offset @local 0) offset (:offset @state 0)
visible (/ width 86) visible (/ width 86)
invisible (- (count (:colors coll)) visible) invisible (- (count items) visible)
close #(st/emit! (udw/toggle-layout-flag :colorpalette)) close #(st/emit! (udw/toggle-layout-flag :colorpalette))
container (mf/use-ref nil) container (mf/use-ref nil)
container-child (mf/use-ref nil) container-child (mf/use-ref nil)
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-left-arrow-click on-left-arrow-click
(fn [event] (fn [event]
(when (> offset 0) (when (> offset 0)
(let [element (mf/ref-val container-child)] (let [element (mf/ref-val container-child)]
(swap! local update :offset dec)))) (swap! state update :offset dec))))
on-right-arrow-click on-right-arrow-click
(fn [event] (fn [event]
(when (< offset invisible) (when (< offset invisible)
(let [element (mf/ref-val container-child)] (let [element (mf/ref-val container-child)]
(swap! local update :offset inc)))) (swap! state update :offset inc))))
on-scroll on-scroll
(fn [event] (fn [event]
@ -92,38 +97,42 @@
(fn [] (fn []
(let [dom (mf/ref-val container) (let [dom (mf/ref-val container)
width (.-clientWidth dom)] width (.-clientWidth dom)]
(when (not= (:width @local) width) (when (not= (:width @state) width)
(swap! local assoc :width width))))] (swap! state assoc :width width))))
handle-click
(fn [library]
(st/emit! (dlib/select-library :palettes (:id library))))]
(mf/use-effect nil after-render) (mf/use-effect nil after-render)
[:div.color-palette [: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 [:div.color-palette-actions
[:select.input-select {:on-change select-coll {:on-click #(swap! state assoc :show-menu true)}
:default-value (pr-str (:id coll))} [:div.color-palette-actions-button i/actions]]
(for [item colls]
[:option {:key (:id item) :value (pr-str (:id item))}
(:name 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] [: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-content {:ref container :on-wheel on-scroll}
[:div.color-palette-inside {:ref container-child [:div.color-palette-inside {:ref container-child
:style {:position "relative" :style {:position "relative"
:width (str (* 86 (count (:colors coll))) "px") :width (str (* 86 (count items)) "px")
:right (str (* 86 offset) "px")}} :right (str (* 86 offset) "px")}}
(for [color (:colors coll)] (for [item items]
[:& palette-item {:color color :key color}])]] [:& palette-item {:color (:content item) :key (:id item)}])]]
[:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide] [:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide]]))))
[:span.close-palette {:on-click close} i/close]]))
(mf/defc colorpalette (mf/defc colorpalette
[props] [{:keys [left-sidebar?]}]
(let [colls (mf/deref collections-iref)] (let [team-id (-> project-ref mf/deref :team-id)
#_(mf/use-effect #(st/emit! (udc/fetch-collections))) libraries (-> libraries-ref mf/deref vals flatten)]
[:& palette {:colls (vals colls)}])) (mf/use-effect #(st/emit! (dlib/retrieve-libraries :palettes)
(dlib/retrieve-libraries :palettes team-id)))
[:& palette {:left-sidebar? left-sidebar?
:libraries libraries}]))

View file

@ -68,10 +68,12 @@
[:li.tooltip.tooltip-right [:li.tooltip.tooltip-right
{:alt "Layers" {:alt "Layers"
:class (when (contains? layout :layers) "selected") :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] i/layers]
[:li.tooltip.tooltip-right [: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] i/icon-set]
[:li.tooltip.tooltip-right [:li.tooltip.tooltip-right
{:alt "History"} {:alt "History"}

View file

@ -11,11 +11,13 @@
(ns uxbox.main.ui.workspace.sidebar (ns uxbox.main.ui.workspace.sidebar
(:require (:require
[rumext.alpha :as mf] [rumext.alpha :as mf]
[cuerdas.core :as str]
[uxbox.main.ui.workspace.sidebar.history :refer [history-toolbox]] [uxbox.main.ui.workspace.sidebar.history :refer [history-toolbox]]
[uxbox.main.ui.workspace.sidebar.icons :refer [icons-toolbox]] [uxbox.main.ui.workspace.sidebar.icons :refer [icons-toolbox]]
[uxbox.main.ui.workspace.sidebar.layers :refer [layers-toolbox]] [uxbox.main.ui.workspace.sidebar.layers :refer [layers-toolbox]]
[uxbox.main.ui.workspace.sidebar.options :refer [options-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) ;; --- Left Sidebar (Component)
@ -24,12 +26,15 @@
[{:keys [layout page file] :as props}] [{:keys [layout page file] :as props}]
[:aside.settings-bar.settings-bar-left [:aside.settings-bar.settings-bar-left
[:div.settings-bar-inside [:div.settings-bar-inside
{:data-layout (str/join "," layout)}
(when (contains? layout :sitemap) (when (contains? layout :sitemap)
[:& sitemap-toolbox {:file file :page page}]) [:& sitemap-toolbox {:file file :page page}])
(when (contains? layout :document-history) (when (contains? layout :document-history)
[:& history-toolbox]) [:& history-toolbox])
(when (contains? layout :layers) (when (contains? layout :layers)
[:& layers-toolbox {:page page}])]]) [:& layers-toolbox {:page page}])
(when (contains? layout :libraries)
[:& libraries-toolbox])]])
;; --- Right Sidebar (Component) ;; --- Right Sidebar (Component)

View file

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

View file

@ -205,3 +205,4 @@
;; (if (::some-interrupt (ex-data e#)) ;; (if (::some-interrupt (ex-data e#))
;; nil ;; nil
;; (throw e#))))))) ;; (throw e#)))))))