mirror of
https://github.com/penpot/penpot.git
synced 2026-05-07 00:58:48 +00:00
commit
394d238f97
@ -23,6 +23,8 @@
|
||||
{:http-server-port 6060
|
||||
:http-server-cors "http://localhost:3449"
|
||||
:database-uri "postgresql://127.0.0.1/uxbox"
|
||||
:database-username "uxbox"
|
||||
:database-password "uxbox"
|
||||
:media-directory "resources/public/media"
|
||||
:assets-directory "resources/public/static"
|
||||
:media-uri "http://localhost:6060/media/"
|
||||
|
||||
@ -66,9 +66,20 @@
|
||||
values ($1, $2, $3, $4, $5, $6)
|
||||
returning id;")
|
||||
|
||||
(def sql:create-icon-library
|
||||
"insert into icon_library (team_id, name)
|
||||
values ($1, $2)
|
||||
returning id;")
|
||||
|
||||
(def sql:create-icon
|
||||
"insert into icon_library (library_id, name, content, metadata)
|
||||
values ($1, $2, $3, $4)
|
||||
returning id;")
|
||||
|
||||
|
||||
(def preset-small
|
||||
{:num-teams 50
|
||||
:num-profiles 50
|
||||
{:num-teams 5
|
||||
:num-profiles 5
|
||||
:num-profiles-per-team 5
|
||||
:num-projects-per-team 5
|
||||
:num-files-per-project 5
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::library-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
|
||||
(defn decode-row
|
||||
[{:keys [metadata] :as row}]
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::library-id ::us/uuid)
|
||||
|
||||
;; --- Query: Image Librarys
|
||||
|
||||
@ -78,14 +78,68 @@
|
||||
"en" : "Type to search results"
|
||||
}
|
||||
},
|
||||
"dashboard.library.add-item.icons" : {
|
||||
"translations" : {
|
||||
"en" : "+ New icon"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"dashboard.library.add-item.images" : {
|
||||
"translations" : {
|
||||
"en" : "+ New image"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"dashboard.library.add-item.palettes" : {
|
||||
"translations" : {
|
||||
"en" : "+ New color"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"dashboard.library.add-library.icons" : {
|
||||
"translations" : {
|
||||
"en" : "+ New icon library"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"dashboard.library.add-library.images" : {
|
||||
"translations" : {
|
||||
"en" : "+ New image library"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"dashboard.library.add-library.palettes" : {
|
||||
"translations" : {
|
||||
"en" : "+ New palette"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"dashboard.library.menu.icons" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:39" ],
|
||||
"translations" : {
|
||||
"en" : "Icons"
|
||||
}
|
||||
},
|
||||
"dashboard.library.menu.images" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:43" ],
|
||||
"translations" : {
|
||||
"en" : "Images"
|
||||
}
|
||||
},
|
||||
"dashboard.library.menu.palettes" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:47" ],
|
||||
"translations" : {
|
||||
"en" : "Palettes"
|
||||
}
|
||||
},
|
||||
"dashboard.sidebar.drafts" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:113" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:112" ],
|
||||
"translations" : {
|
||||
"en" : "Drafts"
|
||||
}
|
||||
},
|
||||
"dashboard.sidebar.libraries" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:118" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:117" ],
|
||||
"translations" : {
|
||||
"en" : "Libraries"
|
||||
}
|
||||
@ -97,7 +151,7 @@
|
||||
"unused" : true
|
||||
},
|
||||
"dashboard.sidebar.recent" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:106" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:105" ],
|
||||
"translations" : {
|
||||
"en" : "Recent"
|
||||
}
|
||||
@ -109,6 +163,24 @@
|
||||
"fr" : "Accepter"
|
||||
}
|
||||
},
|
||||
"ds.button.delete" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:80", "src/uxbox/main/ui/dashboard/library.cljs:111", "src/uxbox/main/ui/dashboard/library.cljs:133", "src/uxbox/main/ui/dashboard/library.cljs:157" ],
|
||||
"translations" : {
|
||||
"en" : "Delete"
|
||||
}
|
||||
},
|
||||
"ds.button.rename" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:79" ],
|
||||
"translations" : {
|
||||
"en" : "Rename"
|
||||
}
|
||||
},
|
||||
"ds.button.save" : {
|
||||
"translations" : {
|
||||
"en" : "Save"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"ds.cancel" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/history.cljs:114" ],
|
||||
"translations" : {
|
||||
@ -166,7 +238,7 @@
|
||||
}
|
||||
},
|
||||
"ds.default-library-title" : {
|
||||
"used-in" : [ "src/uxbox/main/data/icons.cljs:90", "src/uxbox/main/data/colors.cljs:68", "src/uxbox/main/data/images.cljs:110" ],
|
||||
"used-in" : [ "src/uxbox/main/data/colors.cljs:68", "src/uxbox/main/data/icons.cljs:90", "src/uxbox/main/data/images.cljs:110" ],
|
||||
"translations" : {
|
||||
"en" : "Unnamed Collection (%s)",
|
||||
"fr" : "Collection sans nom (%s)"
|
||||
@ -244,7 +316,7 @@
|
||||
}
|
||||
},
|
||||
"ds.multiselect-bar.delete" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/icons.cljs:221", "src/uxbox/main/ui/dashboard/colors.cljs:214", "src/uxbox/main/ui/dashboard/images.cljs:187" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/colors.cljs:214", "src/uxbox/main/ui/dashboard/images.cljs:187", "src/uxbox/main/ui/dashboard/icons.cljs:221" ],
|
||||
"translations" : {
|
||||
"en" : "Delete",
|
||||
"fr" : "Supprimer"
|
||||
@ -300,7 +372,7 @@
|
||||
"unused" : true
|
||||
},
|
||||
"ds.search.placeholder" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:168" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/sidebar.cljs:140" ],
|
||||
"translations" : {
|
||||
"en" : "Search...",
|
||||
"fr" : "Rechercher..."
|
||||
@ -356,7 +428,7 @@
|
||||
}
|
||||
},
|
||||
"ds.uploaded-at" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/icons.cljs:309", "src/uxbox/main/ui/dashboard/images.cljs:271" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/images.cljs:271", "src/uxbox/main/ui/dashboard/icons.cljs:309" ],
|
||||
"translations" : {
|
||||
"en" : "Uploaded at %s",
|
||||
"fr" : "Mise en ligne : %s"
|
||||
@ -426,14 +498,14 @@
|
||||
}
|
||||
},
|
||||
"errors.generic" : {
|
||||
"used-in" : [ "src/uxbox/main/ui.cljs:135" ],
|
||||
"used-in" : [ "src/uxbox/main/ui.cljs:131" ],
|
||||
"translations" : {
|
||||
"en" : "Something wrong has happened.",
|
||||
"fr" : "Quelque chose c'est mal passé."
|
||||
}
|
||||
},
|
||||
"errors.network" : {
|
||||
"used-in" : [ "src/uxbox/main/ui.cljs:129" ],
|
||||
"used-in" : [ "src/uxbox/main/ui.cljs:125" ],
|
||||
"translations" : {
|
||||
"en" : "Unable to connect to backend server.",
|
||||
"fr" : "Impossible de se connecter au serveur principal."
|
||||
@ -538,7 +610,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!"
|
||||
@ -895,7 +967,7 @@
|
||||
}
|
||||
},
|
||||
"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"
|
||||
@ -937,7 +1009,7 @@
|
||||
}
|
||||
},
|
||||
"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:69" ],
|
||||
"translations" : {
|
||||
"en" : "Size, position & rotation",
|
||||
"fr" : "Taille, position et rotation"
|
||||
@ -951,21 +1023,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:98" ],
|
||||
"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:115" ],
|
||||
"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:71" ],
|
||||
"translations" : {
|
||||
"en" : "Size",
|
||||
"fr" : "Taille"
|
||||
@ -1053,5 +1125,8 @@
|
||||
"translations" : {
|
||||
"en" : "Click to close the path"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"modal.create-color.new-color": "New Color",
|
||||
"modal.create-color.edit-color": "Edit Color"
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ body {
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
transition: all .4s ease;
|
||||
// transition: all .4s ease;
|
||||
}
|
||||
|
||||
.global-zeroclipboard-container {
|
||||
|
||||
@ -26,10 +26,12 @@ $mix-percentage-dark: 81%;
|
||||
$mix-percentage-darker: 60%;
|
||||
$mix-percentage-light: 80%;
|
||||
$mix-percentage-lighter: 20%;
|
||||
$mix-percentage-lightest: 10%;
|
||||
|
||||
// Gray scale
|
||||
$color-gray-light: mix($color-gray, $color-white, $mix-percentage-light);
|
||||
$color-gray-lighter: mix($color-gray, $color-white, $mix-percentage-lighter);
|
||||
$color-gray-lightest: mix($color-gray, $color-white, $mix-percentage-lightest);
|
||||
$color-gray-dark: mix($color-gray, $color-black, $mix-percentage-dark);
|
||||
$color-gray-darker: mix($color-gray, $color-black, $mix-percentage-darker);
|
||||
$color-gray-10: #E3E3E3;
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
@import 'main/layouts/login';
|
||||
@import 'main/layouts/projects-page';
|
||||
@import 'main/layouts/recent-files-page';
|
||||
@import 'main/layouts/library-page';
|
||||
|
||||
//#################################################
|
||||
// Commons
|
||||
@ -63,6 +64,7 @@
|
||||
@import 'main/partials/colorpicker';
|
||||
@import 'main/partials/forms';
|
||||
@import 'main/partials/loader';
|
||||
@import 'main/partials/context-menu';
|
||||
|
||||
//#################################################
|
||||
// Resources
|
||||
|
||||
337
frontend/resources/styles/main/layouts/library-page.scss
Normal file
337
frontend/resources/styles/main/layouts/library-page.scss
Normal file
@ -0,0 +1,337 @@
|
||||
.library-page {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-rows: 40px 1fr;
|
||||
grid-template-columns: 14.5rem 1fr;
|
||||
grid-template-areas: "header header" "sidebar content";
|
||||
border-right: 1px solid $color-gray;
|
||||
|
||||
& .main-bar {
|
||||
grid-area: header;
|
||||
}
|
||||
|
||||
& .library-sidebar {
|
||||
grid-area: sidebar;
|
||||
}
|
||||
|
||||
& .library-content {
|
||||
grid-area: content;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.library-page #main-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.library-header-navigation {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.library-header-navigation-item {
|
||||
margin: 0 $size-4;
|
||||
color: $color-gray;
|
||||
text-transform: uppercase;
|
||||
border-bottom: 1px solid transparent;
|
||||
|
||||
&:hover, &.current {
|
||||
color: $color-black;
|
||||
border-bottom: 1px solid $color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.library-sidebar {
|
||||
background-color: $color-white;
|
||||
padding: $size-2;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.library-sidebar-add-item {
|
||||
background-color: $color-primary;
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
padding: $size-2;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-black;
|
||||
color: $color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.library-sidebar-list {
|
||||
margin-top: $size-4;
|
||||
overflow: scroll;
|
||||
height: 100%;
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
|
||||
.library-sidebar-list-element {
|
||||
padding: $size-4 $size-2;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
& a {
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $color-primary-lighter;
|
||||
}
|
||||
|
||||
&.current a {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.library-top-menu {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-bottom: 1px solid #e3e3e3;
|
||||
justify-content: space-between;
|
||||
padding: $size-2 1.5rem;
|
||||
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: #7C7C7C;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
fill: $color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
& > * {
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.library-top-menu-current-element {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.library-top-menu-current-element-name {
|
||||
font-size: 15px;
|
||||
line-height: 18px;
|
||||
color: $color-black;
|
||||
font-weight: normal;
|
||||
margin-right: $size-2;
|
||||
}
|
||||
|
||||
.library-top-menu-current-action {
|
||||
& svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.library-top-menu-actions {
|
||||
display: flex;
|
||||
|
||||
.btn-dashboard {
|
||||
background-color: transparent;
|
||||
margin-left: $size-2;
|
||||
}
|
||||
}
|
||||
|
||||
.library-page-cards-container {
|
||||
align-content: flex-start;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
padding: $size-2;
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
|
||||
.library-card {
|
||||
margin: $size-2;
|
||||
background: $color-white;
|
||||
border: 2px solid transparent;
|
||||
|
||||
&.library-icon, &.library-color {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
&.library-image {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
height: 200px;
|
||||
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
|
||||
& .library-card-footer-menu {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 2px solid $color-primary;
|
||||
}
|
||||
|
||||
&:hover .library-card-footer-menu {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.library-card .input-checkbox {
|
||||
margin: 0;
|
||||
top: $size-2;
|
||||
right: $size-2;
|
||||
position: absolute;
|
||||
|
||||
& label {
|
||||
margin: 0;
|
||||
|
||||
&:before {
|
||||
margin: 0;
|
||||
background-color: white;
|
||||
border: 1px solid #AFB2BF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.library-card-image {
|
||||
height: 136px;
|
||||
|
||||
.library-color & {
|
||||
height: 104px;
|
||||
}
|
||||
|
||||
padding: $size-2;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
|
||||
& object, & svg, & img {
|
||||
margin: auto;
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.library-card-footer {
|
||||
border-top: 1px solid $color-gray-lighter;
|
||||
padding: $size-2 $size-2 $size-2 $size-4;
|
||||
display: grid;
|
||||
grid-template-rows: 50% 50%;
|
||||
grid-template-columns: 1fr 16px 1px;
|
||||
grid-template-areas: "name . ." "timestamp menu options";
|
||||
|
||||
.library-card.library-color & {
|
||||
height: 50%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.library-card-footer-name {
|
||||
color: $color-black;
|
||||
grid-area: name;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.library-card-footer-timestamp {
|
||||
font-size: 12px;
|
||||
grid-area: timestamp;
|
||||
}
|
||||
|
||||
.library-card-footer-color {
|
||||
font-size: 15px;
|
||||
grid-area: timestamp;
|
||||
}
|
||||
|
||||
.library-card-footer-color-label {
|
||||
color: $color-gray;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.library-card-footer-color-rgb {
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
.library-card-footer-menu {
|
||||
grid-area: menu;
|
||||
cursor: pointer;
|
||||
|
||||
& svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.library-card-footer .context-menu {
|
||||
grid-area: options;
|
||||
& .context-menu-items {
|
||||
top: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.modal-create-color {
|
||||
position: relative;
|
||||
background-color: $color-white;
|
||||
padding: 4rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
& .sketch-picker {
|
||||
box-shadow: none !important;
|
||||
border: 1px solid $color-gray-lighter !important;
|
||||
border-radius: 0 !important;
|
||||
|
||||
& input {
|
||||
background-color: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
& .close {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
transform: rotate(45deg);
|
||||
top: 1rem;
|
||||
|
||||
svg {
|
||||
fill: $color-black;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
|
||||
&:hover {
|
||||
fill: $color-danger;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
& .btn-primary {
|
||||
width: 10rem;
|
||||
padding: 0.5rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-create-color-title {
|
||||
color: $color-black;
|
||||
font-size: 24px;
|
||||
font-weight: normal;
|
||||
}
|
||||
34
frontend/resources/styles/main/partials/context-menu.scss
Normal file
34
frontend/resources/styles/main/partials/context-menu.scss
Normal file
@ -0,0 +1,34 @@
|
||||
.context-menu {
|
||||
position: relative;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.context-menu.is-open {
|
||||
position: relative;
|
||||
display: block;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.context-menu-items {
|
||||
background: $color-white;
|
||||
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
|
||||
left: -$size-4;
|
||||
min-width: 7rem;
|
||||
position: absolute;
|
||||
top: $size-3;
|
||||
}
|
||||
|
||||
.context-menu-action {
|
||||
color: $color-black;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
padding: $size-2 $size-4;
|
||||
|
||||
&:hover {
|
||||
color: $color-black;
|
||||
background: $color-gray-lightest;
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@
|
||||
background-color: $color-white;
|
||||
|
||||
.library-bar-inside {
|
||||
border-right: 1px solid $color-gray-lighter;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
(def align-right (icon-xref :align-right))
|
||||
(def alignment (icon-xref :alignment))
|
||||
(def arrow (icon-xref :arrow))
|
||||
(def arrow-down (icon-xref :arrow-down))
|
||||
(def arrow-end (icon-xref :arrow-end))
|
||||
(def arrow-slide (icon-xref :arrow-slide))
|
||||
(def artboard (icon-xref :artboard))
|
||||
|
||||
@ -6,9 +6,11 @@
|
||||
|
||||
(ns uxbox.main.data.colors
|
||||
(:require
|
||||
[cljs.spec.alpha :as s]
|
||||
[beicon.core :as rx]
|
||||
[clojure.set :as set]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.main.repo :as rp]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.util.color :as color]
|
||||
@ -17,227 +19,311 @@
|
||||
[uxbox.util.time :as dt]
|
||||
[uxbox.util.uuid :as uuid]))
|
||||
|
||||
;; TODO: need a good refactor
|
||||
;; ;; TODO: need a good refactor
|
||||
;;
|
||||
;; ;; --- Initialize
|
||||
;;
|
||||
;; (declare fetch-collections)
|
||||
;; (declare persist-collections)
|
||||
;; (declare collections-fetched?)
|
||||
;;
|
||||
;; ;; --- Collections Fetched
|
||||
;;
|
||||
;; (defrecord CollectionsFetched [data]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [{:keys [version value]} data]
|
||||
;; (-> state
|
||||
;; (update :colors-collections merge value)
|
||||
;; (assoc ::version version)))))
|
||||
;;
|
||||
;; (defn collections-fetched
|
||||
;; [data]
|
||||
;; {:pre [(map? data)]}
|
||||
;; (CollectionsFetched. data))
|
||||
;;
|
||||
;; (defn collections-fetched?
|
||||
;; [v]
|
||||
;; (instance? CollectionsFetched v))
|
||||
;;
|
||||
;; ;; --- Fetch Collections
|
||||
;;
|
||||
;; (defrecord FetchCollections []
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (->> (rp/query! :user-attr {:key "color-collections"})
|
||||
;; (rx/map collections-fetched)
|
||||
;; (rx/catch (fn [{:keys [type] :as error}]
|
||||
;; (if (= type :not-found)
|
||||
;; (rx/empty)
|
||||
;; (rx/throw error)))))))
|
||||
;;
|
||||
;; (defn fetch-collections
|
||||
;; []
|
||||
;; (FetchCollections.))
|
||||
;;
|
||||
;; ;; --- Create Collection
|
||||
;;
|
||||
;; (defrecord CreateCollection [id]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [item {:name (tr "ds.default-library-title" (gensym "c"))
|
||||
;; :id id
|
||||
;; :created-at (dt/now)
|
||||
;; :type :own
|
||||
;; :colors #{}}]
|
||||
;; (assoc-in state [:colors-collections id] item)))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (rx/of (persist-collections)
|
||||
;; (rt/nav :dashboard/colors nil {:type :own :id id}))))
|
||||
;;
|
||||
;; (defn create-collection
|
||||
;; []
|
||||
;; (let [id (uuid/next)]
|
||||
;; (CreateCollection. id)))
|
||||
;;
|
||||
;; ;; --- Persist Collections
|
||||
;;
|
||||
;; (defrecord PersistCollections []
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [builtin? #(= :builtin (:type %))
|
||||
;; xform (remove (comp builtin? second))
|
||||
;; version (or (get state ::version) -1)
|
||||
;; value (->> (get state :colors-collections)
|
||||
;; (into {} xform))
|
||||
;; data {:key "color-collections"
|
||||
;; :val value}]
|
||||
;; (->> (rp/mutation! :upsert-user-attr data)
|
||||
;; (rx/map collections-fetched)))))
|
||||
;;
|
||||
;; (defn persist-collections
|
||||
;; []
|
||||
;; (PersistCollections.))
|
||||
;;
|
||||
;; ;; --- Rename Collection
|
||||
;;
|
||||
;; (defrecord RenameCollection [id name]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:colors-collections id :name] name))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (rx/of (persist-collections))))
|
||||
;;
|
||||
;; (defn rename-collection
|
||||
;; [item name]
|
||||
;; (RenameCollection. item name))
|
||||
;;
|
||||
;; ;; --- Delete Collection
|
||||
;;
|
||||
;; (defrecord DeleteCollection [id]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update state :colors-collections dissoc id))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (rx/of (persist-collections))))
|
||||
;;
|
||||
;; (defn delete-collection
|
||||
;; [id]
|
||||
;; (DeleteCollection. id))
|
||||
;;
|
||||
;; ;; --- Replace Color
|
||||
;;
|
||||
;; (defrecord AddColor [coll-id color]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update-in state [:colors-collections coll-id :colors] set/union #{color}))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (rx/of (persist-collections))))
|
||||
;;
|
||||
;; (defn add-color
|
||||
;; "Add or replace color in a collection."
|
||||
;; [coll-id color]
|
||||
;; (AddColor. coll-id color))
|
||||
;;
|
||||
;; ;; --- Remove Color
|
||||
;;
|
||||
;; (defrecord RemoveColors [id colors]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update-in state [:colors-collections id :colors]
|
||||
;; #(set/difference % colors)))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (rx/of (persist-collections))))
|
||||
;;
|
||||
;; (defn remove-colors
|
||||
;; "Remove color in a collection."
|
||||
;; [id colors]
|
||||
;; (RemoveColors. id colors))
|
||||
;;
|
||||
;; ;; --- Select color
|
||||
;;
|
||||
;; (defrecord SelectColor [color]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update-in state [:dashboard :colors :selected] conj color)))
|
||||
;;
|
||||
;; (defrecord DeselectColor [color]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update-in state [:dashboard :colors :selected] disj color)))
|
||||
;;
|
||||
;; (defrecord ToggleColorSelection [color]
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [selected (get-in state [:dashboard :colors :selected])]
|
||||
;; (rx/of
|
||||
;; (if (selected color)
|
||||
;; (DeselectColor. color)
|
||||
;; (SelectColor. color))))))
|
||||
;;
|
||||
;; (defn toggle-color-selection
|
||||
;; [color]
|
||||
;; {:pre [(color/hex? color)]}
|
||||
;; (ToggleColorSelection. color))
|
||||
;;
|
||||
;; ;; --- Copy Selected Color
|
||||
;;
|
||||
;; (defrecord CopySelected [id]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [selected (get-in state [:dashboard :colors :selected])]
|
||||
;; (update-in state [:colors-collections id :colors] set/union selected)))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (rx/of (persist-collections))))
|
||||
;;
|
||||
;; (defn copy-selected
|
||||
;; [id]
|
||||
;; {:pre [(or (uuid? id) (nil? id))]}
|
||||
;; (CopySelected. id))
|
||||
;;
|
||||
;; ;; --- Move Selected Color
|
||||
;;
|
||||
;; (defrecord MoveSelected [from to]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [selected (get-in state [:dashboard :colors :selected])]
|
||||
;; (-> state
|
||||
;; (update-in [:colors-collections from :colors] set/difference selected)
|
||||
;; (update-in [:colors-collections to :colors] set/union selected))))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (rx/of (persist-collections))))
|
||||
;;
|
||||
;; (defn move-selected
|
||||
;; [from to]
|
||||
;; {:pre [(or (uuid? from) (nil? from))
|
||||
;; (or (uuid? to) (nil? to))]}
|
||||
;; (MoveSelected. from to))
|
||||
;;
|
||||
;; ;; --- Delete Colors
|
||||
;;
|
||||
;; (defrecord DeleteColors [coll-id colors]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:dashboard :colors :selected] #{}))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (rx/of (remove-colors coll-id colors))))
|
||||
;;
|
||||
;; (defn delete-colors
|
||||
;; [coll-id colors]
|
||||
;; (DeleteColors. coll-id colors))
|
||||
|
||||
;; --- Initialize
|
||||
|
||||
(declare fetch-collections)
|
||||
(declare persist-collections)
|
||||
(declare collections-fetched?)
|
||||
;;;; NEW
|
||||
|
||||
;; --- Collections Fetched
|
||||
(declare fetch-color-libraries-result)
|
||||
|
||||
(defrecord CollectionsFetched [data]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [{:keys [version value]} data]
|
||||
(defn fetch-color-libraries
|
||||
[team-id]
|
||||
(s/assert ::us/uuid team-id)
|
||||
(ptk/reify ::fetch-color-libraries
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rp/query! :color-libraries {:team-id team-id})
|
||||
(rx/map fetch-color-libraries-result)))))
|
||||
|
||||
(defn fetch-color-libraries-result [result]
|
||||
(ptk/reify ::fetch-color-libraries-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update :colors-collections merge value)
|
||||
(assoc ::version version)))))
|
||||
(assoc-in [:library :color-libraries] result)))))
|
||||
|
||||
(defn collections-fetched
|
||||
(declare fetch-color-library-result)
|
||||
|
||||
(defn fetch-color-library
|
||||
[library-id]
|
||||
(ptk/reify ::fetch-color-library
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:library :selected-items] nil)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rp/query! :colors {:library-id library-id})
|
||||
(rx/map fetch-color-library-result)))))
|
||||
|
||||
(defn fetch-color-library-result
|
||||
[data]
|
||||
{:pre [(map? data)]}
|
||||
(CollectionsFetched. data))
|
||||
|
||||
(defn collections-fetched?
|
||||
[v]
|
||||
(instance? CollectionsFetched v))
|
||||
|
||||
;; --- Fetch Collections
|
||||
|
||||
(defrecord FetchCollections []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/query! :user-attr {:key "color-collections"})
|
||||
(rx/map collections-fetched)
|
||||
(rx/catch (fn [{:keys [type] :as error}]
|
||||
(if (= type :not-found)
|
||||
(rx/empty)
|
||||
(rx/throw error)))))))
|
||||
|
||||
(defn fetch-collections
|
||||
[]
|
||||
(FetchCollections.))
|
||||
|
||||
;; --- Create Collection
|
||||
|
||||
(defrecord CreateCollection [id]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [item {:name (tr "ds.default-library-title" (gensym "c"))
|
||||
:id id
|
||||
:created-at (dt/now)
|
||||
:type :own
|
||||
:colors #{}}]
|
||||
(assoc-in state [:colors-collections id] item)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of (persist-collections)
|
||||
(rt/nav :dashboard/colors nil {:type :own :id id}))))
|
||||
|
||||
(defn create-collection
|
||||
[]
|
||||
(let [id (uuid/next)]
|
||||
(CreateCollection. id)))
|
||||
|
||||
;; --- Persist Collections
|
||||
|
||||
(defrecord PersistCollections []
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [builtin? #(= :builtin (:type %))
|
||||
xform (remove (comp builtin? second))
|
||||
version (or (get state ::version) -1)
|
||||
value (->> (get state :colors-collections)
|
||||
(into {} xform))
|
||||
data {:key "color-collections"
|
||||
:val value}]
|
||||
(->> (rp/mutation! :upsert-user-attr data)
|
||||
(rx/map collections-fetched)))))
|
||||
|
||||
(defn persist-collections
|
||||
[]
|
||||
(PersistCollections.))
|
||||
|
||||
;; --- Rename Collection
|
||||
|
||||
(defrecord RenameCollection [id name]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:colors-collections id :name] name))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(rx/of (persist-collections))))
|
||||
|
||||
(defn rename-collection
|
||||
[item name]
|
||||
(RenameCollection. item name))
|
||||
|
||||
;; --- Delete Collection
|
||||
|
||||
(defrecord DeleteCollection [id]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :colors-collections dissoc id))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(rx/of (persist-collections))))
|
||||
|
||||
(defn delete-collection
|
||||
[id]
|
||||
(DeleteCollection. id))
|
||||
|
||||
;; --- Replace Color
|
||||
|
||||
(defrecord AddColor [coll-id color]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:colors-collections coll-id :colors] set/union #{color}))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(rx/of (persist-collections))))
|
||||
|
||||
(defn add-color
|
||||
"Add or replace color in a collection."
|
||||
[coll-id color]
|
||||
(AddColor. coll-id color))
|
||||
|
||||
;; --- Remove Color
|
||||
|
||||
(defrecord RemoveColors [id colors]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:colors-collections id :colors]
|
||||
#(set/difference % colors)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(rx/of (persist-collections))))
|
||||
|
||||
(defn remove-colors
|
||||
"Remove color in a collection."
|
||||
[id colors]
|
||||
(RemoveColors. id colors))
|
||||
|
||||
;; --- Select color
|
||||
|
||||
(defrecord SelectColor [color]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:dashboard :colors :selected] conj color)))
|
||||
|
||||
(defrecord DeselectColor [color]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:dashboard :colors :selected] disj color)))
|
||||
|
||||
(defrecord ToggleColorSelection [color]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [selected (get-in state [:dashboard :colors :selected])]
|
||||
(rx/of
|
||||
(if (selected color)
|
||||
(DeselectColor. color)
|
||||
(SelectColor. color))))))
|
||||
|
||||
(defn toggle-color-selection
|
||||
[color]
|
||||
{:pre [(color/hex? color)]}
|
||||
(ToggleColorSelection. color))
|
||||
|
||||
;; --- Copy Selected Color
|
||||
|
||||
(defrecord CopySelected [id]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [selected (get-in state [:dashboard :colors :selected])]
|
||||
(update-in state [:colors-collections id :colors] set/union selected)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of (persist-collections))))
|
||||
|
||||
(defn copy-selected
|
||||
[id]
|
||||
{:pre [(or (uuid? id) (nil? id))]}
|
||||
(CopySelected. id))
|
||||
|
||||
;; --- Move Selected Color
|
||||
|
||||
(defrecord MoveSelected [from to]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [selected (get-in state [:dashboard :colors :selected])]
|
||||
(ptk/reify ::fetch-color-library
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update-in [:colors-collections from :colors] set/difference selected)
|
||||
(update-in [:colors-collections to :colors] set/union selected))))
|
||||
(assoc-in [:library :selected-items] data)))))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of (persist-collections))))
|
||||
(declare create-color-library-result)
|
||||
|
||||
(defn move-selected
|
||||
[from to]
|
||||
{:pre [(or (uuid? from) (nil? from))
|
||||
(or (uuid? to) (nil? to))]}
|
||||
(MoveSelected. from to))
|
||||
(defn create-color-library
|
||||
[team-id name]
|
||||
(ptk/reify ::create-color-library
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rp/mutation! :create-color-library {:team-id team-id
|
||||
:name name})
|
||||
(rx/map create-color-library-result)))))
|
||||
|
||||
;; --- Delete Colors
|
||||
(defn create-color-library-result [result]
|
||||
(ptk/reify ::create-color-library-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update-in [:library :color-libraries] #(into [result] %))))))
|
||||
|
||||
(defrecord DeleteColors [coll-id colors]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:dashboard :colors :selected] #{}))
|
||||
(declare create-color-result)
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of (remove-colors coll-id colors))))
|
||||
(defn create-color
|
||||
[library-id color]
|
||||
(s/assert (s/nilable uuid?) library-id)
|
||||
(ptk/reify ::create-color
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
|
||||
(defn delete-colors
|
||||
[coll-id colors]
|
||||
(DeleteColors. coll-id colors))
|
||||
(->> (rp/mutation! :create-color {:library-id library-id
|
||||
:content color
|
||||
:name color})
|
||||
(rx/map create-color-result)))))
|
||||
|
||||
(defn create-color-result
|
||||
[item]
|
||||
(ptk/reify ::create-color-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update-in [:library :selected-items] #(into [item] %) )))))
|
||||
|
||||
@ -35,121 +35,169 @@
|
||||
::user-id]))
|
||||
|
||||
|
||||
(declare fetch-icons)
|
||||
|
||||
(defn initialize
|
||||
[collection-id]
|
||||
(s/assert ::us/uuid collection-id)
|
||||
(ptk/reify ::initialize
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:dashboard-icons :selected] #{}))
|
||||
(declare fetch-icon-libraries-result)
|
||||
|
||||
(defn fetch-icon-libraries
|
||||
[team-id]
|
||||
(s/assert ::us/uuid team-id)
|
||||
(ptk/reify ::fetch-icon-libraries
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of (fetch-icons collection-id)))))
|
||||
(->> (rp/query! :icon-libraries {:team-id team-id})
|
||||
(rx/map fetch-icon-libraries-result)))))
|
||||
|
||||
(defn fetch-icon-libraries-result [result]
|
||||
(ptk/reify ::fetch-icon-libraries-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:library :icon-libraries] result)))))
|
||||
|
||||
(declare fetch-icon-library-result)
|
||||
|
||||
(defn fetch-icon-library
|
||||
[library-id]
|
||||
(ptk/reify ::fetch-icon-library
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:library :selected-items] nil)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rp/query! :icons {:library-id library-id})
|
||||
(rx/map fetch-icon-library-result)))))
|
||||
|
||||
(defn fetch-icon-library-result
|
||||
[data]
|
||||
(ptk/reify ::fetch-icon-library
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:library :selected-items] data)))))
|
||||
|
||||
(declare create-icon-library-result)
|
||||
|
||||
(defn create-icon-library
|
||||
[team-id name]
|
||||
(ptk/reify ::create-icon-library
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rp/mutation! :create-icon-library {:team-id team-id
|
||||
:name name})
|
||||
(rx/map create-icon-library-result)))))
|
||||
|
||||
(defn create-icon-library-result [result]
|
||||
(ptk/reify ::create-icon-library-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update-in [:library :icon-libraries] #(into [result] %))))))
|
||||
|
||||
|
||||
|
||||
;; (declare fetch-icons)
|
||||
;;
|
||||
;; (defn initialize
|
||||
;; [collection-id]
|
||||
;; (s/assert ::us/uuid collection-id)
|
||||
;; (ptk/reify ::initialize
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:dashboard-icons :selected] #{}))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (rx/of (fetch-icons collection-id)))))
|
||||
;;
|
||||
;; --- Fetch Collections
|
||||
|
||||
(declare collections-fetched)
|
||||
|
||||
(def fetch-collections
|
||||
(ptk/reify ::fetch-collections
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/query! :icons-collections)
|
||||
(rx/map collections-fetched)))))
|
||||
|
||||
;; --- Collections Fetched
|
||||
|
||||
(defn collections-fetched
|
||||
[items]
|
||||
(s/assert (s/every ::collection) items)
|
||||
(ptk/reify ::collections-fetched
|
||||
cljs.core/IDeref
|
||||
(-deref [_] items)
|
||||
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(reduce (fn [state {:keys [id user] :as item}]
|
||||
(let [type (if (uuid/zero? (:user-id item)) :builtin :own)
|
||||
item (assoc item :type type)]
|
||||
(assoc-in state [:icons-collections id] item)))
|
||||
state
|
||||
items))))
|
||||
;; (declare collections-fetched)
|
||||
;;
|
||||
;; (def fetch-collections
|
||||
;; (ptk/reify ::fetch-collections
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (->> (rp/query! :icons-collections)
|
||||
;; (rx/map collections-fetched)))))
|
||||
;;
|
||||
;; ;; --- Collections Fetched
|
||||
;;
|
||||
;; (defn collections-fetched
|
||||
;; [items]
|
||||
;; (s/assert (s/every ::collection) items)
|
||||
;; (ptk/reify ::collections-fetched
|
||||
;; cljs.core/IDeref
|
||||
;; (-deref [_] items)
|
||||
;;
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (reduce (fn [state {:keys [id user] :as item}]
|
||||
;; (let [type (if (uuid/zero? (:user-id item)) :builtin :own)
|
||||
;; item (assoc item :type type)]
|
||||
;; (assoc-in state [:icons-collections id] item)))
|
||||
;; state
|
||||
;; items))))
|
||||
|
||||
|
||||
;; --- Create Collection
|
||||
|
||||
(declare collection-created)
|
||||
|
||||
(def create-collection
|
||||
(ptk/reify ::create-collection
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [name (tr "ds.default-library-title" (gensym "c"))
|
||||
data {:name name}]
|
||||
(->> (rp/mutation! :create-icons-collection data)
|
||||
(rx/map collection-created))))))
|
||||
|
||||
|
||||
;; --- Collection Created
|
||||
|
||||
(defn collection-created
|
||||
[item]
|
||||
(s/assert ::collection item)
|
||||
(ptk/reify ::collection-created
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [{:keys [id] :as item} (assoc item :type :own)]
|
||||
(update state :icons-collections assoc id item)))))
|
||||
|
||||
;; --- Rename Collection
|
||||
|
||||
(defn rename-collection
|
||||
[id name]
|
||||
(ptk/reify ::rename-collection
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:icons-collections id :name] name))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [params {:id id :name name}]
|
||||
(->> (rp/mutation! :rename-icons-collection params)
|
||||
(rx/ignore))))))
|
||||
|
||||
;; --- Delete Collection
|
||||
|
||||
(defn delete-collection
|
||||
[id on-success]
|
||||
(ptk/reify ::delete-collection
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :icons-collections dissoc id))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/mutation! :delete-icons-collection {:id id})
|
||||
(rx/tap on-success)
|
||||
(rx/ignore)))))
|
||||
|
||||
;; ;; --- Create Collection
|
||||
;;
|
||||
;; (declare collection-created)
|
||||
;;
|
||||
;; (def create-collection
|
||||
;; (ptk/reify ::create-collection
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (let [name (tr "ds.default-library-title" (gensym "c"))
|
||||
;; data {:name name}]
|
||||
;; (->> (rp/mutation! :create-icons-collection data)
|
||||
;; (rx/map collection-created))))))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Collection Created
|
||||
;;
|
||||
;; (defn collection-created
|
||||
;; [item]
|
||||
;; (s/assert ::collection item)
|
||||
;; (ptk/reify ::collection-created
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [{:keys [id] :as item} (assoc item :type :own)]
|
||||
;; (update state :icons-collections assoc id item)))))
|
||||
;;
|
||||
;; ;; --- Rename Collection
|
||||
;;
|
||||
;; (defn rename-collection
|
||||
;; [id name]
|
||||
;; (ptk/reify ::rename-collection
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:icons-collections id :name] name))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (let [params {:id id :name name}]
|
||||
;; (->> (rp/mutation! :rename-icons-collection params)
|
||||
;; (rx/ignore))))))
|
||||
;;
|
||||
;; ;; --- Delete Collection
|
||||
;;
|
||||
;; (defn delete-collection
|
||||
;; [id on-success]
|
||||
;; (ptk/reify ::delete-collection
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update state :icons-collections dissoc id))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (->> (rp/mutation! :delete-icons-collection {:id id})
|
||||
;; (rx/tap on-success)
|
||||
;; (rx/ignore)))))
|
||||
;;
|
||||
;; --- Icon Created
|
||||
|
||||
(defrecord IconCreated [item]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [{:keys [id] :as item} (assoc item :type :icon)]
|
||||
(update state :icons assoc id item))))
|
||||
|
||||
(defn icon-created
|
||||
[item]
|
||||
(IconCreated. item))
|
||||
|
||||
;; --- Create Icon
|
||||
|
||||
(declare icon-created)
|
||||
|
||||
(defn- parse-svg
|
||||
[data]
|
||||
(s/assert ::us/string data)
|
||||
@ -180,9 +228,11 @@
|
||||
[(dom/get-outer-html g) props])))))
|
||||
|
||||
|
||||
(declare create-icon-result)
|
||||
|
||||
(defn create-icons
|
||||
[id files]
|
||||
(s/assert (s/nilable uuid?) id)
|
||||
[library-id files]
|
||||
(s/assert (s/nilable uuid?) library-id)
|
||||
(ptk/reify ::create-icons
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
@ -192,7 +242,7 @@
|
||||
(allowed? [file]
|
||||
(= (.-type file) "image/svg+xml"))
|
||||
(prepare [[content metadata]]
|
||||
{:collection-id id
|
||||
{:library-id library-id
|
||||
:content content
|
||||
:id (uuid/next)
|
||||
;; TODO Keep the name of the original icon
|
||||
@ -203,130 +253,139 @@
|
||||
(rx/merge-map parse)
|
||||
(rx/map prepare)
|
||||
(rx/flat-map #(rp/mutation! :create-icon %))
|
||||
(rx/map icon-created))))))
|
||||
(rx/map create-icon-result))))))
|
||||
|
||||
;; --- Icon Persisted
|
||||
|
||||
(defrecord IconPersisted [id data]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:icons id] data)))
|
||||
|
||||
(defn icon-persisted
|
||||
[{:keys [id] :as data}]
|
||||
{:pre [(map? data)]}
|
||||
(IconPersisted. id data))
|
||||
|
||||
;; --- Persist Icon
|
||||
|
||||
(defn persist-icon
|
||||
[id]
|
||||
(s/assert ::us/uuid id)
|
||||
(ptk/reify ::persist-icon
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [data (get-in state [:icons id])]
|
||||
(->> (rp/mutation! :update-icon data)
|
||||
(rx/ignore))))))
|
||||
(defn create-icon-result
|
||||
[item]
|
||||
(ptk/reify ::create-icon-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [{:keys [id] :as item} (assoc item :type :icon)]
|
||||
(-> state
|
||||
(update-in [:library :selected-items] #(into [item] %)))))))
|
||||
|
||||
;; ;; --- Icon Persisted
|
||||
;;
|
||||
;; (defrecord IconPersisted [id data]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:icons id] data)))
|
||||
;;
|
||||
;; (defn icon-persisted
|
||||
;; [{:keys [id] :as data}]
|
||||
;; {:pre [(map? data)]}
|
||||
;; (IconPersisted. id data))
|
||||
;;
|
||||
;; ;; --- Persist Icon
|
||||
;;
|
||||
;; (defn persist-icon
|
||||
;; [id]
|
||||
;; (s/assert ::us/uuid id)
|
||||
;; (ptk/reify ::persist-icon
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [data (get-in state [:icons id])]
|
||||
;; (->> (rp/mutation! :update-icon data)
|
||||
;; (rx/ignore))))))
|
||||
;;
|
||||
;; --- Load Icons
|
||||
|
||||
(declare icons-fetched)
|
||||
;; (declare icons-fetched)
|
||||
;;
|
||||
;; (defn fetch-icons
|
||||
;; [id]
|
||||
;; (ptk/reify ::fetch-icons
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (let [params (cond-> {} id (assoc :collection-id id))]
|
||||
;; (->> (rp/query! :icons-by-collection params)
|
||||
;; (rx/map icons-fetched))))))
|
||||
;;
|
||||
;; ;; --- Icons Fetched
|
||||
;;
|
||||
;; (defn icons-fetched
|
||||
;; [items]
|
||||
;; ;; TODO: specs
|
||||
;; (ptk/reify ::icons-fetched
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [icons (d/index-by :id items)]
|
||||
;; (assoc state :icons icons)))))
|
||||
|
||||
(defn fetch-icons
|
||||
[id]
|
||||
(ptk/reify ::fetch-icons
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [params (cond-> {} id (assoc :collection-id id))]
|
||||
(->> (rp/query! :icons-by-collection params)
|
||||
(rx/map icons-fetched))))))
|
||||
|
||||
;; --- Icons Fetched
|
||||
|
||||
(defn icons-fetched
|
||||
[items]
|
||||
;; TODO: specs
|
||||
(ptk/reify ::icons-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [icons (d/index-by :id items)]
|
||||
(assoc state :icons icons)))))
|
||||
|
||||
;; --- Rename Icon
|
||||
|
||||
(defn rename-icon
|
||||
[id name]
|
||||
(s/assert ::us/uuid id)
|
||||
(s/assert ::us/string name)
|
||||
(ptk/reify ::rename-icon
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:icons id :name] name))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of (persist-icon id)))))
|
||||
|
||||
;; --- Icon Selection
|
||||
|
||||
(defn select-icon
|
||||
[id]
|
||||
(ptk/reify ::select-icon
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:dashboard-icons :selected] (fnil conj #{}) id))))
|
||||
|
||||
(defn deselect-icon
|
||||
[id]
|
||||
(ptk/reify ::deselect-icon
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:dashboard-icons :selected] (fnil disj #{}) id))))
|
||||
|
||||
(def deselect-all-icons
|
||||
(ptk/reify ::deselect-all-icons
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:dashboard-icons :selected] #{}))))
|
||||
|
||||
;; --- Delete Icons
|
||||
|
||||
(defn delete-icon
|
||||
[id]
|
||||
(ptk/reify ::delete-icon
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :icons dissoc id))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(rx/merge
|
||||
(rx/of deselect-all-icons)
|
||||
(->> (rp/mutation! :delete-icon {:id id})
|
||||
(rx/ignore))))))
|
||||
|
||||
;; --- Delete Selected
|
||||
|
||||
(def delete-selected
|
||||
(ptk/reify ::delete-selected
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [selected (get-in state [:dashboard-icons :selected])]
|
||||
(->> (rx/from selected)
|
||||
(rx/map delete-icon))))))
|
||||
;; --- Update Opts (Filtering & Ordering)
|
||||
|
||||
(defn update-opts
|
||||
[& {:keys [order filter edition]
|
||||
:or {edition false}}]
|
||||
(ptk/reify ::update-opts
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :dashboard-icons merge
|
||||
{:edition edition}
|
||||
(when order {:order order})
|
||||
(when filter {:filter filter})))))
|
||||
;; ;; --- Rename Icon
|
||||
;;
|
||||
;; (defn rename-icon
|
||||
;; [id name]
|
||||
;; (s/assert ::us/uuid id)
|
||||
;; (s/assert ::us/string name)
|
||||
;; (ptk/reify ::rename-icon
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:icons id :name] name))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (rx/of (persist-icon id)))))
|
||||
;;
|
||||
;; ;; --- Icon Selection
|
||||
;;
|
||||
;; (defn select-icon
|
||||
;; [id]
|
||||
;; (ptk/reify ::select-icon
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update-in state [:dashboard-icons :selected] (fnil conj #{}) id))))
|
||||
;;
|
||||
;; (defn deselect-icon
|
||||
;; [id]
|
||||
;; (ptk/reify ::deselect-icon
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update-in state [:dashboard-icons :selected] (fnil disj #{}) id))))
|
||||
;;
|
||||
;; (def deselect-all-icons
|
||||
;; (ptk/reify ::deselect-all-icons
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:dashboard-icons :selected] #{}))))
|
||||
;;
|
||||
;; ;; --- Delete Icons
|
||||
;;
|
||||
;; (defn delete-icon
|
||||
;; [id]
|
||||
;; (ptk/reify ::delete-icon
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update state :icons dissoc id))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (rx/merge
|
||||
;; (rx/of deselect-all-icons)
|
||||
;; (->> (rp/mutation! :delete-icon {:id id})
|
||||
;; (rx/ignore))))))
|
||||
;;
|
||||
;; ;; --- Delete Selected
|
||||
;;
|
||||
;; (def delete-selected
|
||||
;; (ptk/reify ::delete-selected
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [selected (get-in state [:dashboard-icons :selected])]
|
||||
;; (->> (rx/from selected)
|
||||
;; (rx/map delete-icon))))))
|
||||
;; ;; --- Update Opts (Filtering & Ordering)
|
||||
;;
|
||||
;; (defn update-opts
|
||||
;; [& {:keys [order filter edition]
|
||||
;; :or {edition false}}]
|
||||
;; (ptk/reify ::update-opts
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update state :dashboard-icons merge
|
||||
;; {:edition edition}
|
||||
;; (when order {:order order})
|
||||
;; (when filter {:filter filter})))))
|
||||
|
||||
;; --- Copy Selected Icon
|
||||
|
||||
|
||||
@ -55,305 +55,254 @@
|
||||
::thumb-uri
|
||||
::user-id]))
|
||||
|
||||
;; --- Initialize Collection Page
|
||||
|
||||
(declare fetch-images)
|
||||
|
||||
(defn initialize
|
||||
[collection-id]
|
||||
(us/verify ::us/uuid collection-id)
|
||||
(ptk/reify ::initialize
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:dashboard-images :selected] #{}))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of (fetch-images collection-id)))))
|
||||
|
||||
;; --- Fetch Collections
|
||||
|
||||
(declare collections-fetched)
|
||||
|
||||
(def fetch-collections
|
||||
(ptk/reify ::fetch-collections
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/query! :image-collections)
|
||||
(rx/map collections-fetched)))))
|
||||
|
||||
|
||||
;; --- Collections Fetched
|
||||
|
||||
(defn collections-fetched
|
||||
[items]
|
||||
(us/verify (s/every ::collection) items)
|
||||
(ptk/reify ::collections-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(reduce (fn [state {:keys [id user] :as item}]
|
||||
(let [type (if (uuid/zero? (:user-id item)) :builtin :own)
|
||||
item (assoc item :type type)]
|
||||
(assoc-in state [:images-collections id] item)))
|
||||
state
|
||||
items))))
|
||||
|
||||
|
||||
;; --- Create Collection
|
||||
|
||||
(declare collection-created)
|
||||
|
||||
(def create-collection
|
||||
(ptk/reify ::create-collection
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [data {:name (tr "ds.default-library-title" (gensym "c"))}]
|
||||
(->> (rp/mutation! :create-image-collection data)
|
||||
(rx/map collection-created))))))
|
||||
|
||||
;; --- Collection Created
|
||||
|
||||
(defn collection-created
|
||||
[item]
|
||||
(us/verify ::collection item)
|
||||
(ptk/reify ::collection-created
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [{:keys [id] :as item} (assoc item :type :own)]
|
||||
(update state :images-collections assoc id item)))))
|
||||
|
||||
;; --- Rename Collection
|
||||
|
||||
(defn rename-collection
|
||||
[id name]
|
||||
(ptk/reify ::rename-collection
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:images-collections id :name] name))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [params {:id id :name name}]
|
||||
(->> (rp/mutation! :rename-image-collection params)
|
||||
(rx/ignore))))))
|
||||
|
||||
;; --- Delete Collection
|
||||
|
||||
(defn delete-collection
|
||||
[id on-success]
|
||||
(ptk/reify ::delete-collection
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :images-collections dissoc id))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(->> (rp/mutation! :delete-image-collection {:id id})
|
||||
(rx/tap on-success)
|
||||
(rx/ignore)))))
|
||||
|
||||
;; --- Create Image
|
||||
|
||||
(declare image-created)
|
||||
(def allowed-file-types #{"image/jpeg" "image/png"})
|
||||
|
||||
(defn create-images
|
||||
([id files] (create-images id files identity))
|
||||
([id files on-uploaded]
|
||||
(us/verify (s/nilable ::us/uuid) id)
|
||||
(us/verify fn? on-uploaded)
|
||||
(ptk/reify ::create-images
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:dashboard-images :uploading] true))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(letfn [(allowed-file? [file]
|
||||
(contains? allowed-file-types (.-type file)))
|
||||
(finalize-upload [state]
|
||||
(assoc-in state [:dashboard-images :uploading] false))
|
||||
(on-success [_]
|
||||
(st/emit! finalize-upload)
|
||||
(on-uploaded))
|
||||
(on-error [e]
|
||||
(st/emit! finalize-upload)
|
||||
(rx/throw e))
|
||||
(prepare [file]
|
||||
{:name (.-name file)
|
||||
:collection-id id
|
||||
:content file})]
|
||||
(->> (rx/from files)
|
||||
(rx/filter allowed-file?)
|
||||
(rx/map prepare)
|
||||
(rx/mapcat #(rp/mutation! :upload-image %))
|
||||
(rx/reduce conj [])
|
||||
(rx/do on-success)
|
||||
(rx/mapcat identity)
|
||||
(rx/map image-created)
|
||||
(rx/catch on-error)))))))
|
||||
|
||||
;; --- Image Created
|
||||
|
||||
(defn image-created
|
||||
[item]
|
||||
(us/verify ::image item)
|
||||
(ptk/reify ::image-created
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :images assoc (:id item) item))))
|
||||
|
||||
;; --- Update Image
|
||||
|
||||
(defn persist-image
|
||||
[id]
|
||||
(us/verify ::us/uuid id)
|
||||
(ptk/reify ::persist-image
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [data (get-in state [:images id])]
|
||||
(->> (rp/mutation! :update-image data)
|
||||
(rx/ignore))))))
|
||||
|
||||
;; --- Fetch Images
|
||||
|
||||
(declare images-fetched)
|
||||
|
||||
(defn fetch-images
|
||||
"Fetch a list of images of the selected collection"
|
||||
[id]
|
||||
(us/verify ::us/uuid id)
|
||||
(ptk/reify ::fetch-images
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(let [params {:collection-id id}]
|
||||
(->> (rp/query! :images-by-collection params)
|
||||
(rx/map (partial images-fetched id)))))))
|
||||
|
||||
;; --- Images Fetched
|
||||
|
||||
(s/def ::images (s/every ::image))
|
||||
|
||||
(defn images-fetched
|
||||
[collection-id items]
|
||||
(us/verify ::us/uuid collection-id)
|
||||
(us/verify ::images items)
|
||||
(ptk/reify ::images-fetched
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [images (d/index-by :id items)]
|
||||
(assoc state :images images)))))
|
||||
|
||||
;; --- Fetch Image
|
||||
|
||||
(declare image-fetched)
|
||||
|
||||
(defrecord FetchImage [id]
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [existing (get-in state [:images id])]
|
||||
(if existing
|
||||
(rx/empty)
|
||||
(->> (rp/query! :image-by-id {:id id})
|
||||
(rx/map image-fetched)
|
||||
(rx/catch rp/client-error? #(rx/empty)))))))
|
||||
|
||||
(defn fetch-image
|
||||
"Conditionally fetch image by its id. If image
|
||||
is already loaded, this event is noop."
|
||||
[id]
|
||||
{:pre [(uuid? id)]}
|
||||
(FetchImage. id))
|
||||
|
||||
;; --- Image Fetched
|
||||
|
||||
(defrecord ImageFetched [image]
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [id (:id image)]
|
||||
(update state :images assoc id image))))
|
||||
|
||||
(defn image-fetched
|
||||
[image]
|
||||
{:pre [(map? image)]}
|
||||
(ImageFetched. image))
|
||||
|
||||
;; --- Rename Image
|
||||
|
||||
(defn rename-image
|
||||
[id name]
|
||||
(us/verify ::us/uuid id)
|
||||
(us/verify ::us/string name)
|
||||
(ptk/reify ::rename-image
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:images id :name] name))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of (persist-image id)))))
|
||||
|
||||
;; --- Image Selection
|
||||
|
||||
(defn select-image
|
||||
[id]
|
||||
(ptk/reify ::select-image
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:dashboard-images :selected] (fnil conj #{}) id))))
|
||||
|
||||
(defn deselect-image
|
||||
[id]
|
||||
(ptk/reify ::deselect-image
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update-in state [:dashboard-images :selected] (fnil disj #{}) id))))
|
||||
|
||||
(def deselect-all-images
|
||||
(ptk/reify ::deselect-all-images
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(assoc-in state [:dashboard-images :selected] #{}))))
|
||||
|
||||
;; --- Delete Images
|
||||
|
||||
(defn delete-image
|
||||
[id]
|
||||
(us/verify ::us/uuid id)
|
||||
(ptk/reify ::delete-image
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :images dissoc id))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state s]
|
||||
(rx/merge
|
||||
(rx/of deselect-all-images)
|
||||
(->> (rp/mutation! :delete-image {:id id})
|
||||
(rx/ignore))))))
|
||||
|
||||
;; --- Delete Selected
|
||||
|
||||
(def delete-selected
|
||||
(ptk/reify ::delete-selected
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [selected (get-in state [:dashboard-images :selected])]
|
||||
(->> (rx/from selected)
|
||||
(rx/map delete-image))))))
|
||||
|
||||
;; --- Update Opts (Filtering & Ordering)
|
||||
|
||||
(defn update-opts
|
||||
[& {:keys [order filter edition]
|
||||
:or {edition false}}]
|
||||
(ptk/reify ::update-opts
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(update state :dashboard-images merge
|
||||
{:edition edition}
|
||||
(when order {:order order})
|
||||
(when filter {:filter filter})))))
|
||||
;; ;; --- Initialize Collection Page
|
||||
;;
|
||||
;; (declare fetch-images)
|
||||
;;
|
||||
;; (defn initialize
|
||||
;; [collection-id]
|
||||
;; (us/verify ::us/uuid collection-id)
|
||||
;; (ptk/reify ::initialize
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:dashboard-images :selected] #{}))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (rx/of (fetch-images collection-id)))))
|
||||
;;
|
||||
;; ;; --- Fetch Collections
|
||||
;;
|
||||
;; (declare collections-fetched)
|
||||
;;
|
||||
;; (def fetch-collections
|
||||
;; (ptk/reify ::fetch-collections
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (->> (rp/query! :image-collections)
|
||||
;; (rx/map collections-fetched)))))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Collections Fetched
|
||||
;;
|
||||
;; (defn collections-fetched
|
||||
;; [items]
|
||||
;; (us/verify (s/every ::collection) items)
|
||||
;; (ptk/reify ::collections-fetched
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (reduce (fn [state {:keys [id user] :as item}]
|
||||
;; (let [type (if (uuid/zero? (:user-id item)) :builtin :own)
|
||||
;; item (assoc item :type type)]
|
||||
;; (assoc-in state [:images-collections id] item)))
|
||||
;; state
|
||||
;; items))))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Create Collection
|
||||
;;
|
||||
;; (declare collection-created)
|
||||
;;
|
||||
;; (def create-collection
|
||||
;; (ptk/reify ::create-collection
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (let [data {:name (tr "ds.default-library-title" (gensym "c"))}]
|
||||
;; (->> (rp/mutation! :create-image-collection data)
|
||||
;; (rx/map collection-created))))))
|
||||
;;
|
||||
;; ;; --- Collection Created
|
||||
;;
|
||||
;; (defn collection-created
|
||||
;; [item]
|
||||
;; (us/verify ::collection item)
|
||||
;; (ptk/reify ::collection-created
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [{:keys [id] :as item} (assoc item :type :own)]
|
||||
;; (update state :images-collections assoc id item)))))
|
||||
;;
|
||||
;; ;; --- Rename Collection
|
||||
;;
|
||||
;; (defn rename-collection
|
||||
;; [id name]
|
||||
;; (ptk/reify ::rename-collection
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:images-collections id :name] name))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (let [params {:id id :name name}]
|
||||
;; (->> (rp/mutation! :rename-image-collection params)
|
||||
;; (rx/ignore))))))
|
||||
;;
|
||||
;; ;; --- Delete Collection
|
||||
;;
|
||||
;; (defn delete-collection
|
||||
;; [id on-success]
|
||||
;; (ptk/reify ::delete-collection
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update state :images-collections dissoc id))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (->> (rp/mutation! :delete-image-collection {:id id})
|
||||
;; (rx/tap on-success)
|
||||
;; (rx/ignore)))))
|
||||
;;
|
||||
;; ;; --- Update Image
|
||||
;;
|
||||
;; (defn persist-image
|
||||
;; [id]
|
||||
;; (us/verify ::us/uuid id)
|
||||
;; (ptk/reify ::persist-image
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [data (get-in state [:images id])]
|
||||
;; (->> (rp/mutation! :update-image data)
|
||||
;; (rx/ignore))))))
|
||||
;;
|
||||
;; ;; --- Fetch Images
|
||||
;;
|
||||
;; (declare images-fetched)
|
||||
;;
|
||||
;; (defn fetch-images
|
||||
;; "Fetch a list of images of the selected collection"
|
||||
;; [id]
|
||||
;; (us/verify ::us/uuid id)
|
||||
;; (ptk/reify ::fetch-images
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (let [params {:collection-id id}]
|
||||
;; (->> (rp/query! :images-by-collection params)
|
||||
;; (rx/map (partial images-fetched id)))))))
|
||||
;;
|
||||
;; ;; --- Images Fetched
|
||||
;;
|
||||
;; (s/def ::images (s/every ::image))
|
||||
;;
|
||||
;; (defn images-fetched
|
||||
;; [collection-id items]
|
||||
;; (us/verify ::us/uuid collection-id)
|
||||
;; (us/verify ::images items)
|
||||
;; (ptk/reify ::images-fetched
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [images (d/index-by :id items)]
|
||||
;; (assoc state :images images)))))
|
||||
;;
|
||||
;; ;; --- Fetch Image
|
||||
;;
|
||||
;; (declare image-fetched)
|
||||
;;
|
||||
;; (defrecord FetchImage [id]
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [existing (get-in state [:images id])]
|
||||
;; (if existing
|
||||
;; (rx/empty)
|
||||
;; (->> (rp/query! :image-by-id {:id id})
|
||||
;; (rx/map image-fetched)
|
||||
;; (rx/catch rp/client-error? #(rx/empty)))))))
|
||||
;;
|
||||
;; (defn fetch-image
|
||||
;; "Conditionally fetch image by its id. If image
|
||||
;; is already loaded, this event is noop."
|
||||
;; [id]
|
||||
;; {:pre [(uuid? id)]}
|
||||
;; (FetchImage. id))
|
||||
;;
|
||||
;; ;; --- Image Fetched
|
||||
;;
|
||||
;; (defrecord ImageFetched [image]
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (let [id (:id image)]
|
||||
;; (update state :images assoc id image))))
|
||||
;;
|
||||
;; (defn image-fetched
|
||||
;; [image]
|
||||
;; {:pre [(map? image)]}
|
||||
;; (ImageFetched. image))
|
||||
;;
|
||||
;; ;; --- Rename Image
|
||||
;;
|
||||
;; (defn rename-image
|
||||
;; [id name]
|
||||
;; (us/verify ::us/uuid id)
|
||||
;; (us/verify ::us/string name)
|
||||
;; (ptk/reify ::rename-image
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:images id :name] name))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (rx/of (persist-image id)))))
|
||||
;;
|
||||
;; ;; --- Image Selection
|
||||
;;
|
||||
;; (defn select-image
|
||||
;; [id]
|
||||
;; (ptk/reify ::select-image
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update-in state [:dashboard-images :selected] (fnil conj #{}) id))))
|
||||
;;
|
||||
;; (defn deselect-image
|
||||
;; [id]
|
||||
;; (ptk/reify ::deselect-image
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update-in state [:dashboard-images :selected] (fnil disj #{}) id))))
|
||||
;;
|
||||
;; (def deselect-all-images
|
||||
;; (ptk/reify ::deselect-all-images
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (assoc-in state [:dashboard-images :selected] #{}))))
|
||||
;;
|
||||
;; ;; --- Delete Images
|
||||
;;
|
||||
;; (defn delete-image
|
||||
;; [id]
|
||||
;; (us/verify ::us/uuid id)
|
||||
;; (ptk/reify ::delete-image
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update state :images dissoc id))
|
||||
;;
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state s]
|
||||
;; (rx/merge
|
||||
;; (rx/of deselect-all-images)
|
||||
;; (->> (rp/mutation! :delete-image {:id id})
|
||||
;; (rx/ignore))))))
|
||||
;;
|
||||
;; ;; --- Delete Selected
|
||||
;;
|
||||
;; (def delete-selected
|
||||
;; (ptk/reify ::delete-selected
|
||||
;; ptk/WatchEvent
|
||||
;; (watch [_ state stream]
|
||||
;; (let [selected (get-in state [:dashboard-images :selected])]
|
||||
;; (->> (rx/from selected)
|
||||
;; (rx/map delete-image))))))
|
||||
;;
|
||||
;; ;; --- Update Opts (Filtering & Ordering)
|
||||
;;
|
||||
;; (defn update-opts
|
||||
;; [& {:keys [order filter edition]
|
||||
;; :or {edition false}}]
|
||||
;; (ptk/reify ::update-opts
|
||||
;; ptk/UpdateEvent
|
||||
;; (update [_ state]
|
||||
;; (update state :dashboard-images merge
|
||||
;; {:edition edition}
|
||||
;; (when order {:order order})
|
||||
;; (when filter {:filter filter})))))
|
||||
|
||||
;; --- Copy Selected Image
|
||||
|
||||
@ -398,3 +347,114 @@
|
||||
;; {:pre [(or (uuid? id) (nil? id))]}
|
||||
;; (MoveSelected. id))
|
||||
|
||||
|
||||
;;;;;;; NEW
|
||||
|
||||
(declare fetch-image-libraries-result)
|
||||
|
||||
(defn fetch-image-libraries
|
||||
[team-id]
|
||||
(s/assert ::us/uuid team-id)
|
||||
(ptk/reify ::fetch-image-libraries
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rp/query! :image-libraries {:team-id team-id})
|
||||
(rx/map fetch-image-libraries-result)))))
|
||||
|
||||
(defn fetch-image-libraries-result [result]
|
||||
(ptk/reify ::fetch-image-libraries-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:library :image-libraries] result)))))
|
||||
|
||||
(declare fetch-image-library-result)
|
||||
|
||||
(defn fetch-image-library
|
||||
[library-id]
|
||||
(ptk/reify ::fetch-image-library
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:library :selected-items] nil)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rp/query! :images {:library-id library-id})
|
||||
(rx/map fetch-image-library-result)))))
|
||||
|
||||
(defn fetch-image-library-result
|
||||
[data]
|
||||
(ptk/reify ::fetch-image-library
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:library :selected-items] data)))))
|
||||
|
||||
(declare create-image-library-result)
|
||||
|
||||
(defn create-image-library
|
||||
[team-id name]
|
||||
(ptk/reify ::create-image-library
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(->> (rp/mutation! :create-image-library {:team-id team-id
|
||||
:name name})
|
||||
(rx/map create-image-library-result)))))
|
||||
|
||||
(defn create-image-library-result [result]
|
||||
(ptk/reify ::create-image-library-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update-in [:library :image-libraries] #(into [result] %))))))
|
||||
|
||||
|
||||
|
||||
;; --- Create Image
|
||||
(declare create-images-result)
|
||||
(def allowed-file-types #{"image/jpeg" "image/png"})
|
||||
|
||||
(defn create-images
|
||||
([library-id files] (create-images library-id files identity))
|
||||
([library-id files on-uploaded]
|
||||
(us/verify (s/nilable ::us/uuid) library-id)
|
||||
(us/verify fn? on-uploaded)
|
||||
(ptk/reify ::create-images
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(letfn [(allowed-file? [file]
|
||||
(contains? allowed-file-types (.-type file)))
|
||||
#_(finalize-upload [state]
|
||||
(assoc-in state [:dashboard-images :uploading] false))
|
||||
(on-success [_]
|
||||
#_(st/emit! finalize-upload)
|
||||
(on-uploaded))
|
||||
(on-error [e]
|
||||
#_(st/emit! finalize-upload)
|
||||
(rx/throw e))
|
||||
(prepare [file]
|
||||
{:name (.-name file)
|
||||
:library-id library-id
|
||||
:content file})]
|
||||
(->> (rx/from files)
|
||||
(rx/filter allowed-file?)
|
||||
(rx/map prepare)
|
||||
(rx/mapcat #(rp/mutation! :upload-image %))
|
||||
(rx/reduce conj [])
|
||||
(rx/do on-success)
|
||||
(rx/mapcat identity)
|
||||
(rx/map create-images-result)
|
||||
(rx/catch on-error)))))))
|
||||
|
||||
;; --- Image Created
|
||||
|
||||
(defn create-images-result
|
||||
[item]
|
||||
#_(us/verify ::image item)
|
||||
(ptk/reify ::create-images-result
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(update-in [:library :selected-items] #(into [item] %))))))
|
||||
|
||||
|
||||
@ -56,7 +56,20 @@
|
||||
["/" :dashboard-team]
|
||||
["/search" :dashboard-search]
|
||||
["/project/:project-id" :dashboard-project]
|
||||
["/library" :dashboard-library]]]
|
||||
["/library"
|
||||
["/icons"
|
||||
["" { :name :dashboard-library-icons-index :section :icons}]
|
||||
["/:library-id" { :name :dashboard-library-icons :section :icons}]]
|
||||
|
||||
["/images"
|
||||
["" { :name :dashboard-library-images-index :section :images}]
|
||||
["/:library-id" { :name :dashboard-library-images :section :images}]]
|
||||
|
||||
["/palettes"
|
||||
["" { :name :dashboard-library-palettes-index :section :palettes}]
|
||||
["/:library-id" { :name :dashboard-library-palettes :section :palettes }]]
|
||||
|
||||
]]]
|
||||
|
||||
["/workspace/:file-id" :workspace]])
|
||||
|
||||
@ -90,7 +103,13 @@
|
||||
|
||||
(:dashboard-search
|
||||
:dashboard-team
|
||||
:dashboard-project)
|
||||
:dashboard-project
|
||||
:dashboard-library-icons
|
||||
:dashboard-library-icons-index
|
||||
:dashboard-library-images
|
||||
:dashboard-library-images-index
|
||||
:dashboard-library-palettes
|
||||
:dashboard-library-palettes-index)
|
||||
(mf/element dashboard #js {:route route})
|
||||
|
||||
:workspace
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
|
||||
(ns uxbox.main.ui.colorpicker
|
||||
(:require
|
||||
[lentes.core :as l]
|
||||
[uxbox.main.store :as st]
|
||||
[goog.object :as gobj]
|
||||
[rumext.alpha :as mf]
|
||||
[vendor.react-color]))
|
||||
@ -16,5 +18,21 @@
|
||||
[:> js/SketchPicker {:color value
|
||||
:disableAlpha true
|
||||
:presetColors colors
|
||||
:onChangeComplete on-change-complete}]))
|
||||
:onChangeComplete on-change-complete
|
||||
:style {:box-shadow "none"}}]))
|
||||
|
||||
(defn- lookup-colors
|
||||
[state]
|
||||
(as-> {} $
|
||||
(reduce (fn [acc shape]
|
||||
(-> acc
|
||||
(update (:fill-color shape) (fnil inc 0))
|
||||
(update (:stroke-color shape) (fnil inc 0))))
|
||||
$ (vals (:shapes state)))
|
||||
(reverse (sort-by second $))
|
||||
(map first $)
|
||||
(remove nil? $)))
|
||||
|
||||
(def most-used-colors
|
||||
(-> (l/lens lookup-colors)
|
||||
(l/derive st/state)))
|
||||
|
||||
@ -16,11 +16,11 @@
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.ui.dashboard.header :refer [header]]
|
||||
[uxbox.main.ui.dashboard.sidebar :refer [sidebar]]
|
||||
[uxbox.main.ui.dashboard.search :refer [search-page]]
|
||||
[uxbox.main.ui.dashboard.project :refer [project-page]]
|
||||
[uxbox.main.ui.dashboard.recent-files :refer [recent-files-page]]
|
||||
[uxbox.main.ui.dashboard.library :refer [library-page]]
|
||||
[uxbox.main.ui.dashboard.profile :refer [profile-section]]
|
||||
[uxbox.main.ui.messages :refer [messages-widget]]))
|
||||
|
||||
@ -32,8 +32,10 @@
|
||||
(defn- parse-params
|
||||
[route profile]
|
||||
(let [search-term (get-in route [:params :query :search-term])
|
||||
route-name (get-in route [:data :name])
|
||||
team-id (get-in route [:params :path :team-id])
|
||||
project-id (get-in route [:params :path :project-id])]
|
||||
project-id (get-in route [:params :path :project-id])
|
||||
library-id (get-in route [:params :path :library-id])]
|
||||
(cond->
|
||||
{:search-term search-term}
|
||||
|
||||
@ -48,14 +50,21 @@
|
||||
|
||||
(and (= "drafts" project-id)
|
||||
(= "self" team-id))
|
||||
(assoc :project-id (:default-project-id profile)))))
|
||||
(assoc :project-id (:default-project-id profile))
|
||||
|
||||
(str/starts-with? (name route-name) "dashboard-library")
|
||||
(assoc :library-section (get-in route [:data :section]))
|
||||
|
||||
(uuid-str? library-id)
|
||||
(assoc :library-id (uuid library-id)))))
|
||||
|
||||
|
||||
(mf/defc dashboard
|
||||
[{:keys [route] :as props}]
|
||||
(let [profile (mf/deref refs/profile)
|
||||
section (get-in route [:data :name])
|
||||
{:keys [search-term team-id project-id]} (parse-params route profile)]
|
||||
page (get-in route [:data :name])
|
||||
{:keys [search-term team-id project-id library-id library-section] :as params}
|
||||
(parse-params route profile)]
|
||||
[:main.dashboard-main
|
||||
[:& messages-widget]
|
||||
[:section.dashboard-layout
|
||||
@ -63,17 +72,25 @@
|
||||
[:& profile-section {:profile profile}]
|
||||
[:& sidebar {:team-id team-id
|
||||
:project-id project-id
|
||||
:search-term search-term
|
||||
:section section}]
|
||||
:section page}]
|
||||
[:div.dashboard-content
|
||||
[:& header]
|
||||
(case section
|
||||
(case page
|
||||
:dashboard-search
|
||||
(mf/element search-page #js {:team-id team-id :search-term search-term})
|
||||
|
||||
:dashboard-team
|
||||
(mf/element recent-files-page #js {:team-id team-id})
|
||||
|
||||
(:dashboard-library-icons
|
||||
:dashboard-library-icons-index
|
||||
:dashboard-library-images
|
||||
:dashboard-library-images-index
|
||||
:dashboard-library-palettes
|
||||
:dashboard-library-palettes-index)
|
||||
(mf/element library-page #js {:team-id team-id
|
||||
:library-id library-id
|
||||
:section library-section})
|
||||
|
||||
:dashboard-project
|
||||
(mf/element project-page #js {:team-id team-id
|
||||
:project-id project-id}))]]])
|
||||
|
||||
@ -24,272 +24,272 @@
|
||||
[uxbox.util.i18n :as t :refer [tr]]
|
||||
[uxbox.util.router :as rt]))
|
||||
|
||||
;; --- Refs
|
||||
|
||||
(def collections-iref
|
||||
(-> (l/key :colors-collections)
|
||||
(l/derive st/state)))
|
||||
|
||||
(def selected-colors-iref
|
||||
(-> (l/in [:dashboard :colors :selected])
|
||||
(l/derive st/state)))
|
||||
|
||||
;; --- Colors Modal (Component)
|
||||
|
||||
(mf/defc color-modal
|
||||
[{:keys [on-submit value] :as props}]
|
||||
(let [local (mf/use-var value)]
|
||||
[:div.lightbox-body
|
||||
[:h3 (tr "ds.color-lightbox.title" )]
|
||||
[:form
|
||||
[:div.row-flex.center
|
||||
[:& colorpicker {:value (or @local "#00ccff")
|
||||
:on-change #(reset! local %)}]]
|
||||
[:input#project-btn.btn-primary
|
||||
{:value (tr "ds.color-lightbox.add")
|
||||
:on-click #(on-submit @local)
|
||||
:type "button"}]]]))
|
||||
|
||||
;; --- Page Title
|
||||
|
||||
|
||||
(mf/defc grid-header
|
||||
[{:keys [coll] :as props}]
|
||||
(letfn [(on-change [name]
|
||||
(st/emit! (dc/rename-collection (:id coll) name)))
|
||||
|
||||
(delete []
|
||||
(st/emit!
|
||||
(dc/delete-collection (:id coll))
|
||||
(rt/nav :dashboard-colors nil {:type (:type coll)})))
|
||||
|
||||
(on-delete []
|
||||
(modal/show! confirm-dialog {:on-accept delete}))]
|
||||
[:& common/grid-header {:value (:name coll)
|
||||
:on-change on-change
|
||||
:on-delete on-delete}]))
|
||||
|
||||
;; --- Nav
|
||||
|
||||
(mf/defc nav-item
|
||||
[{:keys [coll selected?] :as props}]
|
||||
(let [local (mf/use-state {})
|
||||
{:keys [id type name]} coll
|
||||
colors (count (:colors coll))
|
||||
editable? (= type :own)]
|
||||
(letfn [(on-click [event]
|
||||
(let [type (or type :own)]
|
||||
(st/emit! (rt/nav :dashboard-colors nil {:type type :id id}))))
|
||||
(on-input-change [event]
|
||||
(let [value (dom/get-target event)
|
||||
value (dom/get-value value)]
|
||||
(swap! local assoc :name value)))
|
||||
(on-cancel [event]
|
||||
(swap! local dissoc :name)
|
||||
(swap! local dissoc :edit))
|
||||
(on-double-click [event]
|
||||
(when editable?
|
||||
(swap! local assoc :edit true)))
|
||||
(on-input-keyup [event]
|
||||
(when (k/enter? event)
|
||||
(let [value (dom/get-target event)
|
||||
value (dom/get-value value)]
|
||||
(st/emit! (dc/rename-collection id (str/trim (:name @local))))
|
||||
(swap! local assoc :edit false))))]
|
||||
[:li {:on-click on-click
|
||||
:on-double-click on-double-click
|
||||
:class-name (when selected? "current")}
|
||||
(if (:edit @local)
|
||||
[:div
|
||||
[:input.element-title
|
||||
{:value (if (:name @local) (:name @local) name)
|
||||
:on-change on-input-change
|
||||
:on-key-down on-input-keyup}]
|
||||
[:span.close {:on-click on-cancel} i/close]]
|
||||
[:span.element-title name])
|
||||
#_[:span.element-subtitle
|
||||
(tr "ds.num-elements" (t/c colors))]])))
|
||||
|
||||
(mf/defc nav
|
||||
[{:keys [id type colls selected-coll] :as props}]
|
||||
(let [own? (= type :own)
|
||||
builtin? (= type :builtin)
|
||||
select-tab #(st/emit! (rt/nav :dashboard-colors nil {:type %}))]
|
||||
[:div.library-bar
|
||||
[:div.library-bar-inside
|
||||
[:ul.library-tabs
|
||||
[:li {:class-name (when own? "current")
|
||||
:on-click (partial select-tab :own)}
|
||||
(tr "ds.your-colors-title")]
|
||||
[:li {:class-name (when builtin? "current")
|
||||
:on-click (partial select-tab :builtin)}
|
||||
(tr "ds.store-colors-title")]]
|
||||
[:ul.library-elements
|
||||
(when own?
|
||||
[:li
|
||||
[:a.btn-primary {:on-click #(st/emit! (dc/create-collection))}
|
||||
(tr "ds.colors-collection.new")]])
|
||||
(for [item colls]
|
||||
(let [selected? (= (:id item) (:id selected-coll))]
|
||||
[:& nav-item {:coll item :selected? selected? :key (:id item)}]))]]]))
|
||||
|
||||
;; --- Grid
|
||||
|
||||
(mf/defc grid-form
|
||||
[{:keys [id] :as props}]
|
||||
(letfn [(on-submit [val]
|
||||
(st/emit! (dc/add-color id val))
|
||||
(modal/hide!))
|
||||
(on-click [event]
|
||||
(modal/show! color-modal {:on-submit on-submit}))]
|
||||
[:div.grid-item.small-item.add-project {:on-click on-click}
|
||||
[:span (tr "ds.color-new")]]))
|
||||
|
||||
(mf/defc grid-options-tooltip
|
||||
[{:keys [selected on-select title] :as props}]
|
||||
{:pre [(uuid? selected)
|
||||
(fn? on-select)
|
||||
(string? title)]}
|
||||
(let [colls (mf/deref collections-iref)
|
||||
colls (->> (vals colls)
|
||||
(filter #(= :own (:type %)))
|
||||
(remove #(= selected (:id %)))
|
||||
(sort-by :name colls))
|
||||
on-select (fn [event id]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(on-select id))]
|
||||
[:ul.move-list
|
||||
[:li.title title]
|
||||
(for [{:keys [id name] :as coll} colls]
|
||||
[:li {:key (str id)}
|
||||
[:a {:on-click #(on-select % id)} name]])]))
|
||||
|
||||
(mf/defc grid-options
|
||||
[{:keys [id type coll selected] :as props}]
|
||||
(let [local (mf/use-state {})]
|
||||
(letfn [(delete [event]
|
||||
(st/emit! (dc/delete-colors id selected)))
|
||||
(on-delete [event]
|
||||
(modal/show! confirm-dialog {:on-accept delete}))
|
||||
(on-toggle-copy [event]
|
||||
(swap! local update :show-copy-tooltip not)
|
||||
(swap! local assoc :show-move-tooltip false))
|
||||
(on-toggle-move [event]
|
||||
(swap! local update :show-move-tooltip not)
|
||||
(swap! local assoc :show-copy-tooltip false))
|
||||
(on-copy [selected]
|
||||
(swap! local assoc
|
||||
:show-move-tooltip false
|
||||
:show-copy-tooltip false)
|
||||
(st/emit! (dc/copy-selected selected)))
|
||||
(on-move [selected]
|
||||
(swap! local assoc
|
||||
:show-move-tooltip false
|
||||
:show-copy-tooltip false)
|
||||
(st/emit! (dc/move-selected id selected)))]
|
||||
|
||||
;; MULTISELECT OPTIONS BAR
|
||||
[:div.multiselect-bar
|
||||
(if (or (= type :own) (nil? id))
|
||||
;; if editable
|
||||
[:div.multiselect-nav
|
||||
[:span.move-item.tooltip.tooltip-top
|
||||
{:alt (tr "ds.multiselect-bar.copy")
|
||||
:on-click on-toggle-copy}
|
||||
(when (:show-copy-tooltip @local)
|
||||
[:& grid-options-tooltip {:selected id
|
||||
:title (tr "ds.multiselect-bar.copy-to-library")
|
||||
:on-select on-copy}])
|
||||
i/copy]
|
||||
[:span.move-item.tooltip.tooltip-top
|
||||
{:alt (tr "ds.multiselect-bar.move")
|
||||
:on-click on-toggle-move}
|
||||
(when (:show-move-tooltip @local)
|
||||
[:& grid-options-tooltip {:selected id
|
||||
:title (tr "ds.multiselect-bar.move-to-library")
|
||||
:on-select on-move}])
|
||||
i/move]
|
||||
[:span.delete.tooltip.tooltip-top
|
||||
{:alt (tr "ds.multiselect-bar.delete")
|
||||
:on-click on-delete}
|
||||
i/trash]]
|
||||
|
||||
;; if not editable
|
||||
[:div.multiselect-nav
|
||||
[:span.move-item.tooltip.tooltip-top
|
||||
{:alt (tr "ds.multiselect-bar.copy")
|
||||
:on-click on-toggle-copy}
|
||||
(when (:show-copy-tooltip @local)
|
||||
[:& grid-options-tooltip {:selected id
|
||||
:title (tr "ds.multiselect-bar.copy-to-library")
|
||||
:on-select on-copy}])
|
||||
i/organize]])])))
|
||||
|
||||
(mf/defc grid-item
|
||||
[{:keys [color selected?] :as props}]
|
||||
(letfn [(toggle-selection [event]
|
||||
(st/emit! (dc/toggle-color-selection color)))]
|
||||
[:div.grid-item.small-item.project-th {:on-click toggle-selection}
|
||||
[:span.color-swatch {:style {:background-color color}}]
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id color
|
||||
:on-change toggle-selection
|
||||
:checked selected?}]
|
||||
[:label {:for color}]]
|
||||
[:span.color-data color]
|
||||
[:span.color-data (apply str "RGB " (interpose ", " (hex->rgb color)))]]))
|
||||
|
||||
(mf/defc grid
|
||||
[{:keys [id type coll selected] :as props}]
|
||||
(let [{:keys [colors]} coll
|
||||
editable? (= :own type)
|
||||
colors (->> (remove nil? colors)
|
||||
(sort-by identity))]
|
||||
[:div.dashboard-grid-content
|
||||
[:div.dashboard-grid-row
|
||||
(when (and editable? id)
|
||||
[:& grid-form {:id id}])
|
||||
(for [color colors]
|
||||
(let [selected? (contains? selected color)]
|
||||
[:& grid-item {:color color :selected? selected? :key color}]))]]))
|
||||
|
||||
(mf/defc content
|
||||
[{:keys [id type coll] :as props}]
|
||||
(let [selected (mf/deref selected-colors-iref)]
|
||||
[:section.dashboard-grid.library
|
||||
(when coll
|
||||
[:& grid-header {:coll coll}])
|
||||
[:& grid {:coll coll :id id :type type :selected selected}]
|
||||
(when (seq selected)
|
||||
[:& grid-options {:id id :type type
|
||||
:selected selected
|
||||
:coll coll}])]))
|
||||
|
||||
;; --- Colors Page
|
||||
|
||||
(mf/defc colors-page
|
||||
[{:keys [id type] :as props}]
|
||||
(let [type (or type :own)
|
||||
|
||||
colls (mf/deref collections-iref)
|
||||
colls (cond->> (vals colls)
|
||||
(= type :own) (filter #(= :own (:type %)))
|
||||
(= type :builtin) (filter #(= :builtin (:type %)))
|
||||
true (sort-by :created-at))
|
||||
selected-coll (if id
|
||||
(seek #(= id (:id %)) colls)
|
||||
(first colls))
|
||||
id (:id selected-coll)]
|
||||
|
||||
(mf/use-effect #(st/emit! (dc/fetch-collections)))
|
||||
|
||||
[:section.dashboard-content
|
||||
[:& nav {:type type
|
||||
:id id
|
||||
:colls colls}]
|
||||
[:& content {:type type
|
||||
:id id
|
||||
:coll selected-coll}]]))
|
||||
|
||||
;; ;; --- Refs
|
||||
;;
|
||||
;; (def collections-iref
|
||||
;; (-> (l/key :colors-collections)
|
||||
;; (l/derive st/state)))
|
||||
;;
|
||||
;; (def selected-colors-iref
|
||||
;; (-> (l/in [:dashboard :colors :selected])
|
||||
;; (l/derive st/state)))
|
||||
;;
|
||||
;; ;; --- Colors Modal (Component)
|
||||
;;
|
||||
;; (mf/defc color-modal
|
||||
;; [{:keys [on-submit value] :as props}]
|
||||
;; (let [local (mf/use-var value)]
|
||||
;; [:div.lightbox-body
|
||||
;; [:h3 (tr "ds.color-lightbox.title" )]
|
||||
;; [:form
|
||||
;; [:div.row-flex.center
|
||||
;; [:& colorpicker {:value (or @local "#00ccff")
|
||||
;; :on-change #(reset! local %)}]]
|
||||
;; [:input#project-btn.btn-primary
|
||||
;; {:value (tr "ds.color-lightbox.add")
|
||||
;; :on-click #(on-submit @local)
|
||||
;; :type "button"}]]]))
|
||||
;;
|
||||
;; ;; --- Page Title
|
||||
;;
|
||||
;;
|
||||
;; (mf/defc grid-header
|
||||
;; [{:keys [coll] :as props}]
|
||||
;; (letfn [(on-change [name]
|
||||
;; (st/emit! (dc/rename-collection (:id coll) name)))
|
||||
;;
|
||||
;; (delete []
|
||||
;; (st/emit!
|
||||
;; (dc/delete-collection (:id coll))
|
||||
;; (rt/nav :dashboard-colors nil {:type (:type coll)})))
|
||||
;;
|
||||
;; (on-delete []
|
||||
;; (modal/show! confirm-dialog {:on-accept delete}))]
|
||||
;; [:& common/grid-header {:value (:name coll)
|
||||
;; :on-change on-change
|
||||
;; :on-delete on-delete}]))
|
||||
;;
|
||||
;; ;; --- Nav
|
||||
;;
|
||||
;; (mf/defc nav-item
|
||||
;; [{:keys [coll selected?] :as props}]
|
||||
;; (let [local (mf/use-state {})
|
||||
;; {:keys [id type name]} coll
|
||||
;; colors (count (:colors coll))
|
||||
;; editable? (= type :own)]
|
||||
;; (letfn [(on-click [event]
|
||||
;; (let [type (or type :own)]
|
||||
;; (st/emit! (rt/nav :dashboard-colors nil {:type type :id id}))))
|
||||
;; (on-input-change [event]
|
||||
;; (let [value (dom/get-target event)
|
||||
;; value (dom/get-value value)]
|
||||
;; (swap! local assoc :name value)))
|
||||
;; (on-cancel [event]
|
||||
;; (swap! local dissoc :name)
|
||||
;; (swap! local dissoc :edit))
|
||||
;; (on-double-click [event]
|
||||
;; (when editable?
|
||||
;; (swap! local assoc :edit true)))
|
||||
;; (on-input-keyup [event]
|
||||
;; (when (k/enter? event)
|
||||
;; (let [value (dom/get-target event)
|
||||
;; value (dom/get-value value)]
|
||||
;; (st/emit! (dc/rename-collection id (str/trim (:name @local))))
|
||||
;; (swap! local assoc :edit false))))]
|
||||
;; [:li {:on-click on-click
|
||||
;; :on-double-click on-double-click
|
||||
;; :class-name (when selected? "current")}
|
||||
;; (if (:edit @local)
|
||||
;; [:div
|
||||
;; [:input.element-title
|
||||
;; {:value (if (:name @local) (:name @local) name)
|
||||
;; :on-change on-input-change
|
||||
;; :on-key-down on-input-keyup}]
|
||||
;; [:span.close {:on-click on-cancel} i/close]]
|
||||
;; [:span.element-title name])
|
||||
;; #_[:span.element-subtitle
|
||||
;; (tr "ds.num-elements" (t/c colors))]])))
|
||||
;;
|
||||
;; (mf/defc nav
|
||||
;; [{:keys [id type colls selected-coll] :as props}]
|
||||
;; (let [own? (= type :own)
|
||||
;; builtin? (= type :builtin)
|
||||
;; select-tab #(st/emit! (rt/nav :dashboard-colors nil {:type %}))]
|
||||
;; [:div.library-bar
|
||||
;; [:div.library-bar-inside
|
||||
;; [:ul.library-tabs
|
||||
;; [:li {:class-name (when own? "current")
|
||||
;; :on-click (partial select-tab :own)}
|
||||
;; (tr "ds.your-colors-title")]
|
||||
;; [:li {:class-name (when builtin? "current")
|
||||
;; :on-click (partial select-tab :builtin)}
|
||||
;; (tr "ds.store-colors-title")]]
|
||||
;; [:ul.library-elements
|
||||
;; (when own?
|
||||
;; [:li
|
||||
;; [:a.btn-primary {:on-click #(st/emit! (dc/create-collection))}
|
||||
;; (tr "ds.colors-collection.new")]])
|
||||
;; (for [item colls]
|
||||
;; (let [selected? (= (:id item) (:id selected-coll))]
|
||||
;; [:& nav-item {:coll item :selected? selected? :key (:id item)}]))]]]))
|
||||
;;
|
||||
;; ;; --- Grid
|
||||
;;
|
||||
;; (mf/defc grid-form
|
||||
;; [{:keys [id] :as props}]
|
||||
;; (letfn [(on-submit [val]
|
||||
;; (st/emit! (dc/add-color id val))
|
||||
;; (modal/hide!))
|
||||
;; (on-click [event]
|
||||
;; (modal/show! color-modal {:on-submit on-submit}))]
|
||||
;; [:div.grid-item.small-item.add-project {:on-click on-click}
|
||||
;; [:span (tr "ds.color-new")]]))
|
||||
;;
|
||||
;; (mf/defc grid-options-tooltip
|
||||
;; [{:keys [selected on-select title] :as props}]
|
||||
;; {:pre [(uuid? selected)
|
||||
;; (fn? on-select)
|
||||
;; (string? title)]}
|
||||
;; (let [colls (mf/deref collections-iref)
|
||||
;; colls (->> (vals colls)
|
||||
;; (filter #(= :own (:type %)))
|
||||
;; (remove #(= selected (:id %)))
|
||||
;; (sort-by :name colls))
|
||||
;; on-select (fn [event id]
|
||||
;; (dom/prevent-default event)
|
||||
;; (dom/stop-propagation event)
|
||||
;; (on-select id))]
|
||||
;; [:ul.move-list
|
||||
;; [:li.title title]
|
||||
;; (for [{:keys [id name] :as coll} colls]
|
||||
;; [:li {:key (str id)}
|
||||
;; [:a {:on-click #(on-select % id)} name]])]))
|
||||
;;
|
||||
;; (mf/defc grid-options
|
||||
;; [{:keys [id type coll selected] :as props}]
|
||||
;; (let [local (mf/use-state {})]
|
||||
;; (letfn [(delete [event]
|
||||
;; (st/emit! (dc/delete-colors id selected)))
|
||||
;; (on-delete [event]
|
||||
;; (modal/show! confirm-dialog {:on-accept delete}))
|
||||
;; (on-toggle-copy [event]
|
||||
;; (swap! local update :show-copy-tooltip not)
|
||||
;; (swap! local assoc :show-move-tooltip false))
|
||||
;; (on-toggle-move [event]
|
||||
;; (swap! local update :show-move-tooltip not)
|
||||
;; (swap! local assoc :show-copy-tooltip false))
|
||||
;; (on-copy [selected]
|
||||
;; (swap! local assoc
|
||||
;; :show-move-tooltip false
|
||||
;; :show-copy-tooltip false)
|
||||
;; (st/emit! (dc/copy-selected selected)))
|
||||
;; (on-move [selected]
|
||||
;; (swap! local assoc
|
||||
;; :show-move-tooltip false
|
||||
;; :show-copy-tooltip false)
|
||||
;; (st/emit! (dc/move-selected id selected)))]
|
||||
;;
|
||||
;; ;; MULTISELECT OPTIONS BAR
|
||||
;; [:div.multiselect-bar
|
||||
;; (if (or (= type :own) (nil? id))
|
||||
;; ;; if editable
|
||||
;; [:div.multiselect-nav
|
||||
;; [:span.move-item.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; :on-click on-toggle-copy}
|
||||
;; (when (:show-copy-tooltip @local)
|
||||
;; [:& grid-options-tooltip {:selected id
|
||||
;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; :on-select on-copy}])
|
||||
;; i/copy]
|
||||
;; [:span.move-item.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.move")
|
||||
;; :on-click on-toggle-move}
|
||||
;; (when (:show-move-tooltip @local)
|
||||
;; [:& grid-options-tooltip {:selected id
|
||||
;; :title (tr "ds.multiselect-bar.move-to-library")
|
||||
;; :on-select on-move}])
|
||||
;; i/move]
|
||||
;; [:span.delete.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.delete")
|
||||
;; :on-click on-delete}
|
||||
;; i/trash]]
|
||||
;;
|
||||
;; ;; if not editable
|
||||
;; [:div.multiselect-nav
|
||||
;; [:span.move-item.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; :on-click on-toggle-copy}
|
||||
;; (when (:show-copy-tooltip @local)
|
||||
;; [:& grid-options-tooltip {:selected id
|
||||
;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; :on-select on-copy}])
|
||||
;; i/organize]])])))
|
||||
;;
|
||||
;; (mf/defc grid-item
|
||||
;; [{:keys [color selected?] :as props}]
|
||||
;; (letfn [(toggle-selection [event]
|
||||
;; (st/emit! (dc/toggle-color-selection color)))]
|
||||
;; [:div.grid-item.small-item.project-th {:on-click toggle-selection}
|
||||
;; [:span.color-swatch {:style {:background-color color}}]
|
||||
;; [:div.input-checkbox.check-primary
|
||||
;; [:input {:type "checkbox"
|
||||
;; :id color
|
||||
;; :on-change toggle-selection
|
||||
;; :checked selected?}]
|
||||
;; [:label {:for color}]]
|
||||
;; [:span.color-data color]
|
||||
;; [:span.color-data (apply str "RGB " (interpose ", " (hex->rgb color)))]]))
|
||||
;;
|
||||
;; (mf/defc grid
|
||||
;; [{:keys [id type coll selected] :as props}]
|
||||
;; (let [{:keys [colors]} coll
|
||||
;; editable? (= :own type)
|
||||
;; colors (->> (remove nil? colors)
|
||||
;; (sort-by identity))]
|
||||
;; [:div.dashboard-grid-content
|
||||
;; [:div.dashboard-grid-row
|
||||
;; (when (and editable? id)
|
||||
;; [:& grid-form {:id id}])
|
||||
;; (for [color colors]
|
||||
;; (let [selected? (contains? selected color)]
|
||||
;; [:& grid-item {:color color :selected? selected? :key color}]))]]))
|
||||
;;
|
||||
;; (mf/defc content
|
||||
;; [{:keys [id type coll] :as props}]
|
||||
;; (let [selected (mf/deref selected-colors-iref)]
|
||||
;; [:section.dashboard-grid.library
|
||||
;; (when coll
|
||||
;; [:& grid-header {:coll coll}])
|
||||
;; [:& grid {:coll coll :id id :type type :selected selected}]
|
||||
;; (when (seq selected)
|
||||
;; [:& grid-options {:id id :type type
|
||||
;; :selected selected
|
||||
;; :coll coll}])]))
|
||||
;;
|
||||
;; ;; --- Colors Page
|
||||
;;
|
||||
;; (mf/defc colors-page
|
||||
;; [{:keys [id type] :as props}]
|
||||
;; (let [type (or type :own)
|
||||
;;
|
||||
;; colls (mf/deref collections-iref)
|
||||
;; colls (cond->> (vals colls)
|
||||
;; (= type :own) (filter #(= :own (:type %)))
|
||||
;; (= type :builtin) (filter #(= :builtin (:type %)))
|
||||
;; true (sort-by :created-at))
|
||||
;; selected-coll (if id
|
||||
;; (seek #(= id (:id %)) colls)
|
||||
;; (first colls))
|
||||
;; id (:id selected-coll)]
|
||||
;;
|
||||
;; (mf/use-effect #(st/emit! (dc/fetch-collections)))
|
||||
;;
|
||||
;; [:section.dashboard-content
|
||||
;; [:& nav {:type type
|
||||
;; :id id
|
||||
;; :colls colls}]
|
||||
;; [:& content {:type type
|
||||
;; :id id
|
||||
;; :coll selected-coll}]]))
|
||||
;;
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
[uxbox.builtins.icons :as i]
|
||||
[rumext.core :as mx :include-macros true]
|
||||
[uxbox.main.ui.lightbox :as lbx]
|
||||
[uxbox.main.ui.dashboard.header :refer (header)]
|
||||
#_[uxbox.main.ui.dashboard.header :refer (header)]
|
||||
[uxbox.util.dom :as dom]))
|
||||
|
||||
;; --- Page Title
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
;; defined by the Mozilla Public License, v. 2.0.
|
||||
;;
|
||||
;; Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
;; Copyright (c) 2015-2020 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
|
||||
(ns uxbox.main.ui.dashboard.header
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.util.i18n :as i18n :refer [t]]
|
||||
[uxbox.main.ui.dashboard.profile :refer [profile-section]]))
|
||||
|
||||
|
||||
;; --- Component: Header
|
||||
|
||||
(mf/defc header
|
||||
[{:keys [profile] :as props}]
|
||||
(let [locale (i18n/use-locale)]
|
||||
[:header#main-bar.main-bar
|
||||
[:h1.dashboard-title "Personal"]
|
||||
[:a.btn-dashboard "+ New project"]]))
|
||||
|
||||
@ -28,357 +28,357 @@
|
||||
[uxbox.util.router :as rt]
|
||||
[uxbox.util.time :as dt]))
|
||||
|
||||
;; --- Helpers & Constants
|
||||
|
||||
(def +ordering-options+
|
||||
{:name "ds.ordering.by-name"
|
||||
:created "ds.ordering.by-creation-date"})
|
||||
|
||||
(defn- sort-icons-by
|
||||
[ordering icons]
|
||||
(case ordering
|
||||
:name (sort-by :name icons)
|
||||
:created (reverse (sort-by :created-at icons))
|
||||
icons))
|
||||
|
||||
(defn- contains-term?
|
||||
[phrase term]
|
||||
{:pre [(string? phrase)
|
||||
(string? term)]}
|
||||
(let [term (name term)]
|
||||
(str/includes? (str/lower phrase) (str/trim (str/lower term)))))
|
||||
|
||||
(defn- filter-icons-by
|
||||
[term icons]
|
||||
(if (str/blank? term)
|
||||
icons
|
||||
(filter #(contains-term? (:name %) term) icons)))
|
||||
|
||||
;; --- Component: Grid Header
|
||||
|
||||
(mf/defc grid-header
|
||||
[{:keys [collection] :as props}]
|
||||
(let [{:keys [id type]} collection
|
||||
on-change #(st/emit! (di/rename-collection id %))
|
||||
on-deleted #(st/emit! (rt/nav :dashboard-icons nil {:type type}))
|
||||
delete #(st/emit! (di/delete-collection id on-deleted))
|
||||
on-delete #(modal/show! confirm-dialog {:on-accept delete})]
|
||||
[:& common/grid-header {:value (:name collection)
|
||||
:on-change on-change
|
||||
:on-delete on-delete}]))
|
||||
|
||||
;; --- Nav
|
||||
|
||||
(mf/defc nav-item
|
||||
[{:keys [collection selected?] :as props}]
|
||||
(let [local (mf/use-state {})
|
||||
{:keys [id type name]} collection
|
||||
editable? (= type :own)
|
||||
|
||||
on-click
|
||||
(fn [event]
|
||||
(let [type (or type :own)]
|
||||
(st/emit! (rt/nav :dashboard-icons {} {:type type :id id}))))
|
||||
|
||||
|
||||
on-input-change
|
||||
(fn [event]
|
||||
(-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(swap! local assoc :name)))
|
||||
|
||||
on-cancel #(swap! local dissoc :name :edit)
|
||||
on-double-click #(when editable? (swap! local assoc :edit true))
|
||||
|
||||
on-input-keyup
|
||||
(fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(let [value (-> (dom/get-target event) (dom/get-value))]
|
||||
(st/emit! (di/rename-collection id (str/trim (:name @local))))
|
||||
(swap! local assoc :edit false))))]
|
||||
|
||||
[:li {:on-click on-click
|
||||
:on-double-click on-double-click
|
||||
:class-name (when selected? "current")}
|
||||
(if (:edit @local)
|
||||
[:div
|
||||
[:input.element-title {:value (or (:name @local) name)
|
||||
:on-change on-input-change
|
||||
:on-key-down on-input-keyup}]
|
||||
[:span.close {:on-click on-cancel} i/close]]
|
||||
[:span.element-title name])]))
|
||||
|
||||
|
||||
(mf/defc nav
|
||||
[{:keys [id type collections] :as props}]
|
||||
(let [locale (i18n/use-locale)
|
||||
own? (= type :own)
|
||||
builtin? (= type :builtin)
|
||||
create-collection #(st/emit! di/create-collection)
|
||||
select-own-tab #(st/emit! (rt/nav :dashboard-icons nil {:type :own}))
|
||||
select-buitin-tab #(st/emit! (rt/nav :dashboard-icons nil {:type :builtin}))]
|
||||
|
||||
[:div.library-bar
|
||||
[:div.library-bar-inside
|
||||
;; Tabs
|
||||
[:ul.library-tabs
|
||||
[:li {:class (when own? "current")
|
||||
:on-click select-own-tab}
|
||||
(t locale "ds.your-icons-title")]
|
||||
|
||||
[:li {:class (when builtin? "current")
|
||||
:on-click select-buitin-tab}
|
||||
(t locale "ds.store-icons-title")]]
|
||||
|
||||
|
||||
;; Collections List
|
||||
[:ul.library-elements
|
||||
(when own?
|
||||
[:li
|
||||
[:a.btn-primary {:on-click #(st/emit! di/create-collection)}
|
||||
(tr "ds.icons-collection.new")]])
|
||||
(for [item collections]
|
||||
[:& nav-item {:collection item
|
||||
:selected? (= (:id item) id)
|
||||
:key (:id item)}])]]]))
|
||||
|
||||
|
||||
;; (mf/def grid-options-tooltip
|
||||
;; :mixins [mf/reactive mf/memo]
|
||||
|
||||
;; :render
|
||||
;; (fn [own {:keys [selected on-select title]}]
|
||||
;; {:pre [(uuid? selected)
|
||||
;; (fn? on-select)
|
||||
;; (string? title)]}
|
||||
;; (let [colls (mf/react collections-iref)
|
||||
;; colls (->> (vals colls)
|
||||
;; (filter #(= :own (:type %)))
|
||||
;; (remove #(= selected (:id %)))
|
||||
;; (sort-by :name colls))
|
||||
;; on-select (fn [event id]
|
||||
;; (dom/prevent-default event)
|
||||
;; (dom/stop-propagation event)
|
||||
;; (on-select id))]
|
||||
;; [:ul.move-list
|
||||
;; [:li.title title]
|
||||
;; [:li
|
||||
;; [:a {:href "#" :on-click #(on-select % nil)} "Storage"]]
|
||||
;; (for [{:keys [id name] :as coll} colls]
|
||||
;; [:li {:key (pr-str id)}
|
||||
;; [:a {:on-click #(on-select % id)} name]])])))
|
||||
|
||||
(mf/defc grid-options
|
||||
[{:keys [id type selected] :as props}]
|
||||
(let [local (mf/use-state {})
|
||||
delete #(st/emit! di/delete-selected)
|
||||
on-delete #(modal/show! confirm-dialog {:on-accept delete})
|
||||
|
||||
;; (on-toggle-copy [event]
|
||||
;; (swap! local update :show-copy-tooltip not))
|
||||
;; (on-toggle-move [event]
|
||||
;; (swap! local update :show-move-tooltip not))
|
||||
;; (on-copy [selected]
|
||||
;; (swap! local assoc
|
||||
;; :show-move-tooltip false
|
||||
;; :show-copy-tooltip false)
|
||||
;; (st/emit! (di/copy-selected selected)))
|
||||
;; (on-move [selected]
|
||||
;; (swap! local assoc
|
||||
;; :show-move-tooltip false
|
||||
;; :show-copy-tooltip false)
|
||||
;; (st/emit! (di/move-selected selected)))
|
||||
;; (on-rename [event]
|
||||
;; (let [selected (first selected)]
|
||||
;; (st/emit! (di/update-opts :edition selected))))
|
||||
]
|
||||
;; MULTISELECT OPTIONS BAR
|
||||
[:div.multiselect-bar
|
||||
(when (= type :own)
|
||||
;; If editable
|
||||
[:div.multiselect-nav
|
||||
;; [:span.move-item.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; :on-click on-toggle-copy}
|
||||
;; (when (:show-copy-tooltip @local)
|
||||
;; [:& grid-options-tooltip {:selected id
|
||||
;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; :on-select on-copy}])
|
||||
;; i/copy]
|
||||
;; [:span.move-item.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.move")
|
||||
;; :on-click on-toggle-move}
|
||||
;; (when (:show-move-tooltip @local)
|
||||
;; [:& grid-options-tooltip {:selected id
|
||||
;; :title (tr "ds.multiselect-bar.move-to-library")
|
||||
;; :on-select on-move}])
|
||||
;; i/move]
|
||||
;; (when (= 1 (count selected))
|
||||
;; [:span.move-item.tooltip.tooltip-top {:alt (tr "ds.multiselect-bar.rename")
|
||||
;; :on-click on-rename}
|
||||
;; i/pencil])
|
||||
[:span.delete.tooltip.tooltip-top
|
||||
{:alt (tr "ds.multiselect-bar.delete")
|
||||
:on-click on-delete}
|
||||
i/trash]]
|
||||
|
||||
;; If not editable
|
||||
;; [:div.multiselect-nav
|
||||
;; [:span.move-item.tooltip.tooltip-top {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; :on-click on-toggle-copy}
|
||||
;; (when (:show-copy-tooltip @local)
|
||||
;; [:& grid-options-tooltip {:selected id
|
||||
;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; :on-select on-copy}])
|
||||
;; i/organize]]
|
||||
)]))
|
||||
|
||||
;; --- Grid Form
|
||||
|
||||
(mf/defc grid-form
|
||||
[{:keys [id type uploading?] :as props}]
|
||||
(let [locale (i18n/use-locale)
|
||||
input (mf/use-ref nil)
|
||||
on-click #(dom/click (mf/ref-node input))
|
||||
on-select #(st/emit! (->> (dom/get-target %)
|
||||
(dom/get-files)
|
||||
(array-seq)
|
||||
(di/create-icons id)))]
|
||||
[:div.grid-item.add-project {:on-click on-click}
|
||||
(if uploading?
|
||||
[:div i/loader-pencil]
|
||||
[:span (t locale "ds.icon-new")])
|
||||
[:input.upload-icon-input
|
||||
{:style {:display "none"}
|
||||
:multiple true
|
||||
:ref input
|
||||
:value ""
|
||||
:accept "icon/svg+xml"
|
||||
:type "file"
|
||||
:on-change on-select}]]))
|
||||
|
||||
;; --- Grid Item
|
||||
|
||||
(mf/defc grid-item
|
||||
[{:keys [icon selected? edition?] :as props}]
|
||||
(let [toggle-selection #(st/emit! (if selected?
|
||||
(di/deselect-icon (:id icon))
|
||||
(di/select-icon (:id icon))))
|
||||
on-blur
|
||||
(fn [event]
|
||||
(let [target (dom/get-target event)
|
||||
name (dom/get-value target)]
|
||||
(st/emit! (di/update-opts :edition false)
|
||||
(di/rename-icon (:id icon) name))))
|
||||
|
||||
on-key-down
|
||||
(fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(on-blur event)))
|
||||
|
||||
ignore-click
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event))
|
||||
|
||||
on-edit
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (di/update-opts :edition (:id icon))))]
|
||||
|
||||
[:div.grid-item.small-item.project-th
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id (:id icon)
|
||||
:on-change toggle-selection
|
||||
:checked selected?}]
|
||||
[:label {:for (:id icon)}]]
|
||||
[:span.grid-item-icon
|
||||
[:& icon/icon-svg {:shape icon}]]
|
||||
[:div.item-info {:on-click ignore-click}
|
||||
(if edition?
|
||||
[:input.element-name {:type "text"
|
||||
:auto-focus true
|
||||
:on-key-down on-key-down
|
||||
:on-blur on-blur
|
||||
:on-click on-edit
|
||||
:default-value (:name icon)}]
|
||||
[:h3 {:on-double-click on-edit}
|
||||
(:name icon)])
|
||||
(str (tr "ds.uploaded-at" (dt/format (:created-at icon) "dd/MM/yyyy")))]]))
|
||||
|
||||
;; --- Grid
|
||||
|
||||
(def icons-iref
|
||||
(-> (comp (l/key :icons) (l/lens vals))
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc grid
|
||||
[{:keys [id type collection opts] :as props}]
|
||||
(let [editable? (= type :own)
|
||||
icons (->> (mf/deref icons-iref)
|
||||
(filter-icons-by (:filter opts ""))
|
||||
(sort-icons-by (:order opts :name)))]
|
||||
[:div.dashboard-grid-content
|
||||
[:div.dashboard-grid-row
|
||||
(when editable?
|
||||
[:& grid-form {:id id :type type :uploading? (:uploading opts)}])
|
||||
|
||||
[:& chunked-list {:items icons
|
||||
:initial-size 30
|
||||
:chunk-size 30
|
||||
:key (str type id (count icons))}
|
||||
(fn [icon]
|
||||
[:& grid-item {:icon icon
|
||||
:key (:id icon)
|
||||
:selected (contains? (:selected opts) (:id icon))
|
||||
:edition? (= (:edition opts) (:id icon))}])]]]))
|
||||
|
||||
;; --- Content
|
||||
|
||||
(def opts-iref
|
||||
(-> (l/key :dashboard-icons)
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc content
|
||||
[{:keys [id type collection] :as props}]
|
||||
(let [{:keys [selected] :as opts} (mf/deref opts-iref)]
|
||||
[:section.dashboard-grid.library
|
||||
(when collection
|
||||
[:& grid-header {:collection collection}])
|
||||
(if collection
|
||||
[:& grid {:id id :type type :collection collection :opts opts}]
|
||||
[:span "EMPTY STATE TODO"])
|
||||
(when-not (empty? selected)
|
||||
#_[:& grid-options {:id id :type type :selected (:selected opts)}])]))
|
||||
|
||||
;; --- Icons Page
|
||||
|
||||
(def collections-iref
|
||||
(-> (l/key :icons-collections)
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc icons-page
|
||||
[{:keys [id type] :as props}]
|
||||
(let [type (or type :own)
|
||||
collections (mf/deref collections-iref)
|
||||
collections (cond->> (vals collections)
|
||||
(= type :own) (filter #(= :own (:type %)))
|
||||
(= type :builtin) (filter #(= :builtin (:type %)))
|
||||
true (sort-by :created-at))
|
||||
|
||||
collection (cond
|
||||
(uuid? id) (seek #(= id (:id %)) collections)
|
||||
:else (first collections))
|
||||
|
||||
id (:id collection)]
|
||||
|
||||
(mf/use-effect #(st/emit! di/fetch-collections))
|
||||
(mf/use-effect
|
||||
{:fn #(when id (st/emit! (di/initialize id)))
|
||||
:deps (mf/deps id)})
|
||||
|
||||
[:section.dashboard-content
|
||||
[:& nav {:type type :id id :collections collections}]
|
||||
[:& content {:type type :id id :collection collection}]]))
|
||||
;; ;; --- Helpers & Constants
|
||||
;;
|
||||
;; (def +ordering-options+
|
||||
;; {:name "ds.ordering.by-name"
|
||||
;; :created "ds.ordering.by-creation-date"})
|
||||
;;
|
||||
;; (defn- sort-icons-by
|
||||
;; [ordering icons]
|
||||
;; (case ordering
|
||||
;; :name (sort-by :name icons)
|
||||
;; :created (reverse (sort-by :created-at icons))
|
||||
;; icons))
|
||||
;;
|
||||
;; (defn- contains-term?
|
||||
;; [phrase term]
|
||||
;; {:pre [(string? phrase)
|
||||
;; (string? term)]}
|
||||
;; (let [term (name term)]
|
||||
;; (str/includes? (str/lower phrase) (str/trim (str/lower term)))))
|
||||
;;
|
||||
;; (defn- filter-icons-by
|
||||
;; [term icons]
|
||||
;; (if (str/blank? term)
|
||||
;; icons
|
||||
;; (filter #(contains-term? (:name %) term) icons)))
|
||||
;;
|
||||
;; ;; --- Component: Grid Header
|
||||
;;
|
||||
;; (mf/defc grid-header
|
||||
;; [{:keys [collection] :as props}]
|
||||
;; (let [{:keys [id type]} collection
|
||||
;; on-change #(st/emit! (di/rename-collection id %))
|
||||
;; on-deleted #(st/emit! (rt/nav :dashboard-icons nil {:type type}))
|
||||
;; delete #(st/emit! (di/delete-collection id on-deleted))
|
||||
;; on-delete #(modal/show! confirm-dialog {:on-accept delete})]
|
||||
;; [:& common/grid-header {:value (:name collection)
|
||||
;; :on-change on-change
|
||||
;; :on-delete on-delete}]))
|
||||
;;
|
||||
;; ;; --- Nav
|
||||
;;
|
||||
;; (mf/defc nav-item
|
||||
;; [{:keys [collection selected?] :as props}]
|
||||
;; (let [local (mf/use-state {})
|
||||
;; {:keys [id type name]} collection
|
||||
;; editable? (= type :own)
|
||||
;;
|
||||
;; on-click
|
||||
;; (fn [event]
|
||||
;; (let [type (or type :own)]
|
||||
;; (st/emit! (rt/nav :dashboard-icons {} {:type type :id id}))))
|
||||
;;
|
||||
;;
|
||||
;; on-input-change
|
||||
;; (fn [event]
|
||||
;; (-> (dom/get-target event)
|
||||
;; (dom/get-value)
|
||||
;; (swap! local assoc :name)))
|
||||
;;
|
||||
;; on-cancel #(swap! local dissoc :name :edit)
|
||||
;; on-double-click #(when editable? (swap! local assoc :edit true))
|
||||
;;
|
||||
;; on-input-keyup
|
||||
;; (fn [event]
|
||||
;; (when (kbd/enter? event)
|
||||
;; (let [value (-> (dom/get-target event) (dom/get-value))]
|
||||
;; (st/emit! (di/rename-collection id (str/trim (:name @local))))
|
||||
;; (swap! local assoc :edit false))))]
|
||||
;;
|
||||
;; [:li {:on-click on-click
|
||||
;; :on-double-click on-double-click
|
||||
;; :class-name (when selected? "current")}
|
||||
;; (if (:edit @local)
|
||||
;; [:div
|
||||
;; [:input.element-title {:value (or (:name @local) name)
|
||||
;; :on-change on-input-change
|
||||
;; :on-key-down on-input-keyup}]
|
||||
;; [:span.close {:on-click on-cancel} i/close]]
|
||||
;; [:span.element-title name])]))
|
||||
;;
|
||||
;;
|
||||
;; (mf/defc nav
|
||||
;; [{:keys [id type collections] :as props}]
|
||||
;; (let [locale (i18n/use-locale)
|
||||
;; own? (= type :own)
|
||||
;; builtin? (= type :builtin)
|
||||
;; create-collection #(st/emit! di/create-collection)
|
||||
;; select-own-tab #(st/emit! (rt/nav :dashboard-icons nil {:type :own}))
|
||||
;; select-buitin-tab #(st/emit! (rt/nav :dashboard-icons nil {:type :builtin}))]
|
||||
;;
|
||||
;; [:div.library-bar
|
||||
;; [:div.library-bar-inside
|
||||
;; ;; Tabs
|
||||
;; [:ul.library-tabs
|
||||
;; [:li {:class (when own? "current")
|
||||
;; :on-click select-own-tab}
|
||||
;; (t locale "ds.your-icons-title")]
|
||||
;;
|
||||
;; [:li {:class (when builtin? "current")
|
||||
;; :on-click select-buitin-tab}
|
||||
;; (t locale "ds.store-icons-title")]]
|
||||
;;
|
||||
;;
|
||||
;; ;; Collections List
|
||||
;; [:ul.library-elements
|
||||
;; (when own?
|
||||
;; [:li
|
||||
;; [:a.btn-primary {:on-click #(st/emit! di/create-collection)}
|
||||
;; (tr "ds.icons-collection.new")]])
|
||||
;; (for [item collections]
|
||||
;; [:& nav-item {:collection item
|
||||
;; :selected? (= (:id item) id)
|
||||
;; :key (:id item)}])]]]))
|
||||
;;
|
||||
;;
|
||||
;; ;; (mf/def grid-options-tooltip
|
||||
;; ;; :mixins [mf/reactive mf/memo]
|
||||
;;
|
||||
;; ;; :render
|
||||
;; ;; (fn [own {:keys [selected on-select title]}]
|
||||
;; ;; {:pre [(uuid? selected)
|
||||
;; ;; (fn? on-select)
|
||||
;; ;; (string? title)]}
|
||||
;; ;; (let [colls (mf/react collections-iref)
|
||||
;; ;; colls (->> (vals colls)
|
||||
;; ;; (filter #(= :own (:type %)))
|
||||
;; ;; (remove #(= selected (:id %)))
|
||||
;; ;; (sort-by :name colls))
|
||||
;; ;; on-select (fn [event id]
|
||||
;; ;; (dom/prevent-default event)
|
||||
;; ;; (dom/stop-propagation event)
|
||||
;; ;; (on-select id))]
|
||||
;; ;; [:ul.move-list
|
||||
;; ;; [:li.title title]
|
||||
;; ;; [:li
|
||||
;; ;; [:a {:href "#" :on-click #(on-select % nil)} "Storage"]]
|
||||
;; ;; (for [{:keys [id name] :as coll} colls]
|
||||
;; ;; [:li {:key (pr-str id)}
|
||||
;; ;; [:a {:on-click #(on-select % id)} name]])])))
|
||||
;;
|
||||
;; (mf/defc grid-options
|
||||
;; [{:keys [id type selected] :as props}]
|
||||
;; (let [local (mf/use-state {})
|
||||
;; delete #(st/emit! di/delete-selected)
|
||||
;; on-delete #(modal/show! confirm-dialog {:on-accept delete})
|
||||
;;
|
||||
;; ;; (on-toggle-copy [event]
|
||||
;; ;; (swap! local update :show-copy-tooltip not))
|
||||
;; ;; (on-toggle-move [event]
|
||||
;; ;; (swap! local update :show-move-tooltip not))
|
||||
;; ;; (on-copy [selected]
|
||||
;; ;; (swap! local assoc
|
||||
;; ;; :show-move-tooltip false
|
||||
;; ;; :show-copy-tooltip false)
|
||||
;; ;; (st/emit! (di/copy-selected selected)))
|
||||
;; ;; (on-move [selected]
|
||||
;; ;; (swap! local assoc
|
||||
;; ;; :show-move-tooltip false
|
||||
;; ;; :show-copy-tooltip false)
|
||||
;; ;; (st/emit! (di/move-selected selected)))
|
||||
;; ;; (on-rename [event]
|
||||
;; ;; (let [selected (first selected)]
|
||||
;; ;; (st/emit! (di/update-opts :edition selected))))
|
||||
;; ]
|
||||
;; ;; MULTISELECT OPTIONS BAR
|
||||
;; [:div.multiselect-bar
|
||||
;; (when (= type :own)
|
||||
;; ;; If editable
|
||||
;; [:div.multiselect-nav
|
||||
;; ;; [:span.move-item.tooltip.tooltip-top
|
||||
;; ;; {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; ;; :on-click on-toggle-copy}
|
||||
;; ;; (when (:show-copy-tooltip @local)
|
||||
;; ;; [:& grid-options-tooltip {:selected id
|
||||
;; ;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; ;; :on-select on-copy}])
|
||||
;; ;; i/copy]
|
||||
;; ;; [:span.move-item.tooltip.tooltip-top
|
||||
;; ;; {:alt (tr "ds.multiselect-bar.move")
|
||||
;; ;; :on-click on-toggle-move}
|
||||
;; ;; (when (:show-move-tooltip @local)
|
||||
;; ;; [:& grid-options-tooltip {:selected id
|
||||
;; ;; :title (tr "ds.multiselect-bar.move-to-library")
|
||||
;; ;; :on-select on-move}])
|
||||
;; ;; i/move]
|
||||
;; ;; (when (= 1 (count selected))
|
||||
;; ;; [:span.move-item.tooltip.tooltip-top {:alt (tr "ds.multiselect-bar.rename")
|
||||
;; ;; :on-click on-rename}
|
||||
;; ;; i/pencil])
|
||||
;; [:span.delete.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.delete")
|
||||
;; :on-click on-delete}
|
||||
;; i/trash]]
|
||||
;;
|
||||
;; ;; If not editable
|
||||
;; ;; [:div.multiselect-nav
|
||||
;; ;; [:span.move-item.tooltip.tooltip-top {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; ;; :on-click on-toggle-copy}
|
||||
;; ;; (when (:show-copy-tooltip @local)
|
||||
;; ;; [:& grid-options-tooltip {:selected id
|
||||
;; ;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; ;; :on-select on-copy}])
|
||||
;; ;; i/organize]]
|
||||
;; )]))
|
||||
;;
|
||||
;; ;; --- Grid Form
|
||||
;;
|
||||
;; (mf/defc grid-form
|
||||
;; [{:keys [id type uploading?] :as props}]
|
||||
;; (let [locale (i18n/use-locale)
|
||||
;; input (mf/use-ref nil)
|
||||
;; on-click #(dom/click (mf/ref-node input))
|
||||
;; on-select #(st/emit! (->> (dom/get-target %)
|
||||
;; (dom/get-files)
|
||||
;; (array-seq)
|
||||
;; (di/create-icons id)))]
|
||||
;; [:div.grid-item.add-project {:on-click on-click}
|
||||
;; (if uploading?
|
||||
;; [:div i/loader-pencil]
|
||||
;; [:span (t locale "ds.icon-new")])
|
||||
;; [:input.upload-icon-input
|
||||
;; {:style {:display "none"}
|
||||
;; :multiple true
|
||||
;; :ref input
|
||||
;; :value ""
|
||||
;; :accept "icon/svg+xml"
|
||||
;; :type "file"
|
||||
;; :on-change on-select}]]))
|
||||
;;
|
||||
;; ;; --- Grid Item
|
||||
;;
|
||||
;; (mf/defc grid-item
|
||||
;; [{:keys [icon selected? edition?] :as props}]
|
||||
;; (let [toggle-selection #(st/emit! (if selected?
|
||||
;; (di/deselect-icon (:id icon))
|
||||
;; (di/select-icon (:id icon))))
|
||||
;; on-blur
|
||||
;; (fn [event]
|
||||
;; (let [target (dom/get-target event)
|
||||
;; name (dom/get-value target)]
|
||||
;; (st/emit! (di/update-opts :edition false)
|
||||
;; (di/rename-icon (:id icon) name))))
|
||||
;;
|
||||
;; on-key-down
|
||||
;; (fn [event]
|
||||
;; (when (kbd/enter? event)
|
||||
;; (on-blur event)))
|
||||
;;
|
||||
;; ignore-click
|
||||
;; (fn [event]
|
||||
;; (dom/stop-propagation event)
|
||||
;; (dom/prevent-default event))
|
||||
;;
|
||||
;; on-edit
|
||||
;; (fn [event]
|
||||
;; (dom/stop-propagation event)
|
||||
;; (dom/prevent-default event)
|
||||
;; (st/emit! (di/update-opts :edition (:id icon))))]
|
||||
;;
|
||||
;; [:div.grid-item.small-item.project-th
|
||||
;; [:div.input-checkbox.check-primary
|
||||
;; [:input {:type "checkbox"
|
||||
;; :id (:id icon)
|
||||
;; :on-change toggle-selection
|
||||
;; :checked selected?}]
|
||||
;; [:label {:for (:id icon)}]]
|
||||
;; [:span.grid-item-icon
|
||||
;; [:& icon/icon-svg {:shape icon}]]
|
||||
;; [:div.item-info {:on-click ignore-click}
|
||||
;; (if edition?
|
||||
;; [:input.element-name {:type "text"
|
||||
;; :auto-focus true
|
||||
;; :on-key-down on-key-down
|
||||
;; :on-blur on-blur
|
||||
;; :on-click on-edit
|
||||
;; :default-value (:name icon)}]
|
||||
;; [:h3 {:on-double-click on-edit}
|
||||
;; (:name icon)])
|
||||
;; (str (tr "ds.uploaded-at" (dt/format (:created-at icon) "dd/MM/yyyy")))]]))
|
||||
;;
|
||||
;; ;; --- Grid
|
||||
;;
|
||||
;; (def icons-iref
|
||||
;; (-> (comp (l/key :icons) (l/lens vals))
|
||||
;; (l/derive st/state)))
|
||||
;;
|
||||
;; (mf/defc grid
|
||||
;; [{:keys [id type collection opts] :as props}]
|
||||
;; (let [editable? (= type :own)
|
||||
;; icons (->> (mf/deref icons-iref)
|
||||
;; (filter-icons-by (:filter opts ""))
|
||||
;; (sort-icons-by (:order opts :name)))]
|
||||
;; [:div.dashboard-grid-content
|
||||
;; [:div.dashboard-grid-row
|
||||
;; (when editable?
|
||||
;; [:& grid-form {:id id :type type :uploading? (:uploading opts)}])
|
||||
;;
|
||||
;; [:& chunked-list {:items icons
|
||||
;; :initial-size 30
|
||||
;; :chunk-size 30
|
||||
;; :key (str type id (count icons))}
|
||||
;; (fn [icon]
|
||||
;; [:& grid-item {:icon icon
|
||||
;; :key (:id icon)
|
||||
;; :selected (contains? (:selected opts) (:id icon))
|
||||
;; :edition? (= (:edition opts) (:id icon))}])]]]))
|
||||
;;
|
||||
;; ;; --- Content
|
||||
;;
|
||||
;; (def opts-iref
|
||||
;; (-> (l/key :dashboard-icons)
|
||||
;; (l/derive st/state)))
|
||||
;;
|
||||
;; (mf/defc content
|
||||
;; [{:keys [id type collection] :as props}]
|
||||
;; (let [{:keys [selected] :as opts} (mf/deref opts-iref)]
|
||||
;; [:section.dashboard-grid.library
|
||||
;; (when collection
|
||||
;; [:& grid-header {:collection collection}])
|
||||
;; (if collection
|
||||
;; [:& grid {:id id :type type :collection collection :opts opts}]
|
||||
;; [:span "EMPTY STATE TODO"])
|
||||
;; (when-not (empty? selected)
|
||||
;; #_[:& grid-options {:id id :type type :selected (:selected opts)}])]))
|
||||
;;
|
||||
;; ;; --- Icons Page
|
||||
;;
|
||||
;; (def collections-iref
|
||||
;; (-> (l/key :icons-collections)
|
||||
;; (l/derive st/state)))
|
||||
;;
|
||||
;; (mf/defc icons-page
|
||||
;; [{:keys [id type] :as props}]
|
||||
;; (let [type (or type :own)
|
||||
;; collections (mf/deref collections-iref)
|
||||
;; collections (cond->> (vals collections)
|
||||
;; (= type :own) (filter #(= :own (:type %)))
|
||||
;; (= type :builtin) (filter #(= :builtin (:type %)))
|
||||
;; true (sort-by :created-at))
|
||||
;;
|
||||
;; collection (cond
|
||||
;; (uuid? id) (seek #(= id (:id %)) collections)
|
||||
;; :else (first collections))
|
||||
;;
|
||||
;; id (:id collection)]
|
||||
;;
|
||||
;; (mf/use-effect #(st/emit! di/fetch-collections))
|
||||
;; (mf/use-effect
|
||||
;; {:fn #(when id (st/emit! (di/initialize id)))
|
||||
;; :deps (mf/deps id)})
|
||||
;;
|
||||
;; [:section.dashboard-content
|
||||
;; [:& nav {:type type :id id :collections collections}]
|
||||
;; [:& content {:type type :id id :collection collection}]]))
|
||||
|
||||
@ -28,360 +28,360 @@
|
||||
[uxbox.util.router :as rt]
|
||||
[uxbox.util.time :as dt]))
|
||||
|
||||
;; --- Page Title
|
||||
|
||||
(mf/defc grid-header
|
||||
[{:keys [collection] :as props}]
|
||||
(let [{:keys [id type]} collection
|
||||
on-change #(st/emit! (di/rename-collection id %))
|
||||
on-deleted #(st/emit! (rt/nav :dashboard-images nil {:type type}))
|
||||
delete #(st/emit! (di/delete-collection id on-deleted))
|
||||
on-delete #(modal/show! confirm-dialog {:on-accept delete})]
|
||||
[:& common/grid-header {:value (:name collection)
|
||||
:on-change on-change
|
||||
:on-delete on-delete}]))
|
||||
|
||||
;; --- Nav
|
||||
|
||||
(mf/defc nav-item
|
||||
[{:keys [coll selected?] :as props}]
|
||||
(let [local (mf/use-state {})
|
||||
{:keys [id type name num-images]} coll
|
||||
editable? (= type :own)
|
||||
|
||||
on-click
|
||||
(fn [event]
|
||||
(let [type (or type :own)]
|
||||
(st/emit! (rt/nav :dashboard-images {} {:type type :id id}))))
|
||||
|
||||
on-cancel-edition #(swap! local dissoc :edit)
|
||||
on-double-click #(when editable? (swap! local assoc :edit true))
|
||||
|
||||
on-input-keyup
|
||||
(fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(str/trim))]
|
||||
(st/emit! (di/rename-collection id value))
|
||||
(swap! local assoc :edit false))))]
|
||||
|
||||
[:li {:on-click on-click
|
||||
:on-double-click on-double-click
|
||||
:class-name (when selected? "current")}
|
||||
(if (:edit @local)
|
||||
[:div
|
||||
[:input.element-title {:default-value name
|
||||
:on-key-down on-input-keyup}]
|
||||
[:span.close {:on-click on-cancel-edition} i/close]]
|
||||
[:span.element-title (if id name "Storage")])]))
|
||||
|
||||
(mf/defc nav
|
||||
[{:keys [id type collections] :as props}]
|
||||
(let [locale (i18n/use-locale)
|
||||
own? (= type :own)
|
||||
builtin? (= type :builtin)
|
||||
create-collection #(st/emit! di/create-collection)
|
||||
select-own-tab #(st/emit! (rt/nav :dashboard-images nil {:type :own}))
|
||||
select-buitin-tab #(st/emit! (rt/nav :dashboard-images nil {:type :builtin}))]
|
||||
[:div.library-bar
|
||||
[:div.library-bar-inside
|
||||
|
||||
;; Tabs
|
||||
[:ul.library-tabs
|
||||
[:li {:class (when own? "current")
|
||||
:on-click select-own-tab}
|
||||
(t locale "ds.your-images-title")]
|
||||
|
||||
[:li {:class (when builtin? "current")
|
||||
:on-click select-buitin-tab}
|
||||
(t locale "ds.store-images-title")]]
|
||||
|
||||
;; Collections List
|
||||
[:ul.library-elements
|
||||
(when own?
|
||||
[:li
|
||||
[:a.btn-primary {:on-click create-collection}
|
||||
(t locale "ds.images-collection.new")]])
|
||||
|
||||
(for [item collections]
|
||||
[:& nav-item {:coll item
|
||||
:selected? (= (:id item) id)
|
||||
:key (:id item)}])]]]))
|
||||
|
||||
;; --- Grid
|
||||
|
||||
;; (mf/defc grid-options-tooltip
|
||||
;; [{:keys [selected on-select title] :as props}]
|
||||
;; {:pre [(uuid? selected)
|
||||
;; (fn? on-select)
|
||||
;; (string? title)]}
|
||||
;; (let [colls (mf/deref collections-iref)
|
||||
;; colls (->> (vals colls)
|
||||
;; (filter #(= :own (:type %)))
|
||||
;; (remove #(= selected (:id %)))
|
||||
;; #_(sort-by :name colls))
|
||||
;; on-select (fn [event id]
|
||||
;; (dom/prevent-default event)
|
||||
;; (dom/stop-propagation event)
|
||||
;; (on-select id))]
|
||||
;; [:ul.move-list
|
||||
;; [:li.title title]
|
||||
;; [:li
|
||||
;; (when (not (nil? selected))
|
||||
;; [:a {:href "#" :on-click #(on-select % nil)} "Storage"])]
|
||||
;; (for [{:keys [id name] :as coll} colls]
|
||||
;; [:li {:key (pr-str id)}
|
||||
;; [:a {:on-click #(on-select % id)} name]])]))
|
||||
|
||||
(mf/defc grid-options
|
||||
[{:keys [id type selected] :as props}]
|
||||
(let [local (mf/use-state {})
|
||||
delete #(st/emit! di/delete-selected)
|
||||
on-delete #(modal/show! confirm-dialog {:on-accept delete})
|
||||
|
||||
;; (on-toggle-copy [event]
|
||||
;; (swap! local update :show-copy-tooltip not))
|
||||
;; (on-toggle-move [event]
|
||||
;; (swap! local update :show-move-tooltip not))
|
||||
;; (on-copy [selected]
|
||||
;; (swap! local assoc
|
||||
;; :show-move-tooltip false
|
||||
;; :show-copy-tooltip false)
|
||||
;; (st/emit! (di/copy-selected selected)))
|
||||
;; (on-move [selected]
|
||||
;; (swap! local assoc
|
||||
;; :show-move-tooltip false
|
||||
;; :show-copy-tooltip false)
|
||||
;; (st/emit! (di/move-selected selected)))
|
||||
;; (on-rename [event]
|
||||
;; (let [selected (first selected)]
|
||||
;; (st/emit! (di/update-opts :edition selected))))
|
||||
]
|
||||
;; MULTISELECT OPTIONS BAR
|
||||
[:div.multiselect-bar
|
||||
(when (= type :own)
|
||||
;; If editable
|
||||
[:div.multiselect-nav
|
||||
;; [:span.move-item.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; :on-click on-toggle-copy}
|
||||
;; (when (:show-copy-tooltip @local)
|
||||
;; [:& grid-options-tooltip {:selected id
|
||||
;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; :on-select on-copy}])
|
||||
;; i/copy]
|
||||
;; [:span.move-item.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.move")
|
||||
;; :on-click on-toggle-move}
|
||||
;; (when (:show-move-tooltip @local)
|
||||
;; [:& grid-options-tooltip {:selected id
|
||||
;; :title (tr "ds.multiselect-bar.move-to-library")
|
||||
;; :on-select on-move}])
|
||||
;; i/move]
|
||||
;; (when (= 1 (count selected))
|
||||
;; [:span.move-item.tooltip.tooltip-top {:alt (tr "ds.multiselect-bar.rename")
|
||||
;; :on-click on-rename}
|
||||
;; i/pencil])
|
||||
[:span.delete.tooltip.tooltip-top
|
||||
{:alt (tr "ds.multiselect-bar.delete")
|
||||
:on-click on-delete}
|
||||
i/trash]]
|
||||
|
||||
;; If not editable
|
||||
;; [:div.multiselect-nav
|
||||
;; [:span.move-item.tooltip.tooltip-top {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; :on-click on-toggle-copy}
|
||||
;; (when (:show-copy-tooltip @local)
|
||||
;; [:& grid-options-tooltip {:selected id
|
||||
;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; :on-select on-copy}])
|
||||
;; i/organize]]
|
||||
)]))
|
||||
|
||||
|
||||
;; --- Grid Form
|
||||
|
||||
(mf/defc grid-form
|
||||
[{:keys [id type uploading?] :as props}]
|
||||
(let [input (mf/use-ref nil)
|
||||
on-click #(dom/click (mf/ref-node input))
|
||||
on-select #(st/emit! (->> (dom/get-target %)
|
||||
(dom/get-files)
|
||||
(array-seq)
|
||||
(di/create-images id)))]
|
||||
[:div.grid-item.add-project {:on-click on-click}
|
||||
(if uploading?
|
||||
[:div i/loader-pencil]
|
||||
[:span (tr "ds.image-new")])
|
||||
[:input.upload-image-input
|
||||
{:style {:display "none"}
|
||||
:multiple true
|
||||
:ref input
|
||||
:value ""
|
||||
:accept "image/jpeg,image/png,image/webp"
|
||||
:type "file"
|
||||
:on-change on-select}]]))
|
||||
|
||||
;; --- Grid Item
|
||||
|
||||
(mf/defc grid-item
|
||||
[{:keys [image selected? edition?] :as props}]
|
||||
(let [toggle-selection #(st/emit! (if selected?
|
||||
(di/deselect-image (:id image))
|
||||
(di/select-image (:id image))))
|
||||
on-blur
|
||||
(fn [event]
|
||||
(let [target (dom/get-target event)
|
||||
name (dom/get-value target)]
|
||||
(st/emit! (di/update-opts :edition false)
|
||||
(di/rename-image (:id image) name))))
|
||||
|
||||
on-key-down
|
||||
(fn [event]
|
||||
(when (kbd/enter? event)
|
||||
(on-blur event)))
|
||||
|
||||
on-edit
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
(dom/prevent-default event)
|
||||
(st/emit! (di/update-opts :edition (:id image))))
|
||||
|
||||
background (str "url('" (:thumb-uri image) "')")]
|
||||
|
||||
[:div.grid-item.images-th
|
||||
[:div.grid-item-th {:style {:background-image background}}
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id (:id image)
|
||||
:on-change toggle-selection
|
||||
:checked selected?}]
|
||||
[:label {:for (:id image)}]]]
|
||||
|
||||
[:div.item-info
|
||||
(if edition?
|
||||
[:input.element-name {:type "text"
|
||||
:auto-focus true
|
||||
:on-key-down on-key-down
|
||||
:on-blur on-blur
|
||||
:on-click on-edit
|
||||
:default-value (:name image)}]
|
||||
[:h3 {:on-double-click on-edit} (:name image)])
|
||||
[:span.date (tr "ds.uploaded-at" (dt/format (:created-at image) "dd/MM/yyyy"))]]]))
|
||||
|
||||
;; --- Grid
|
||||
|
||||
;; (defn- make-images-iref
|
||||
;; [collection-id]
|
||||
;; (letfn [(selector [state]
|
||||
;; (->> (vals (:images state))
|
||||
;; (filterv #(= (:collection-id %) collection-id))))]
|
||||
;; (-> (l/lens selector)
|
||||
;; (l/derive st/state))))
|
||||
|
||||
(def images-iref
|
||||
(-> (comp (l/key :images) (l/lens vals))
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc grid
|
||||
[{:keys [id type collection opts] :as props}]
|
||||
(let [editable? (= type :own)
|
||||
;; images-iref (mf/use-memo {:fn #(make-images-iref id)
|
||||
;; :deps (mf/deps id)})
|
||||
images (->> (mf/deref images-iref)
|
||||
(sort-by :created-at))]
|
||||
[:div.dashboard-grid-content
|
||||
[:div.dashboard-grid-row
|
||||
(when editable?
|
||||
[:& grid-form {:id id :type type :uploading? (:uploading opts)}])
|
||||
(for [item images]
|
||||
[:& grid-item {:image item
|
||||
:key (:id item)
|
||||
:selected? (contains? (:selected opts) (:id item))
|
||||
:edition? (= (:edition opts) (:id item))}])]]))
|
||||
|
||||
;; --- Menu
|
||||
|
||||
;; (mf/defc menu
|
||||
;; [{:keys [opts coll] :as props}]
|
||||
;; (let [ordering (:order opts :name)
|
||||
;; filtering (:filter opts "")
|
||||
;; icount (count (:images coll))]
|
||||
;; (letfn [(on-term-change [event]
|
||||
;; (let [term (-> (dom/get-target event)
|
||||
;; (dom/get-value))]
|
||||
;; (st/emit! (di/update-opts :filter term))))
|
||||
;; (on-ordering-change [event]
|
||||
;; (let [value (dom/event->value event)
|
||||
;; value (read-string value)]
|
||||
;; (st/emit! (di/update-opts :order value))))
|
||||
;; (on-clear [event]
|
||||
;; (st/emit! (di/update-opts :filter "")))]
|
||||
;; [:section.dashboard-bar.library-gap
|
||||
;; [:div.dashboard-info
|
||||
|
||||
;; ;; Counter
|
||||
;; [:span.dashboard-images (tr "ds.num-images" (t/c icount))]
|
||||
|
||||
;; ;; Sorting
|
||||
;; [:div
|
||||
;; [:span (tr "ds.ordering")]
|
||||
;; [:select.input-select {:on-change on-ordering-change
|
||||
;; :value (pr-str ordering)}
|
||||
;; (for [[key value] (seq +ordering-options+)]
|
||||
;; [:option {:key key :value (pr-str key)} (tr value)])]]
|
||||
|
||||
;; ;; Search
|
||||
;; [:form.dashboard-search
|
||||
;; [:input.input-text {:key :images-search-box
|
||||
;; :type "text"
|
||||
;; :on-change on-term-change
|
||||
;; :auto-focus true
|
||||
;; :placeholder (tr "ds.search.placeholder")
|
||||
;; :value filtering}]
|
||||
;; [:div.clear-search {:on-click on-clear} i/close]]]])))
|
||||
|
||||
(def opts-iref
|
||||
(-> (l/key :dashboard-images)
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc content
|
||||
[{:keys [id type collection] :as props}]
|
||||
(let [{:keys [selected] :as opts} (mf/deref opts-iref)]
|
||||
[:section.dashboard-grid.library
|
||||
(when collection
|
||||
[:& grid-header {:collection collection}])
|
||||
(if collection
|
||||
[:& grid {:id id :type type :collection collection :opts opts}]
|
||||
[:span "EMPTY STATE TODO"])
|
||||
(when-not (empty? selected)
|
||||
[:& grid-options {:id id :type type :selected selected}])]))
|
||||
|
||||
;; --- Images Page
|
||||
|
||||
(def collections-iref
|
||||
(-> (l/key :images-collections)
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc images-page
|
||||
[{:keys [id type] :as props}]
|
||||
(let [collections (mf/deref collections-iref)
|
||||
collections (cond->> (vals collections)
|
||||
(= type :own) (filter #(= :own (:type %)))
|
||||
(= type :builtin) (filter #(= :builtin (:type %)))
|
||||
true (sort-by :created-at))
|
||||
|
||||
collection (cond
|
||||
(uuid? id) (d/seek #(= id (:id %)) collections)
|
||||
:else (first collections))
|
||||
id (:id collection)]
|
||||
|
||||
(mf/use-effect #(st/emit! di/fetch-collections))
|
||||
(mf/use-effect
|
||||
{:fn #(when id (st/emit! (di/initialize id)))
|
||||
:deps (mf/deps id)})
|
||||
|
||||
[:section.dashboard-content
|
||||
[:& nav {:type type :id id :collections collections}]
|
||||
[:& content {:type type :id id :collection collection}]]))
|
||||
;; ;; --- Page Title
|
||||
;;
|
||||
;; (mf/defc grid-header
|
||||
;; [{:keys [collection] :as props}]
|
||||
;; (let [{:keys [id type]} collection
|
||||
;; on-change #(st/emit! (di/rename-collection id %))
|
||||
;; on-deleted #(st/emit! (rt/nav :dashboard-images nil {:type type}))
|
||||
;; delete #(st/emit! (di/delete-collection id on-deleted))
|
||||
;; on-delete #(modal/show! confirm-dialog {:on-accept delete})]
|
||||
;; [:& common/grid-header {:value (:name collection)
|
||||
;; :on-change on-change
|
||||
;; :on-delete on-delete}]))
|
||||
;;
|
||||
;; ;; --- Nav
|
||||
;;
|
||||
;; (mf/defc nav-item
|
||||
;; [{:keys [coll selected?] :as props}]
|
||||
;; (let [local (mf/use-state {})
|
||||
;; {:keys [id type name num-images]} coll
|
||||
;; editable? (= type :own)
|
||||
;;
|
||||
;; on-click
|
||||
;; (fn [event]
|
||||
;; (let [type (or type :own)]
|
||||
;; (st/emit! (rt/nav :dashboard-images {} {:type type :id id}))))
|
||||
;;
|
||||
;; on-cancel-edition #(swap! local dissoc :edit)
|
||||
;; on-double-click #(when editable? (swap! local assoc :edit true))
|
||||
;;
|
||||
;; on-input-keyup
|
||||
;; (fn [event]
|
||||
;; (when (kbd/enter? event)
|
||||
;; (let [value (-> (dom/get-target event)
|
||||
;; (dom/get-value)
|
||||
;; (str/trim))]
|
||||
;; (st/emit! (di/rename-collection id value))
|
||||
;; (swap! local assoc :edit false))))]
|
||||
;;
|
||||
;; [:li {:on-click on-click
|
||||
;; :on-double-click on-double-click
|
||||
;; :class-name (when selected? "current")}
|
||||
;; (if (:edit @local)
|
||||
;; [:div
|
||||
;; [:input.element-title {:default-value name
|
||||
;; :on-key-down on-input-keyup}]
|
||||
;; [:span.close {:on-click on-cancel-edition} i/close]]
|
||||
;; [:span.element-title (if id name "Storage")])]))
|
||||
;;
|
||||
;; (mf/defc nav
|
||||
;; [{:keys [id type collections] :as props}]
|
||||
;; (let [locale (i18n/use-locale)
|
||||
;; own? (= type :own)
|
||||
;; builtin? (= type :builtin)
|
||||
;; create-collection #(st/emit! di/create-collection)
|
||||
;; select-own-tab #(st/emit! (rt/nav :dashboard-images nil {:type :own}))
|
||||
;; select-buitin-tab #(st/emit! (rt/nav :dashboard-images nil {:type :builtin}))]
|
||||
;; [:div.library-bar
|
||||
;; [:div.library-bar-inside
|
||||
;;
|
||||
;; ;; Tabs
|
||||
;; [:ul.library-tabs
|
||||
;; [:li {:class (when own? "current")
|
||||
;; :on-click select-own-tab}
|
||||
;; (t locale "ds.your-images-title")]
|
||||
;;
|
||||
;; [:li {:class (when builtin? "current")
|
||||
;; :on-click select-buitin-tab}
|
||||
;; (t locale "ds.store-images-title")]]
|
||||
;;
|
||||
;; ;; Collections List
|
||||
;; [:ul.library-elements
|
||||
;; (when own?
|
||||
;; [:li
|
||||
;; [:a.btn-primary {:on-click create-collection}
|
||||
;; (t locale "ds.images-collection.new")]])
|
||||
;;
|
||||
;; (for [item collections]
|
||||
;; [:& nav-item {:coll item
|
||||
;; :selected? (= (:id item) id)
|
||||
;; :key (:id item)}])]]]))
|
||||
;;
|
||||
;; ;; --- Grid
|
||||
;;
|
||||
;; ;; (mf/defc grid-options-tooltip
|
||||
;; ;; [{:keys [selected on-select title] :as props}]
|
||||
;; ;; {:pre [(uuid? selected)
|
||||
;; ;; (fn? on-select)
|
||||
;; ;; (string? title)]}
|
||||
;; ;; (let [colls (mf/deref collections-iref)
|
||||
;; ;; colls (->> (vals colls)
|
||||
;; ;; (filter #(= :own (:type %)))
|
||||
;; ;; (remove #(= selected (:id %)))
|
||||
;; ;; #_(sort-by :name colls))
|
||||
;; ;; on-select (fn [event id]
|
||||
;; ;; (dom/prevent-default event)
|
||||
;; ;; (dom/stop-propagation event)
|
||||
;; ;; (on-select id))]
|
||||
;; ;; [:ul.move-list
|
||||
;; ;; [:li.title title]
|
||||
;; ;; [:li
|
||||
;; ;; (when (not (nil? selected))
|
||||
;; ;; [:a {:href "#" :on-click #(on-select % nil)} "Storage"])]
|
||||
;; ;; (for [{:keys [id name] :as coll} colls]
|
||||
;; ;; [:li {:key (pr-str id)}
|
||||
;; ;; [:a {:on-click #(on-select % id)} name]])]))
|
||||
;;
|
||||
;; (mf/defc grid-options
|
||||
;; [{:keys [id type selected] :as props}]
|
||||
;; (let [local (mf/use-state {})
|
||||
;; delete #(st/emit! di/delete-selected)
|
||||
;; on-delete #(modal/show! confirm-dialog {:on-accept delete})
|
||||
;;
|
||||
;; ;; (on-toggle-copy [event]
|
||||
;; ;; (swap! local update :show-copy-tooltip not))
|
||||
;; ;; (on-toggle-move [event]
|
||||
;; ;; (swap! local update :show-move-tooltip not))
|
||||
;; ;; (on-copy [selected]
|
||||
;; ;; (swap! local assoc
|
||||
;; ;; :show-move-tooltip false
|
||||
;; ;; :show-copy-tooltip false)
|
||||
;; ;; (st/emit! (di/copy-selected selected)))
|
||||
;; ;; (on-move [selected]
|
||||
;; ;; (swap! local assoc
|
||||
;; ;; :show-move-tooltip false
|
||||
;; ;; :show-copy-tooltip false)
|
||||
;; ;; (st/emit! (di/move-selected selected)))
|
||||
;; ;; (on-rename [event]
|
||||
;; ;; (let [selected (first selected)]
|
||||
;; ;; (st/emit! (di/update-opts :edition selected))))
|
||||
;; ]
|
||||
;; ;; MULTISELECT OPTIONS BAR
|
||||
;; [:div.multiselect-bar
|
||||
;; (when (= type :own)
|
||||
;; ;; If editable
|
||||
;; [:div.multiselect-nav
|
||||
;; ;; [:span.move-item.tooltip.tooltip-top
|
||||
;; ;; {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; ;; :on-click on-toggle-copy}
|
||||
;; ;; (when (:show-copy-tooltip @local)
|
||||
;; ;; [:& grid-options-tooltip {:selected id
|
||||
;; ;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; ;; :on-select on-copy}])
|
||||
;; ;; i/copy]
|
||||
;; ;; [:span.move-item.tooltip.tooltip-top
|
||||
;; ;; {:alt (tr "ds.multiselect-bar.move")
|
||||
;; ;; :on-click on-toggle-move}
|
||||
;; ;; (when (:show-move-tooltip @local)
|
||||
;; ;; [:& grid-options-tooltip {:selected id
|
||||
;; ;; :title (tr "ds.multiselect-bar.move-to-library")
|
||||
;; ;; :on-select on-move}])
|
||||
;; ;; i/move]
|
||||
;; ;; (when (= 1 (count selected))
|
||||
;; ;; [:span.move-item.tooltip.tooltip-top {:alt (tr "ds.multiselect-bar.rename")
|
||||
;; ;; :on-click on-rename}
|
||||
;; ;; i/pencil])
|
||||
;; [:span.delete.tooltip.tooltip-top
|
||||
;; {:alt (tr "ds.multiselect-bar.delete")
|
||||
;; :on-click on-delete}
|
||||
;; i/trash]]
|
||||
;;
|
||||
;; ;; If not editable
|
||||
;; ;; [:div.multiselect-nav
|
||||
;; ;; [:span.move-item.tooltip.tooltip-top {:alt (tr "ds.multiselect-bar.copy")
|
||||
;; ;; :on-click on-toggle-copy}
|
||||
;; ;; (when (:show-copy-tooltip @local)
|
||||
;; ;; [:& grid-options-tooltip {:selected id
|
||||
;; ;; :title (tr "ds.multiselect-bar.copy-to-library")
|
||||
;; ;; :on-select on-copy}])
|
||||
;; ;; i/organize]]
|
||||
;; )]))
|
||||
;;
|
||||
;;
|
||||
;; ;; --- Grid Form
|
||||
;;
|
||||
;; (mf/defc grid-form
|
||||
;; [{:keys [id type uploading?] :as props}]
|
||||
;; (let [input (mf/use-ref nil)
|
||||
;; on-click #(dom/click (mf/ref-node input))
|
||||
;; on-select #(st/emit! (->> (dom/get-target %)
|
||||
;; (dom/get-files)
|
||||
;; (array-seq)
|
||||
;; (di/create-images id)))]
|
||||
;; [:div.grid-item.add-project {:on-click on-click}
|
||||
;; (if uploading?
|
||||
;; [:div i/loader-pencil]
|
||||
;; [:span (tr "ds.image-new")])
|
||||
;; [:input.upload-image-input
|
||||
;; {:style {:display "none"}
|
||||
;; :multiple true
|
||||
;; :ref input
|
||||
;; :value ""
|
||||
;; :accept "image/jpeg,image/png,image/webp"
|
||||
;; :type "file"
|
||||
;; :on-change on-select}]]))
|
||||
;;
|
||||
;; ;; --- Grid Item
|
||||
;;
|
||||
;; (mf/defc grid-item
|
||||
;; [{:keys [image selected? edition?] :as props}]
|
||||
;; (let [toggle-selection #(st/emit! (if selected?
|
||||
;; (di/deselect-image (:id image))
|
||||
;; (di/select-image (:id image))))
|
||||
;; on-blur
|
||||
;; (fn [event]
|
||||
;; (let [target (dom/get-target event)
|
||||
;; name (dom/get-value target)]
|
||||
;; (st/emit! (di/update-opts :edition false)
|
||||
;; (di/rename-image (:id image) name))))
|
||||
;;
|
||||
;; on-key-down
|
||||
;; (fn [event]
|
||||
;; (when (kbd/enter? event)
|
||||
;; (on-blur event)))
|
||||
;;
|
||||
;; on-edit
|
||||
;; (fn [event]
|
||||
;; (dom/stop-propagation event)
|
||||
;; (dom/prevent-default event)
|
||||
;; (st/emit! (di/update-opts :edition (:id image))))
|
||||
;;
|
||||
;; background (str "url('" (:thumb-uri image) "')")]
|
||||
;;
|
||||
;; [:div.grid-item.images-th
|
||||
;; [:div.grid-item-th {:style {:background-image background}}
|
||||
;; [:div.input-checkbox.check-primary
|
||||
;; [:input {:type "checkbox"
|
||||
;; :id (:id image)
|
||||
;; :on-change toggle-selection
|
||||
;; :checked selected?}]
|
||||
;; [:label {:for (:id image)}]]]
|
||||
;;
|
||||
;; [:div.item-info
|
||||
;; (if edition?
|
||||
;; [:input.element-name {:type "text"
|
||||
;; :auto-focus true
|
||||
;; :on-key-down on-key-down
|
||||
;; :on-blur on-blur
|
||||
;; :on-click on-edit
|
||||
;; :default-value (:name image)}]
|
||||
;; [:h3 {:on-double-click on-edit} (:name image)])
|
||||
;; [:span.date (tr "ds.uploaded-at" (dt/format (:created-at image) "dd/MM/yyyy"))]]]))
|
||||
;;
|
||||
;; ;; --- Grid
|
||||
;;
|
||||
;; ;; (defn- make-images-iref
|
||||
;; ;; [collection-id]
|
||||
;; ;; (letfn [(selector [state]
|
||||
;; ;; (->> (vals (:images state))
|
||||
;; ;; (filterv #(= (:collection-id %) collection-id))))]
|
||||
;; ;; (-> (l/lens selector)
|
||||
;; ;; (l/derive st/state))))
|
||||
;;
|
||||
;; (def images-iref
|
||||
;; (-> (comp (l/key :images) (l/lens vals))
|
||||
;; (l/derive st/state)))
|
||||
;;
|
||||
;; (mf/defc grid
|
||||
;; [{:keys [id type collection opts] :as props}]
|
||||
;; (let [editable? (= type :own)
|
||||
;; ;; images-iref (mf/use-memo {:fn #(make-images-iref id)
|
||||
;; ;; :deps (mf/deps id)})
|
||||
;; images (->> (mf/deref images-iref)
|
||||
;; (sort-by :created-at))]
|
||||
;; [:div.dashboard-grid-content
|
||||
;; [:div.dashboard-grid-row
|
||||
;; (when editable?
|
||||
;; [:& grid-form {:id id :type type :uploading? (:uploading opts)}])
|
||||
;; (for [item images]
|
||||
;; [:& grid-item {:image item
|
||||
;; :key (:id item)
|
||||
;; :selected? (contains? (:selected opts) (:id item))
|
||||
;; :edition? (= (:edition opts) (:id item))}])]]))
|
||||
;;
|
||||
;; ;; --- Menu
|
||||
;;
|
||||
;; ;; (mf/defc menu
|
||||
;; ;; [{:keys [opts coll] :as props}]
|
||||
;; ;; (let [ordering (:order opts :name)
|
||||
;; ;; filtering (:filter opts "")
|
||||
;; ;; icount (count (:images coll))]
|
||||
;; ;; (letfn [(on-term-change [event]
|
||||
;; ;; (let [term (-> (dom/get-target event)
|
||||
;; ;; (dom/get-value))]
|
||||
;; ;; (st/emit! (di/update-opts :filter term))))
|
||||
;; ;; (on-ordering-change [event]
|
||||
;; ;; (let [value (dom/event->value event)
|
||||
;; ;; value (read-string value)]
|
||||
;; ;; (st/emit! (di/update-opts :order value))))
|
||||
;; ;; (on-clear [event]
|
||||
;; ;; (st/emit! (di/update-opts :filter "")))]
|
||||
;; ;; [:section.dashboard-bar.library-gap
|
||||
;; ;; [:div.dashboard-info
|
||||
;;
|
||||
;; ;; ;; Counter
|
||||
;; ;; [:span.dashboard-images (tr "ds.num-images" (t/c icount))]
|
||||
;;
|
||||
;; ;; ;; Sorting
|
||||
;; ;; [:div
|
||||
;; ;; [:span (tr "ds.ordering")]
|
||||
;; ;; [:select.input-select {:on-change on-ordering-change
|
||||
;; ;; :value (pr-str ordering)}
|
||||
;; ;; (for [[key value] (seq +ordering-options+)]
|
||||
;; ;; [:option {:key key :value (pr-str key)} (tr value)])]]
|
||||
;;
|
||||
;; ;; ;; Search
|
||||
;; ;; [:form.dashboard-search
|
||||
;; ;; [:input.input-text {:key :images-search-box
|
||||
;; ;; :type "text"
|
||||
;; ;; :on-change on-term-change
|
||||
;; ;; :auto-focus true
|
||||
;; ;; :placeholder (tr "ds.search.placeholder")
|
||||
;; ;; :value filtering}]
|
||||
;; ;; [:div.clear-search {:on-click on-clear} i/close]]]])))
|
||||
;;
|
||||
;; (def opts-iref
|
||||
;; (-> (l/key :dashboard-images)
|
||||
;; (l/derive st/state)))
|
||||
;;
|
||||
;; (mf/defc content
|
||||
;; [{:keys [id type collection] :as props}]
|
||||
;; (let [{:keys [selected] :as opts} (mf/deref opts-iref)]
|
||||
;; [:section.dashboard-grid.library
|
||||
;; (when collection
|
||||
;; [:& grid-header {:collection collection}])
|
||||
;; (if collection
|
||||
;; [:& grid {:id id :type type :collection collection :opts opts}]
|
||||
;; [:span "EMPTY STATE TODO"])
|
||||
;; (when-not (empty? selected)
|
||||
;; [:& grid-options {:id id :type type :selected selected}])]))
|
||||
;;
|
||||
;; ;; --- Images Page
|
||||
;;
|
||||
;; (def collections-iref
|
||||
;; (-> (l/key :images-collections)
|
||||
;; (l/derive st/state)))
|
||||
;;
|
||||
;; (mf/defc images-page
|
||||
;; [{:keys [id type] :as props}]
|
||||
;; (let [collections (mf/deref collections-iref)
|
||||
;; collections (cond->> (vals collections)
|
||||
;; (= type :own) (filter #(= :own (:type %)))
|
||||
;; (= type :builtin) (filter #(= :builtin (:type %)))
|
||||
;; true (sort-by :created-at))
|
||||
;;
|
||||
;; collection (cond
|
||||
;; (uuid? id) (d/seek #(= id (:id %)) collections)
|
||||
;; :else (first collections))
|
||||
;; id (:id collection)]
|
||||
;;
|
||||
;; (mf/use-effect #(st/emit! di/fetch-collections))
|
||||
;; (mf/use-effect
|
||||
;; {:fn #(when id (st/emit! (di/initialize id)))
|
||||
;; :deps (mf/deps id)})
|
||||
;;
|
||||
;; [:section.dashboard-content
|
||||
;; [:& nav {:type type :id id :collections collections}]
|
||||
;; [:& content {:type type :id id :collection collection}]]))
|
||||
|
||||
293
frontend/src/uxbox/main/ui/dashboard/library.cljs
Normal file
293
frontend/src/uxbox/main/ui/dashboard/library.cljs
Normal file
@ -0,0 +1,293 @@
|
||||
;; 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) 2015-2020 Andrey Antukh <niwi@niwi.nz>
|
||||
;; Copyright (c) 2015-2020 Juan de la Cruz <delacruzgarciajuan@gmail.com>
|
||||
|
||||
(ns uxbox.main.ui.dashboard.library
|
||||
(:require
|
||||
[lentes.core :as l]
|
||||
[rumext.alpha :as mf]
|
||||
[cuerdas.core :as str]
|
||||
[uxbox.util.router :as rt]
|
||||
[uxbox.util.i18n :as i18n :refer [t tr]]
|
||||
[uxbox.util.color :as uc]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.main.data.icons :as dico]
|
||||
[uxbox.main.data.images :as dimg]
|
||||
[uxbox.main.data.colors :as dcol]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.ui.components.context-menu :refer [context-menu]]
|
||||
[uxbox.main.ui.modal :as modal]
|
||||
[uxbox.main.ui.confirm :refer [confirm-dialog]]
|
||||
[uxbox.main.ui.colorpicker :refer [colorpicker most-used-colors]]
|
||||
))
|
||||
|
||||
(mf/defc modal-create-color
|
||||
[{:keys [on-accept on-cancel] :as ctx}]
|
||||
(let [state (mf/use-state { :current-color "#406280" })]
|
||||
(letfn [(accept [event]
|
||||
(dom/prevent-default event)
|
||||
(modal/hide!)
|
||||
(when on-accept (on-accept (:current-color @state))))
|
||||
|
||||
(cancel [event]
|
||||
(dom/prevent-default event)
|
||||
(modal/hide!)
|
||||
(when on-cancel (on-cancel)))]
|
||||
[:div.modal-create-color
|
||||
[:h3.modal-create-color-title (tr "modal.create-color.new-color")]
|
||||
[:& colorpicker {:value (:current-color @state)
|
||||
:colors (into-array @most-used-colors)
|
||||
:on-change #(swap! state assoc :current-color %)}]
|
||||
|
||||
[:input.btn-primary {:type "button"
|
||||
:value (tr "ds.button.save")
|
||||
:on-click accept}]
|
||||
|
||||
[:a.close {:href "#" :on-click cancel} i/close]])))
|
||||
|
||||
|
||||
(defmulti create-library (fn [x _] x))
|
||||
(defmethod create-library :icons [_ team-id]
|
||||
(let [name (str "Icon Library "(gensym "l"))]
|
||||
(st/emit! (dico/create-icon-library team-id name))))
|
||||
|
||||
(defmethod create-library :images [_ team-id]
|
||||
(let [name (str "Image Library "(gensym "l"))]
|
||||
(st/emit! (dimg/create-image-library team-id name))))
|
||||
|
||||
(defmethod create-library :palettes [_ team-id]
|
||||
(let [name (str "Image Library "(gensym "l"))]
|
||||
(st/emit! (dcol/create-color-library team-id name))))
|
||||
|
||||
(defmulti create-item (fn [x _ _] x))
|
||||
|
||||
(defmethod create-item :icons [_ library-id data]
|
||||
(let [files (->> data
|
||||
(dom/get-target)
|
||||
(dom/get-files)
|
||||
(array-seq))]
|
||||
(st/emit! (dico/create-icons library-id files))))
|
||||
|
||||
(defmethod create-item :images [_ library-id data]
|
||||
(let [files (->> data
|
||||
(dom/get-target)
|
||||
(dom/get-files)
|
||||
(array-seq))]
|
||||
(st/emit! (dimg/create-images library-id files))))
|
||||
|
||||
(defmethod create-item :palettes [_ library-id]
|
||||
(letfn [(dispatch-color [color]
|
||||
(st/emit! (dcol/create-color library-id color)))]
|
||||
(modal/show! modal-create-color {:on-accept dispatch-color})))
|
||||
|
||||
(mf/defc library-header
|
||||
[{:keys [section team-id] :as props}]
|
||||
(let [icons? (= section :icons)
|
||||
images? (= section :images)
|
||||
palettes? (= section :palettes)
|
||||
locale (i18n/use-locale)]
|
||||
[:header#main-bar.main-bar
|
||||
[:h1.dashboard-title "Libraries"]
|
||||
[:nav.library-header-navigation
|
||||
[:a.library-header-navigation-item
|
||||
{:class-name (when icons? "current")
|
||||
:on-click #(st/emit! (rt/nav :dashboard-library-icons-index {:team-id team-id}))}
|
||||
(t locale "dashboard.library.menu.icons")]
|
||||
[:a.library-header-navigation-item
|
||||
{:class-name (when images? "current")
|
||||
:on-click #(st/emit! (rt/nav :dashboard-library-images-index {:team-id team-id}))}
|
||||
(t locale "dashboard.library.menu.images")]
|
||||
[:a.library-header-navigation-item
|
||||
{:class-name (when palettes? "current")
|
||||
:on-click #(st/emit! (rt/nav :dashboard-library-palettes-index {:team-id team-id}))}
|
||||
(t locale "dashboard.library.menu.palettes")]]]))
|
||||
|
||||
(mf/defc library-sidebar
|
||||
[{:keys [section items team-id library-id]}]
|
||||
(let [locale (i18n/use-locale)]
|
||||
[:aside.library-sidebar
|
||||
[:button.library-sidebar-add-item
|
||||
{:type "button"
|
||||
:on-click #(create-library section team-id)}
|
||||
(t locale (str "dashboard.library.add-library." (name section)))]
|
||||
[:ul.library-sidebar-list
|
||||
(for [item items]
|
||||
[:li.library-sidebar-list-element
|
||||
{:key (:id item)
|
||||
:class-name (when (= library-id (:id item)) "current")
|
||||
:on-click
|
||||
(fn []
|
||||
(let [path (keyword (str "dashboard-library-" (name section)))]
|
||||
(dico/fetch-icon-library (:id item))
|
||||
(st/emit! (rt/nav path {:team-id team-id :library-id (:id item)}))))}
|
||||
[:a (:name item)]])]]))
|
||||
|
||||
(mf/defc library-top-menu
|
||||
[{:keys [selected section library-id]}]
|
||||
(let [state (mf/use-state {:is-open false})
|
||||
locale (i18n/use-locale)]
|
||||
[:header.library-top-menu
|
||||
[:div.library-top-menu-current-element
|
||||
[:h2.library-top-menu-current-element-name (:name selected)]
|
||||
[:a.library-top-menu-current-action
|
||||
{ :on-click #(swap! state update :is-open not)}
|
||||
[:span i/arrow-down]]
|
||||
[:& context-menu
|
||||
{:show (:is-open @state)
|
||||
:on-close #(swap! state update :is-open not)
|
||||
:options [[(t locale "ds.button.rename") #(println "Rename")]
|
||||
[(t locale "ds.button.delete") #(println "Delete")]]}]]
|
||||
|
||||
[:div.library-top-menu-actions
|
||||
[:a i/trash]
|
||||
|
||||
(if (= section :palettes)
|
||||
[:button.btn-dashboard
|
||||
{:on-click #(create-item section library-id)}
|
||||
(t locale (str "dashboard.library.add-item." (name section)))]
|
||||
|
||||
[:*
|
||||
[:label {:for "file-upload" :class-name "btn-dashboard"}
|
||||
(t locale (str "dashboard.library.add-item." (name section)))]
|
||||
[:input {:on-change #(create-item section library-id %)
|
||||
:id "file-upload" :type "file" :style {:display "none"}}]]
|
||||
|
||||
)]]))
|
||||
|
||||
(mf/defc library-icon-card
|
||||
[{:keys [id name url content metadata]}]
|
||||
(let [locale (i18n/use-locale)
|
||||
state (mf/use-state {:is-open false})]
|
||||
[:div.library-card.library-icon
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id (str "icon-" id)
|
||||
:on-change #(println "toggle-selection")
|
||||
#_(:checked false)}]
|
||||
[:label {:for (str "icon-" id)}]]
|
||||
[:div.library-card-image
|
||||
#_[:object { :data url :type "image/svg+xml" }]
|
||||
[:svg {:view-box (->> metadata :view-box (str/join " "))
|
||||
:width (:width metadata)
|
||||
:height (:height metadata)
|
||||
:dangerouslySetInnerHTML {:__html content}}]]
|
||||
|
||||
[:div.library-card-footer
|
||||
[:div.library-card-footer-name name]
|
||||
[:div.library-card-footer-timestamp "Less than 5 seconds ago"]
|
||||
[:div.library-card-footer-menu
|
||||
{ :on-click #(swap! state update :is-open not) }
|
||||
i/actions]
|
||||
[:& context-menu
|
||||
{:show (:is-open @state)
|
||||
:on-close #(swap! state update :is-open not)
|
||||
:options [[(t locale "ds.button.delete") #(println "Delete")]]}]]]))
|
||||
|
||||
(mf/defc library-image-card
|
||||
[{:keys [id name thumb-uri]}]
|
||||
(let [locale (i18n/use-locale)
|
||||
state (mf/use-state {:is-open false})]
|
||||
[:div.library-card.library-image
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id (str "image-" id)
|
||||
:on-change #(println "toggle-selection")
|
||||
#_(:checked false)}]
|
||||
[:label {:for (str "image-" id)}]]
|
||||
[:div.library-card-image
|
||||
[:img {:src thumb-uri}]]
|
||||
[:div.library-card-footer
|
||||
[:div.library-card-footer-name name]
|
||||
[:div.library-card-footer-timestamp "Less than 5 seconds ago"]
|
||||
[:div.library-card-footer-menu
|
||||
{ :on-click #(swap! state update :is-open not) }
|
||||
i/actions]
|
||||
[:& context-menu
|
||||
{:show (:is-open @state)
|
||||
:on-close #(swap! state update :is-open not)
|
||||
:options [[(t locale "ds.button.delete") #(println "Delete")]]}]]]))
|
||||
|
||||
(mf/defc library-color-card
|
||||
[{ :keys [ id content ] }]
|
||||
(when content
|
||||
(let [locale (i18n/use-locale)
|
||||
state (mf/use-state {:is-open false})]
|
||||
[:div.library-card.library-color
|
||||
[:div.input-checkbox.check-primary
|
||||
[:input {:type "checkbox"
|
||||
:id (str "color-" id)
|
||||
:on-change #(println "toggle-selection")
|
||||
#_(:checked false)}]
|
||||
[:label {:for (str "color-" id)}]]
|
||||
[:div.library-card-image
|
||||
{ :style { :background-color content }}]
|
||||
[:div.library-card-footer
|
||||
[:div.library-card-footer-name content ]
|
||||
[:div.library-card-footer-color
|
||||
[:span.library-card-footer-color-label "RGB"]
|
||||
[:span.library-card-footer-color-rgb (str/join " " (uc/hex->rgb content))]]
|
||||
[:div.library-card-footer-menu
|
||||
{ :on-click #(swap! state update :is-open not) }
|
||||
i/actions]
|
||||
[:& context-menu
|
||||
{:show (:is-open @state)
|
||||
:on-close #(swap! state update :is-open not)
|
||||
:options [[(t locale "ds.button.delete") #(println "Delete")]]}]]])))
|
||||
|
||||
(def icon-libraries-ref
|
||||
(-> (comp (l/key :library) (l/key :icon-libraries))
|
||||
(l/derive st/state)))
|
||||
|
||||
(def image-libraries-ref
|
||||
(-> (comp (l/key :library) (l/key :image-libraries))
|
||||
(l/derive st/state)))
|
||||
|
||||
(def color-libraries-ref
|
||||
(-> (comp (l/key :library) (l/key :color-libraries))
|
||||
(l/derive st/state)))
|
||||
|
||||
(def selected-items-ref
|
||||
(-> (comp (l/key :library) (l/key :selected-items))
|
||||
(l/derive st/state)))
|
||||
|
||||
(mf/defc library-page
|
||||
[{:keys [team-id library-id section]}]
|
||||
(mf/use-effect {:fn #(case section
|
||||
:icons (st/emit! (dico/fetch-icon-libraries team-id))
|
||||
:images (st/emit! (dimg/fetch-image-libraries team-id))
|
||||
:palettes (st/emit! (dcol/fetch-color-libraries team-id)))
|
||||
:deps (mf/deps section team-id)})
|
||||
(mf/use-effect {:fn #(when library-id
|
||||
(case section
|
||||
:icons (st/emit! (dico/fetch-icon-library library-id))
|
||||
:images (st/emit! (dimg/fetch-image-library library-id))
|
||||
:palettes (st/emit! (dcol/fetch-color-library library-id))))
|
||||
:deps (mf/deps library-id)})
|
||||
(let [libraries (case section
|
||||
:icons (mf/deref icon-libraries-ref)
|
||||
:images (mf/deref image-libraries-ref)
|
||||
:palettes (mf/deref color-libraries-ref))
|
||||
items (mf/deref selected-items-ref)
|
||||
selected-library (first (filter #(= (:id %) library-id) libraries))]
|
||||
[:div.library-page
|
||||
[:& library-header {:section section :team-id team-id}]
|
||||
[:& library-sidebar {:items libraries :team-id team-id :library-id library-id :section section}]
|
||||
|
||||
(when library-id
|
||||
[:section.library-content
|
||||
[:& library-top-menu {:selected selected-library :section section :library-id library-id}]
|
||||
[:div.library-page-cards-container
|
||||
(for [item items]
|
||||
(let [item (assoc item :key (:id item))]
|
||||
(case section
|
||||
:icons [:& library-icon-card item]
|
||||
:images [:& library-image-card item]
|
||||
:palettes [:& library-color-card item ])))]])]))
|
||||
@ -39,7 +39,14 @@
|
||||
(-> (l/key :recent-files)
|
||||
(l/derive st/state)))
|
||||
|
||||
;; --- Component: Drafts Page
|
||||
;; --- Component: Recent files
|
||||
|
||||
(mf/defc recent-files-header
|
||||
[{:keys [profile] :as props}]
|
||||
(let [locale (i18n/use-locale)]
|
||||
[:header#main-bar.main-bar
|
||||
[:h1.dashboard-title "Recent"]
|
||||
[:a.btn-dashboard "+ New project"]]))
|
||||
|
||||
(mf/defc recent-project
|
||||
[{:keys [project files first? locale] :as props}]
|
||||
@ -70,11 +77,13 @@
|
||||
recent-files (mf/deref recent-files-ref)
|
||||
locale (i18n/use-locale)]
|
||||
(when (and projects recent-files)
|
||||
[:section.recent-files-page
|
||||
(for [project projects]
|
||||
[:& recent-project {:project project
|
||||
:locale locale
|
||||
:key (:id project)
|
||||
:files (get recent-files (:id project))
|
||||
:first? (= project (first projects))}])])))
|
||||
[:*
|
||||
[:& recent-files-header]
|
||||
[:section.recent-files-page
|
||||
(for [project projects]
|
||||
[:& recent-project {:project project
|
||||
:locale locale
|
||||
:key (:id project)
|
||||
:files (get recent-files (:id project))
|
||||
:first? (= project (first projects))}])]])))
|
||||
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.main.ui.confirm :refer [confirm-dialog]]
|
||||
[uxbox.main.ui.dashboard.common :as common]
|
||||
[uxbox.main.ui.dashboard.header :refer [header]]
|
||||
[uxbox.main.ui.messages :refer [messages-widget]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.i18n :as i18n :refer [t tr]]
|
||||
@ -96,6 +95,8 @@
|
||||
drafts? (and (= selected-section :dashboard-project)
|
||||
(= selected-team-id (:default-team-id profile))
|
||||
(= selected-project-id (:default-project-id profile)))
|
||||
library? (and (str/starts-with? (name selected-section) "dashboard-library")
|
||||
(= selected-team-id (:default-team-id profile)))
|
||||
locale (i18n/use-locale)]
|
||||
[:ul.library-elements
|
||||
[:li.recent-projects
|
||||
@ -113,6 +114,8 @@
|
||||
|
||||
|
||||
[:li
|
||||
{:on-click #(st/emit! (rt/nav :dashboard-library-icons-index {:team-id team-id}))
|
||||
:class-name (when library? "current")}
|
||||
i/icon-set
|
||||
[:span.element-title (t locale "dashboard.sidebar.libraries")]]
|
||||
|
||||
|
||||
@ -125,5 +125,5 @@
|
||||
(mf/defc colorpalette
|
||||
[props]
|
||||
(let [colls (mf/deref collections-iref)]
|
||||
(mf/use-effect #(st/emit! (udc/fetch-collections)))
|
||||
#_(mf/use-effect #(st/emit! (udc/fetch-collections)))
|
||||
[:& palette {:colls (vals colls)}]))
|
||||
|
||||
@ -160,8 +160,8 @@
|
||||
(d/read-string)
|
||||
(swap! local assoc :collection-id))]
|
||||
|
||||
(mf/use-effect #(st/emit! udi/fetch-collections))
|
||||
(mf/use-effect
|
||||
#_(mf/use-effect #(st/emit! udi/fetch-collections))
|
||||
#_(mf/use-effect
|
||||
{:deps (mf/deps collection-id)
|
||||
:fn #(when collection-id
|
||||
(st/emit! (udi/fetch-images collection-id)))})
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.dashboard.icons :as icons]
|
||||
#_[uxbox.main.ui.dashboard.icons :as icons]
|
||||
[uxbox.main.ui.shapes.icon :as icon]
|
||||
[uxbox.util.data :refer [read-string]]
|
||||
[uxbox.util.dom :as dom]
|
||||
@ -40,13 +40,13 @@
|
||||
|
||||
(mf/defc icons-list
|
||||
[{:keys [collection-id] :as props}]
|
||||
(let [icons (mf/deref icons/icons-iref)
|
||||
(let [icons [] #_(mf/deref icons/icons-iref) ;; TODO: Fix this
|
||||
|
||||
on-select
|
||||
(fn [event data]
|
||||
(st/emit! (dw/select-for-drawing :icon data)))]
|
||||
|
||||
(mf/use-effect
|
||||
#_(mf/use-effect
|
||||
{:fn #(st/emit! (di/fetch-icons collection-id))
|
||||
:deps (mf/deps collection-id)})
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
|
||||
local (mf/deref refs/workspace-local)
|
||||
|
||||
collections (vals (mf/deref icons/collections-iref))
|
||||
collections (vals [] #_(mf/deref icons/collections-iref)) ;; TODO: FIX THIS
|
||||
collection (first collections)
|
||||
|
||||
on-close
|
||||
@ -79,7 +79,7 @@
|
||||
(st/emit! (dw/select-for-drawing nil))
|
||||
(reset! selected val))]
|
||||
|
||||
(mf/use-effect
|
||||
#_(mf/use-effect
|
||||
{:fn #(st/emit! di/fetch-collections)})
|
||||
|
||||
[:div#form-figures.tool-window
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user