mirror of
https://github.com/penpot/penpot.git
synced 2026-08-31 17:19:11 +00:00
Merge pull request #144 from uxbox/130/icons_library
Adds CRUD for libraries and deletion of elements
This commit is contained in:
commit
74c8107a92
@ -66,6 +66,7 @@
|
|||||||
@import 'main/partials/loader';
|
@import 'main/partials/loader';
|
||||||
@import 'main/partials/context-menu';
|
@import 'main/partials/context-menu';
|
||||||
@import 'main/partials/debug-icons-preview';
|
@import 'main/partials/debug-icons-preview';
|
||||||
|
@import 'main/partials/editable-label';
|
||||||
|
|
||||||
//#################################################
|
//#################################################
|
||||||
// Resources
|
// Resources
|
||||||
|
|||||||
@ -20,6 +20,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.library-content-empty {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-content-empty-text {
|
||||||
|
color: #7C7C7C;
|
||||||
|
border: 1px dashed #AFB2BF;
|
||||||
|
text-align: center;
|
||||||
|
padding: 5rem;
|
||||||
|
margin: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.library-page #main-bar {
|
.library-page #main-bar {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@ -79,16 +92,13 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
color: $color-black;
|
||||||
& a {
|
|
||||||
color: $color-black;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $color-primary-lighter;
|
background-color: $color-primary-lighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.current a {
|
&.current {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,6 +155,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.library-top-menu-actions-delete {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column
|
||||||
|
}
|
||||||
|
|
||||||
.library-page-cards-container {
|
.library-page-cards-container {
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -335,3 +351,4 @@
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
frontend/resources/styles/main/partials/editable-label.scss
Normal file
30
frontend/resources/styles/main/partials/editable-label.scss
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
.editable-label {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&.is-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-label-input {
|
||||||
|
border: 0;
|
||||||
|
height: 30px;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: $color-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editable-label-close {
|
||||||
|
background-color: $color-white;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 3px 5px;
|
||||||
|
|
||||||
|
& svg {
|
||||||
|
fill: $color-gray;
|
||||||
|
height: 15px;
|
||||||
|
transform: rotate(45deg) translateY(7px);
|
||||||
|
width: 15px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -222,13 +222,62 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirm dialog
|
.lightbox .confirm-dialog {
|
||||||
.confirm-dialog {
|
background-color: $color-white;
|
||||||
.btn-gray,
|
width: 23rem;
|
||||||
.btn-success,
|
|
||||||
.btn-delete {
|
& .close {
|
||||||
margin: 2rem 1rem 0 1rem;
|
right: 1rem;
|
||||||
}
|
top: 1rem;
|
||||||
|
|
||||||
|
& svg {
|
||||||
|
fill: $color-black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightbox .confirm-dialog-title {
|
||||||
|
font-size: 24px;
|
||||||
|
color: $color-black;
|
||||||
|
font-weight: normal;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-top: 5rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog-cancel-button {
|
||||||
|
border: 1px solid $color-gray;
|
||||||
|
background: $color-gray-lightest;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 0.5rem;
|
||||||
|
margin-right: 1rem;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
margin-bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $color-gray-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-dialog-accept-button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid $color-danger;
|
||||||
|
background: $color-danger;
|
||||||
|
color: $color-white;
|
||||||
|
margin-bottom: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $color-danger-dark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export dialog
|
// Export dialog
|
||||||
|
|||||||
@ -246,66 +246,6 @@
|
|||||||
|
|
||||||
|
|
||||||
;;;; NEW
|
;;;; NEW
|
||||||
|
|
||||||
(declare fetch-color-libraries-result)
|
|
||||||
|
|
||||||
(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
|
|
||||||
(assoc-in [:library :color-libraries] result)))))
|
|
||||||
|
|
||||||
(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]
|
|
||||||
(ptk/reify ::fetch-color-library
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(-> state
|
|
||||||
(assoc-in [:library :selected-items] data)))))
|
|
||||||
|
|
||||||
(declare create-color-library-result)
|
|
||||||
|
|
||||||
(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)))))
|
|
||||||
|
|
||||||
(defn create-color-library-result [result]
|
|
||||||
(ptk/reify ::create-color-library-result
|
|
||||||
ptk/UpdateEvent
|
|
||||||
(update [_ state]
|
|
||||||
(-> state
|
|
||||||
(update-in [:library :color-libraries] #(into [result] %))))))
|
|
||||||
|
|
||||||
(declare create-color-result)
|
(declare create-color-result)
|
||||||
|
|
||||||
(defn create-color
|
(defn create-color
|
||||||
@ -318,12 +258,12 @@
|
|||||||
(->> (rp/mutation! :create-color {:library-id library-id
|
(->> (rp/mutation! :create-color {:library-id library-id
|
||||||
:content color
|
:content color
|
||||||
:name color})
|
:name color})
|
||||||
(rx/map create-color-result)))))
|
(rx/map (partial create-color-result library-id))))))
|
||||||
|
|
||||||
(defn create-color-result
|
(defn create-color-result
|
||||||
[item]
|
[library-id item]
|
||||||
(ptk/reify ::create-color-result
|
(ptk/reify ::create-color-result
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(-> state
|
(-> state
|
||||||
(update-in [:library :selected-items] #(into [item] %) )))))
|
(update-in [:library :selected-items library-id] #(into [item] %) )))))
|
||||||
|
|||||||
@ -34,67 +34,8 @@
|
|||||||
::modified-at
|
::modified-at
|
||||||
::user-id]))
|
::user-id]))
|
||||||
|
|
||||||
|
;; rename-icon-library
|
||||||
(declare fetch-icon-libraries-result)
|
;; delete-icon-library
|
||||||
|
|
||||||
(defn fetch-icon-libraries
|
|
||||||
[team-id]
|
|
||||||
(s/assert ::us/uuid team-id)
|
|
||||||
(ptk/reify ::fetch-icon-libraries
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(->> (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)
|
;; (declare fetch-icons)
|
||||||
;;
|
;;
|
||||||
@ -253,16 +194,16 @@
|
|||||||
(rx/merge-map parse)
|
(rx/merge-map parse)
|
||||||
(rx/map prepare)
|
(rx/map prepare)
|
||||||
(rx/flat-map #(rp/mutation! :create-icon %))
|
(rx/flat-map #(rp/mutation! :create-icon %))
|
||||||
(rx/map create-icon-result))))))
|
(rx/map (partial create-icon-result library-id)))))))
|
||||||
|
|
||||||
(defn create-icon-result
|
(defn create-icon-result
|
||||||
[item]
|
[library-id item]
|
||||||
(ptk/reify ::create-icon-result
|
(ptk/reify ::create-icon-result
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [{:keys [id] :as item} (assoc item :type :icon)]
|
(let [{:keys [id] :as item} (assoc item :type :icon)]
|
||||||
(-> state
|
(-> state
|
||||||
(update-in [:library :selected-items] #(into [item] %)))))))
|
(update-in [:library :selected-items library-id] #(into [item] %)))))))
|
||||||
|
|
||||||
;; ;; --- Icon Persisted
|
;; ;; --- Icon Persisted
|
||||||
;;
|
;;
|
||||||
|
|||||||
@ -350,67 +350,6 @@
|
|||||||
|
|
||||||
;;;;;;; NEW
|
;;;;;;; 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
|
;; --- Create Image
|
||||||
(declare create-images-result)
|
(declare create-images-result)
|
||||||
(def allowed-file-types #{"image/jpeg" "image/png"})
|
(def allowed-file-types #{"image/jpeg" "image/png"})
|
||||||
@ -444,17 +383,17 @@
|
|||||||
(rx/reduce conj [])
|
(rx/reduce conj [])
|
||||||
(rx/do on-success)
|
(rx/do on-success)
|
||||||
(rx/mapcat identity)
|
(rx/mapcat identity)
|
||||||
(rx/map create-images-result)
|
(rx/map (partial create-images-result library-id))
|
||||||
(rx/catch on-error)))))))
|
(rx/catch on-error)))))))
|
||||||
|
|
||||||
;; --- Image Created
|
;; --- Image Created
|
||||||
|
|
||||||
(defn create-images-result
|
(defn create-images-result
|
||||||
[item]
|
[library-id item]
|
||||||
#_(us/verify ::image item)
|
#_(us/verify ::image item)
|
||||||
(ptk/reify ::create-images-result
|
(ptk/reify ::create-images-result
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(-> state
|
(-> state
|
||||||
(update-in [:library :selected-items] #(into [item] %))))))
|
(update-in [:library :selected-items library-id] #(into [item] %))))))
|
||||||
|
|
||||||
|
|||||||
207
frontend/src/uxbox/main/data/library.cljs
Normal file
207
frontend/src/uxbox/main/data/library.cljs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
(ns uxbox.main.data.library
|
||||||
|
(:require
|
||||||
|
[cljs.spec.alpha :as s]
|
||||||
|
[beicon.core :as rx]
|
||||||
|
[cuerdas.core :as str]
|
||||||
|
[potok.core :as ptk]
|
||||||
|
[uxbox.common.spec :as us]
|
||||||
|
[uxbox.common.data :as d]
|
||||||
|
[uxbox.main.repo :as rp]
|
||||||
|
[uxbox.main.store :as st]
|
||||||
|
[uxbox.util.dom :as dom]
|
||||||
|
[uxbox.util.webapi :as wapi]
|
||||||
|
[uxbox.util.i18n :as i18n :refer [t tr]]
|
||||||
|
[uxbox.util.router :as r]
|
||||||
|
[uxbox.util.uuid :as uuid]))
|
||||||
|
|
||||||
|
|
||||||
|
;; Retrieve libraries
|
||||||
|
|
||||||
|
(declare retrieve-libraries-result)
|
||||||
|
|
||||||
|
(defn retrieve-libraries
|
||||||
|
[type team-id]
|
||||||
|
(s/assert ::us/uuid team-id)
|
||||||
|
(let [method (case type
|
||||||
|
:icons :icon-libraries
|
||||||
|
:images :image-libraries
|
||||||
|
:palettes :color-libraries)]
|
||||||
|
(ptk/reify ::retrieve-libraries
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(->> (rp/query! method {:team-id team-id})
|
||||||
|
(rx/map (partial retrieve-libraries-result type)))))))
|
||||||
|
|
||||||
|
(defn retrieve-libraries-result [type result]
|
||||||
|
(ptk/reify ::retrieve-libraries-result
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(assoc-in [:library type] result)))))
|
||||||
|
|
||||||
|
;; Retrieve library data
|
||||||
|
|
||||||
|
(declare retrieve-library-data-result)
|
||||||
|
|
||||||
|
(defn retrieve-library-data
|
||||||
|
[type library-id]
|
||||||
|
(ptk/reify ::retrieve-library-data
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [method (case type
|
||||||
|
:icons :icons
|
||||||
|
:images :images
|
||||||
|
:palettes :colors)]
|
||||||
|
(->> (rp/query! method {:library-id library-id})
|
||||||
|
(rx/map (partial retrieve-library-data-result library-id)))))))
|
||||||
|
|
||||||
|
(defn retrieve-library-data-result
|
||||||
|
[library-id data]
|
||||||
|
(ptk/reify ::retrieve-library-data-result
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(assoc-in [:library :selected-items library-id] data)))))
|
||||||
|
|
||||||
|
|
||||||
|
;; Create library
|
||||||
|
|
||||||
|
(declare create-library-result)
|
||||||
|
|
||||||
|
(defn create-library
|
||||||
|
[type team-id name]
|
||||||
|
(ptk/reify ::create-library
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [method (case type
|
||||||
|
:icons :create-icon-library
|
||||||
|
:images :create-image-library
|
||||||
|
:palettes :create-color-library)]
|
||||||
|
(->> (rp/mutation! method {:team-id team-id
|
||||||
|
:name name})
|
||||||
|
(rx/map (partial create-library-result type)))))))
|
||||||
|
|
||||||
|
(defn create-library-result
|
||||||
|
[type result]
|
||||||
|
(ptk/reify ::create-library-result
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(update-in [:library type] #(into [result] %))))))
|
||||||
|
|
||||||
|
;; Rename library
|
||||||
|
|
||||||
|
(declare rename-library-result)
|
||||||
|
|
||||||
|
(defn rename-library
|
||||||
|
[type library-id name]
|
||||||
|
(ptk/reify ::rename-library
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [method (case type
|
||||||
|
:icons :rename-icon-library
|
||||||
|
:images :rename-image-library
|
||||||
|
:palettes :rename-color-library)]
|
||||||
|
(->> (rp/mutation! method {:id library-id
|
||||||
|
:name name})
|
||||||
|
(rx/map #(rename-library-result type library-id name)))))))
|
||||||
|
|
||||||
|
(defn rename-library-result
|
||||||
|
[type library-id name]
|
||||||
|
(ptk/reify ::rename-library-result
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(letfn [(change-name
|
||||||
|
[library] (if (= library-id (:id library))
|
||||||
|
(assoc library :name name)
|
||||||
|
library))
|
||||||
|
(update-fn [libraries] (map change-name libraries))]
|
||||||
|
|
||||||
|
(-> state
|
||||||
|
(update-in [:library type] update-fn))))))
|
||||||
|
|
||||||
|
;; Delete library
|
||||||
|
|
||||||
|
(declare delete-library-result)
|
||||||
|
|
||||||
|
(defn delete-library
|
||||||
|
[type library-id]
|
||||||
|
(ptk/reify ::delete-library
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(assoc-in [:library :last-deleted-library] library-id)))
|
||||||
|
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [method (case type
|
||||||
|
:icons :delete-icon-library
|
||||||
|
:images :delete-image-library
|
||||||
|
:palettes :delete-color-library)]
|
||||||
|
(->> (rp/mutation! method {:id library-id})
|
||||||
|
(rx/map #(delete-library-result type library-id)))))))
|
||||||
|
|
||||||
|
(defn delete-library-result
|
||||||
|
[type library-id]
|
||||||
|
(ptk/reify ::create-library-result
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(let [update-fn (fn [libraries]
|
||||||
|
(filterv #(not= library-id (:id %)) libraries))]
|
||||||
|
(-> state
|
||||||
|
(update-in [:library type] update-fn))))))
|
||||||
|
|
||||||
|
;; Delete library item
|
||||||
|
|
||||||
|
(declare delete-item-result)
|
||||||
|
|
||||||
|
(defn delete-item
|
||||||
|
[type library-id item-id]
|
||||||
|
(ptk/reify ::delete-item
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [method (case type
|
||||||
|
:icons :delete-icon
|
||||||
|
:images :delete-image
|
||||||
|
:palettes :delete-color)]
|
||||||
|
(->> (rp/mutation! method {:id item-id})
|
||||||
|
(rx/map #(delete-item-result type library-id item-id)))))))
|
||||||
|
|
||||||
|
(defn delete-item-result
|
||||||
|
[type library-id item-id]
|
||||||
|
(ptk/reify ::delete-item-result
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(let [update-fn (fn [items]
|
||||||
|
(filterv #(not= item-id (:id %)) items))]
|
||||||
|
(-> state
|
||||||
|
(update-in [:library :selected-items library-id] update-fn))))))
|
||||||
|
|
||||||
|
;; Batch delete
|
||||||
|
|
||||||
|
(declare batch-delete-item-result)
|
||||||
|
|
||||||
|
(defn batch-delete-item
|
||||||
|
[type library-id item-ids]
|
||||||
|
(ptk/reify ::batch-delete-item
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state stream]
|
||||||
|
(let [method (case type
|
||||||
|
:icons :delete-icon
|
||||||
|
:images :delete-image
|
||||||
|
:palettes :delete-color)]
|
||||||
|
(->> (rx/from item-ids)
|
||||||
|
(rx/flat-map #(rp/mutation! method {:id %}))
|
||||||
|
(rx/last)
|
||||||
|
(rx/map #(batch-delete-item-result type library-id item-ids)))))))
|
||||||
|
|
||||||
|
(defn batch-delete-item-result
|
||||||
|
[type library-id item-ids]
|
||||||
|
(ptk/reify ::batch-delete-item-result
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(let [item-ids-set (set item-ids)
|
||||||
|
update-fn (fn [items]
|
||||||
|
(filterv #(not (item-ids-set (:id %))) items))]
|
||||||
|
(-> state
|
||||||
|
(update-in [:library :selected-items library-id] update-fn))))))
|
||||||
42
frontend/src/uxbox/main/ui/components/editable_label.cljs
Normal file
42
frontend/src/uxbox/main/ui/components/editable_label.cljs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
(ns uxbox.main.ui.components.editable-label
|
||||||
|
(:require
|
||||||
|
[rumext.alpha :as mf]
|
||||||
|
[uxbox.builtins.icons :as i]
|
||||||
|
[uxbox.main.ui.keyboard :as kbd]
|
||||||
|
[uxbox.util.dom :as dom]
|
||||||
|
[uxbox.util.timers :as timers]
|
||||||
|
[uxbox.util.data :refer [classnames]]))
|
||||||
|
|
||||||
|
(mf/defc editable-label
|
||||||
|
[{:keys [ value on-change on-cancel edit readonly class-name]}]
|
||||||
|
(let [input (mf/use-ref nil)
|
||||||
|
state (mf/use-state (:editing false))
|
||||||
|
is-editing (or edit (:editing @state))
|
||||||
|
start-editing (fn []
|
||||||
|
(swap! state assoc :editing true)
|
||||||
|
(timers/schedule 100 #(dom/focus! (mf/ref-node input))))
|
||||||
|
stop-editing (fn [] (swap! state assoc :editing false))
|
||||||
|
cancel-editing (fn []
|
||||||
|
(stop-editing)
|
||||||
|
(when on-cancel (on-cancel)))
|
||||||
|
on-dbl-click (fn [e] (when (not readonly) (start-editing)))
|
||||||
|
on-key-up (fn [e]
|
||||||
|
(cond
|
||||||
|
(kbd/esc? e)
|
||||||
|
(cancel-editing)
|
||||||
|
|
||||||
|
(kbd/enter? e)
|
||||||
|
(let [value (-> e dom/get-target dom/get-value)]
|
||||||
|
(on-change value)
|
||||||
|
(stop-editing))))
|
||||||
|
]
|
||||||
|
|
||||||
|
(if is-editing
|
||||||
|
[:div.editable-label {:class class-name}
|
||||||
|
[:input.editable-label-input {:ref input
|
||||||
|
:default-value value
|
||||||
|
:on-key-down on-key-up}]
|
||||||
|
[:span.editable-label-close {:on-click cancel-editing} i/close]]
|
||||||
|
[:span.editable-label {:class class-name
|
||||||
|
:on-double-click on-dbl-click} value]
|
||||||
|
)))
|
||||||
@ -14,31 +14,36 @@
|
|||||||
[uxbox.util.dom :as dom]))
|
[uxbox.util.dom :as dom]))
|
||||||
|
|
||||||
(mf/defc confirm-dialog
|
(mf/defc confirm-dialog
|
||||||
[{:keys [on-accept on-cancel hint] :as ctx}]
|
[{:keys [message on-accept on-cancel hint cancel-text accept-text] :as ctx}]
|
||||||
(letfn [(accept [event]
|
(let [message (or message (tr "ds.confirm-title"))
|
||||||
(dom/prevent-default event)
|
cancel-text (or cancel-text (tr "ds.confirm-cancel"))
|
||||||
(modal/hide!)
|
accept-text (or accept-text (tr "ds.confirm-ok"))
|
||||||
(on-accept (dissoc ctx :on-accept :on-cancel)))
|
|
||||||
(cancel [event]
|
accept
|
||||||
(dom/prevent-default event)
|
(fn [event]
|
||||||
(modal/hide!)
|
(dom/prevent-default event)
|
||||||
(when on-cancel
|
(modal/hide!)
|
||||||
(on-cancel (dissoc ctx :on-accept :on-cancel))))]
|
(on-accept (dissoc ctx :on-accept :on-cancel)))
|
||||||
|
|
||||||
|
cancel
|
||||||
|
(fn [event]
|
||||||
|
(dom/prevent-default event)
|
||||||
|
(modal/hide!)
|
||||||
|
(when on-cancel
|
||||||
|
(on-cancel (dissoc ctx :on-accept :on-cancel))))]
|
||||||
[:div.lightbox-body.confirm-dialog
|
[:div.lightbox-body.confirm-dialog
|
||||||
[:h3 (tr "ds.confirm-title")]
|
[:h3.confirm-dialog-title message]
|
||||||
(if hint
|
(if hint [:span hint])
|
||||||
[:span hint])
|
|
||||||
[:div.row-flex
|
[:div.confirm-dialog-buttons
|
||||||
[:input.btn-success.btn-small
|
[:input.confirm-dialog-cancel-button
|
||||||
{:type "button"
|
{:type "button"
|
||||||
:value (tr "ds.confirm-ok")
|
:value cancel-text
|
||||||
:on-click accept}]
|
:on-click cancel}]
|
||||||
[:input.btn-delete.btn-small
|
|
||||||
|
[:input.confirm-dialog-accept-button
|
||||||
{:type "button"
|
{:type "button"
|
||||||
:value (tr "ds.confirm-cancel")
|
:value accept-text
|
||||||
:on-click cancel}]]
|
:on-click accept}]]
|
||||||
[:a.close {:href "#"
|
|
||||||
:on-click #(do
|
[:a.close {:href "#" :on-click cancel} i/close]]))
|
||||||
(dom/prevent-default %)
|
|
||||||
(modal/hide!))}
|
|
||||||
i/close]]))
|
|
||||||
|
|||||||
@ -87,7 +87,8 @@
|
|||||||
:dashboard-library-images-index
|
:dashboard-library-images-index
|
||||||
:dashboard-library-palettes
|
:dashboard-library-palettes
|
||||||
:dashboard-library-palettes-index)
|
:dashboard-library-palettes-index)
|
||||||
(mf/element library-page #js {:team-id team-id
|
(mf/element library-page #js {:key library-id
|
||||||
|
:team-id team-id
|
||||||
:library-id library-id
|
:library-id library-id
|
||||||
:section library-section})
|
:section library-section})
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,8 @@
|
|||||||
[uxbox.util.i18n :as i18n :refer [t tr]]
|
[uxbox.util.i18n :as i18n :refer [t tr]]
|
||||||
[uxbox.util.color :as uc]
|
[uxbox.util.color :as uc]
|
||||||
[uxbox.util.dom :as dom]
|
[uxbox.util.dom :as dom]
|
||||||
|
[uxbox.util.time :as dt]
|
||||||
|
[uxbox.main.data.library :as dlib]
|
||||||
[uxbox.main.data.icons :as dico]
|
[uxbox.main.data.icons :as dico]
|
||||||
[uxbox.main.data.images :as dimg]
|
[uxbox.main.data.images :as dimg]
|
||||||
[uxbox.main.data.colors :as dcol]
|
[uxbox.main.data.colors :as dcol]
|
||||||
@ -27,6 +29,7 @@
|
|||||||
[uxbox.main.ui.modal :as modal]
|
[uxbox.main.ui.modal :as modal]
|
||||||
[uxbox.main.ui.confirm :refer [confirm-dialog]]
|
[uxbox.main.ui.confirm :refer [confirm-dialog]]
|
||||||
[uxbox.main.ui.colorpicker :refer [colorpicker most-used-colors]]
|
[uxbox.main.ui.colorpicker :refer [colorpicker most-used-colors]]
|
||||||
|
[uxbox.main.ui.components.editable-label :refer [editable-label]]
|
||||||
))
|
))
|
||||||
|
|
||||||
(mf/defc modal-create-color
|
(mf/defc modal-create-color
|
||||||
@ -53,19 +56,9 @@
|
|||||||
|
|
||||||
[:a.close {:href "#" :on-click cancel} i/close]])))
|
[:a.close {:href "#" :on-click cancel} i/close]])))
|
||||||
|
|
||||||
|
(defn create-library [section team-id]
|
||||||
(defmulti create-library (fn [x _] x))
|
(let [name (str (str (str/title (name section)) " " (gensym "Library ")))]
|
||||||
(defmethod create-library :icons [_ team-id]
|
(st/emit! (dlib/create-library section team-id name))))
|
||||||
(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))
|
(defmulti create-item (fn [x _ _] x))
|
||||||
|
|
||||||
@ -126,28 +119,51 @@
|
|||||||
:on-click
|
:on-click
|
||||||
(fn []
|
(fn []
|
||||||
(let [path (keyword (str "dashboard-library-" (name section)))]
|
(let [path (keyword (str "dashboard-library-" (name section)))]
|
||||||
(dico/fetch-icon-library (:id item))
|
(dlib/retrieve-libraries :icons (:id item))
|
||||||
(st/emit! (rt/nav path {:team-id team-id :library-id (:id item)}))))}
|
(st/emit! (rt/nav path {:team-id team-id :library-id (:id item)}))))}
|
||||||
[:a (:name item)]])]]))
|
[:& editable-label {:value (:name item)
|
||||||
|
:on-change #(st/emit! (dlib/rename-library section library-id %))}]
|
||||||
|
])]]))
|
||||||
|
|
||||||
(mf/defc library-top-menu
|
(mf/defc library-top-menu
|
||||||
[{:keys [selected section library-id]}]
|
[{:keys [selected section library-id team-id on-delete-selected]}]
|
||||||
(let [state (mf/use-state {:is-open false})
|
(let [state (mf/use-state {:is-open false
|
||||||
locale (i18n/use-locale)]
|
:editing-name false})
|
||||||
|
locale (i18n/use-locale)
|
||||||
|
stop-editing #(swap! state assoc :editing-name false)]
|
||||||
[:header.library-top-menu
|
[:header.library-top-menu
|
||||||
[:div.library-top-menu-current-element
|
[:div.library-top-menu-current-element
|
||||||
[:h2.library-top-menu-current-element-name (:name selected)]
|
[:& editable-label {:edit (:editing-name @state)
|
||||||
|
:on-change #(do
|
||||||
|
(stop-editing)
|
||||||
|
(st/emit! (dlib/rename-library section library-id %)))
|
||||||
|
:on-cancel #(swap! state assoc :editing-name false)
|
||||||
|
:class-name "library-top-menu-current-element-name"
|
||||||
|
:value (:name selected)}]
|
||||||
[:a.library-top-menu-current-action
|
[:a.library-top-menu-current-action
|
||||||
{ :on-click #(swap! state update :is-open not)}
|
{ :on-click #(swap! state update :is-open not)}
|
||||||
[:span i/arrow-down]]
|
[:span i/arrow-down]]
|
||||||
[:& context-menu
|
[:& context-menu
|
||||||
{:show (:is-open @state)
|
{:show (:is-open @state)
|
||||||
:on-close #(swap! state update :is-open not)
|
:on-close #(swap! state update :is-open not)
|
||||||
:options [[(t locale "ds.button.rename") #(println "Rename")]
|
:options [[(t locale "ds.button.rename")
|
||||||
[(t locale "ds.button.delete") #(println "Delete")]]}]]
|
#(swap! state assoc :editing-name true)]
|
||||||
|
|
||||||
|
[(t locale "ds.button.delete")
|
||||||
|
(fn []
|
||||||
|
(let [path (keyword (str "dashboard-library-" (name section) "-index"))]
|
||||||
|
(modal/show!
|
||||||
|
confirm-dialog
|
||||||
|
{:on-accept #(do
|
||||||
|
(st/emit! (dlib/delete-library section library-id))
|
||||||
|
(st/emit! (rt/nav path {:team-id team-id})))
|
||||||
|
:message "Are you sure you want to delete this library?"
|
||||||
|
:accept-text "Delete"})))]]}]]
|
||||||
|
|
||||||
[:div.library-top-menu-actions
|
[:div.library-top-menu-actions
|
||||||
[:a i/trash]
|
[:a.library-top-menu-actions-delete
|
||||||
|
{:on-click #(when on-delete-selected (on-delete-selected))}
|
||||||
|
i/trash]
|
||||||
|
|
||||||
(if (= section :palettes)
|
(if (= section :palettes)
|
||||||
[:button.btn-dashboard
|
[:button.btn-dashboard
|
||||||
@ -158,23 +174,35 @@
|
|||||||
[:label {:for "file-upload" :class-name "btn-dashboard"}
|
[:label {:for "file-upload" :class-name "btn-dashboard"}
|
||||||
(t locale (str "dashboard.library.add-item." (name section)))]
|
(t locale (str "dashboard.library.add-item." (name section)))]
|
||||||
[:input {:on-change #(create-item section library-id %)
|
[:input {:on-change #(create-item section library-id %)
|
||||||
:id "file-upload" :type "file" :style {:display "none"}}]]
|
:id "file-upload"
|
||||||
|
:type "file"
|
||||||
)]]))
|
:multiple true
|
||||||
|
:accept (case section
|
||||||
|
:images "image"
|
||||||
|
:icons "image/svg+xml"
|
||||||
|
"")
|
||||||
|
:style {:display "none"}}]])]]))
|
||||||
|
|
||||||
(mf/defc library-icon-card
|
(mf/defc library-icon-card
|
||||||
[{:keys [id name url content metadata]}]
|
[{:keys [item on-select on-unselect]}]
|
||||||
(let [locale (i18n/use-locale)
|
(let [{:keys [id name url content metadata library-id modified-at]} item
|
||||||
state (mf/use-state {:is-open false})]
|
locale (i18n/use-locale)
|
||||||
|
state (mf/use-state {:is-open false
|
||||||
|
:selected false})
|
||||||
|
time (dt/timeago modified-at {:locale locale})
|
||||||
|
handle-change (fn []
|
||||||
|
(swap! state update :selected not)
|
||||||
|
(if (:selected @state)
|
||||||
|
(when on-unselect (on-unselect id))
|
||||||
|
(when on-select (on-select id))))]
|
||||||
[:div.library-card.library-icon
|
[:div.library-card.library-icon
|
||||||
[:div.input-checkbox.check-primary
|
[:div.input-checkbox.check-primary
|
||||||
[:input {:type "checkbox"
|
[:input {:type "checkbox"
|
||||||
:id (str "icon-" id)
|
:id (str "icon-" id)
|
||||||
:on-change #(println "toggle-selection")
|
:on-change handle-change
|
||||||
#_(:checked false)}]
|
:checked (:selected @state)}]
|
||||||
[:label {:for (str "icon-" id)}]]
|
[:label {:for (str "icon-" id)}]]
|
||||||
[:div.library-card-image
|
[:div.library-card-image
|
||||||
#_[:object { :data url :type "image/svg+xml" }]
|
|
||||||
[:svg {:view-box (->> metadata :view-box (str/join " "))
|
[:svg {:view-box (->> metadata :view-box (str/join " "))
|
||||||
:width (:width metadata)
|
:width (:width metadata)
|
||||||
:height (:height metadata)
|
:height (:height metadata)
|
||||||
@ -182,112 +210,181 @@
|
|||||||
|
|
||||||
[:div.library-card-footer
|
[:div.library-card-footer
|
||||||
[:div.library-card-footer-name name]
|
[:div.library-card-footer-name name]
|
||||||
[:div.library-card-footer-timestamp "Less than 5 seconds ago"]
|
[:div.library-card-footer-timestamp time]
|
||||||
[:div.library-card-footer-menu
|
[:div.library-card-footer-menu
|
||||||
{ :on-click #(swap! state update :is-open not) }
|
{ :on-click #(swap! state update :is-open not) }
|
||||||
i/actions]
|
i/actions]
|
||||||
[:& context-menu
|
[:& context-menu
|
||||||
{:show (:is-open @state)
|
{:show (:is-open @state)
|
||||||
:on-close #(swap! state update :is-open not)
|
:on-close #(swap! state update :is-open not)
|
||||||
:options [[(t locale "ds.button.delete") #(println "Delete")]]}]]]))
|
:options [[(t locale "ds.button.delete")
|
||||||
|
(fn []
|
||||||
|
(modal/show!
|
||||||
|
confirm-dialog
|
||||||
|
{:on-accept #(st/emit! (dlib/delete-item :icons library-id id))
|
||||||
|
:message "Are you sure you want to delete this icon?"
|
||||||
|
:accept-text "Delete"}))]]}]]]))
|
||||||
|
|
||||||
(mf/defc library-image-card
|
(mf/defc library-image-card
|
||||||
[{:keys [id name thumb-uri]}]
|
[{:keys [item on-select on-unselect]}]
|
||||||
(let [locale (i18n/use-locale)
|
(let [{:keys [id name thumb-uri library-id modified-at]} item
|
||||||
state (mf/use-state {:is-open false})]
|
locale (i18n/use-locale)
|
||||||
|
state (mf/use-state {:is-open false})
|
||||||
|
time (dt/timeago modified-at {:locale locale})
|
||||||
|
handle-change (fn []
|
||||||
|
(swap! state update :selected not)
|
||||||
|
(if (:selected @state)
|
||||||
|
(when on-unselect (on-unselect id))
|
||||||
|
(when on-select (on-select id))))]
|
||||||
[:div.library-card.library-image
|
[:div.library-card.library-image
|
||||||
[:div.input-checkbox.check-primary
|
[:div.input-checkbox.check-primary
|
||||||
[:input {:type "checkbox"
|
[:input {:type "checkbox"
|
||||||
:id (str "image-" id)
|
:id (str "image-" id)
|
||||||
:on-change #(println "toggle-selection")
|
:on-change handle-change
|
||||||
#_(:checked false)}]
|
:checked (:selected @state)}]
|
||||||
[:label {:for (str "image-" id)}]]
|
[:label {:for (str "image-" id)}]]
|
||||||
[:div.library-card-image
|
[:div.library-card-image
|
||||||
[:img {:src thumb-uri}]]
|
[:img {:src thumb-uri}]]
|
||||||
[:div.library-card-footer
|
[:div.library-card-footer
|
||||||
[:div.library-card-footer-name name]
|
[:div.library-card-footer-name name]
|
||||||
[:div.library-card-footer-timestamp "Less than 5 seconds ago"]
|
[:div.library-card-footer-timestamp time]
|
||||||
[:div.library-card-footer-menu
|
[:div.library-card-footer-menu
|
||||||
{ :on-click #(swap! state update :is-open not) }
|
{ :on-click #(swap! state update :is-open not) }
|
||||||
i/actions]
|
i/actions]
|
||||||
[:& context-menu
|
[:& context-menu
|
||||||
{:show (:is-open @state)
|
{:show (:is-open @state)
|
||||||
:on-close #(swap! state update :is-open not)
|
:on-close #(swap! state update :is-open not)
|
||||||
:options [[(t locale "ds.button.delete") #(println "Delete")]]}]]]))
|
:options [[(t locale "ds.button.delete")
|
||||||
|
(fn []
|
||||||
|
(modal/show!
|
||||||
|
confirm-dialog
|
||||||
|
{:on-accept #(st/emit! (dlib/delete-item :images library-id id))
|
||||||
|
:message "Are you sure you want to delete this image?"
|
||||||
|
:accept-text "Delete"}))]]}]]]))
|
||||||
|
|
||||||
(mf/defc library-color-card
|
(mf/defc library-color-card
|
||||||
[{ :keys [ id content ] }]
|
[{:keys [item on-select on-unselect]}]
|
||||||
(when content
|
(let [{:keys [ id content library-id modified-at]} item
|
||||||
(let [locale (i18n/use-locale)
|
locale (i18n/use-locale)
|
||||||
state (mf/use-state {:is-open false})]
|
state (mf/use-state {:is-open false})
|
||||||
[:div.library-card.library-color
|
handle-change (fn []
|
||||||
[:div.input-checkbox.check-primary
|
(swap! state update :selected not)
|
||||||
[:input {:type "checkbox"
|
(if (:selected @state)
|
||||||
:id (str "color-" id)
|
(when on-unselect (on-unselect id))
|
||||||
:on-change #(println "toggle-selection")
|
(when on-select (on-select id))))]
|
||||||
#_(:checked false)}]
|
(when content
|
||||||
[:label {:for (str "color-" id)}]]
|
[:div.library-card.library-color
|
||||||
[:div.library-card-image
|
[:div.input-checkbox.check-primary
|
||||||
{ :style { :background-color content }}]
|
[:input {:type "checkbox"
|
||||||
[:div.library-card-footer
|
:id (str "color-" id)
|
||||||
[:div.library-card-footer-name content ]
|
:on-change handle-change
|
||||||
[:div.library-card-footer-color
|
:checked (:selected @state)}]
|
||||||
[:span.library-card-footer-color-label "RGB"]
|
[:label {:for (str "color-" id)}]]
|
||||||
[:span.library-card-footer-color-rgb (str/join " " (uc/hex->rgb content))]]
|
[:div.library-card-image
|
||||||
[:div.library-card-footer-menu
|
{ :style { :background-color content }}]
|
||||||
{ :on-click #(swap! state update :is-open not) }
|
[:div.library-card-footer
|
||||||
i/actions]
|
[:div.library-card-footer-name content ]
|
||||||
[:& context-menu
|
[:div.library-card-footer-color
|
||||||
{:show (:is-open @state)
|
[:span.library-card-footer-color-label "RGB"]
|
||||||
:on-close #(swap! state update :is-open not)
|
[:span.library-card-footer-color-rgb (str/join " " (uc/hex->rgb content))]]
|
||||||
:options [[(t locale "ds.button.delete") #(println "Delete")]]}]]])))
|
[: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")
|
||||||
|
(fn []
|
||||||
|
(modal/show!
|
||||||
|
confirm-dialog
|
||||||
|
{:on-accept #(st/emit! (dlib/delete-item :palettes library-id id))
|
||||||
|
:message "Are you sure you want to delete this color?"
|
||||||
|
:accept-text "Delete"}))]]}]]])))
|
||||||
|
|
||||||
(def icon-libraries-ref
|
(defn libraries-ref [section]
|
||||||
(-> (comp (l/key :library) (l/key :icon-libraries))
|
(-> (comp (l/key :library) (l/key section))
|
||||||
(l/derive st/state)))
|
(l/derive st/state)))
|
||||||
|
|
||||||
(def image-libraries-ref
|
(defn selected-items-ref [library-id]
|
||||||
(-> (comp (l/key :library) (l/key :image-libraries))
|
(-> (comp (l/key :library) (l/key :selected-items) (l/key library-id))
|
||||||
(l/derive st/state)))
|
(l/derive st/state)))
|
||||||
|
|
||||||
(def color-libraries-ref
|
(def last-deleted-library-ref
|
||||||
(-> (comp (l/key :library) (l/key :color-libraries))
|
(-> (comp (l/key :library) (l/key :last-deleted-library))
|
||||||
(l/derive st/state)))
|
|
||||||
|
|
||||||
(def selected-items-ref
|
|
||||||
(-> (comp (l/key :library) (l/key :selected-items))
|
|
||||||
(l/derive st/state)))
|
(l/derive st/state)))
|
||||||
|
|
||||||
(mf/defc library-page
|
(mf/defc library-page
|
||||||
[{:keys [team-id library-id section]}]
|
[{:keys [team-id library-id section]}]
|
||||||
(mf/use-effect {:fn #(case section
|
(let [state (mf/use-state {:selected #{}})
|
||||||
:icons (st/emit! (dico/fetch-icon-libraries team-id))
|
libraries (mf/deref (libraries-ref section))
|
||||||
:images (st/emit! (dimg/fetch-image-libraries team-id))
|
items (mf/deref (selected-items-ref library-id))
|
||||||
:palettes (st/emit! (dcol/fetch-color-libraries team-id)))
|
last-deleted-library (mf/deref last-deleted-library-ref)
|
||||||
: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))]
|
selected-library (first (filter #(= (:id %) library-id) libraries))]
|
||||||
|
|
||||||
|
(mf/use-effect {:fn #(if (and (nil? library-id) (> (count libraries) 0))
|
||||||
|
(let [path (keyword (str "dashboard-library-" (name section)))]
|
||||||
|
(st/emit! (rt/nav path {:team-id team-id :library-id (:id (first libraries))}))))
|
||||||
|
:deps (mf/deps libraries)})
|
||||||
|
|
||||||
|
(mf/use-effect {:fn #(if (and library-id (not (some (fn [{id :id}] (= library-id id)) libraries)))
|
||||||
|
(let [path (keyword (str "dashboard-library-" (name section) "-index"))]
|
||||||
|
(st/emit! (rt/nav path {:team-id team-id}))))
|
||||||
|
:deps (mf/deps libraries)})
|
||||||
|
|
||||||
|
(mf/use-effect {:fn #(st/emit! (dlib/retrieve-libraries section team-id))
|
||||||
|
:deps (mf/deps section team-id)})
|
||||||
|
|
||||||
|
(mf/use-effect {:fn #(when (and library-id (not= last-deleted-library library-id))
|
||||||
|
(st/emit! (dlib/retrieve-library-data section library-id)))
|
||||||
|
:deps (mf/deps library-id last-deleted-library)})
|
||||||
|
|
||||||
[:div.library-page
|
[:div.library-page
|
||||||
[:& library-header {:section section :team-id team-id}]
|
[:& library-header {:section section :team-id team-id}]
|
||||||
[:& library-sidebar {:items libraries :team-id team-id :library-id library-id :section section}]
|
[:& library-sidebar {:items libraries :team-id team-id :library-id library-id :section section}]
|
||||||
|
|
||||||
(when library-id
|
(if library-id
|
||||||
[:section.library-content
|
[:section.library-content
|
||||||
[:& library-top-menu {:selected selected-library :section section :library-id library-id}]
|
[:& library-top-menu
|
||||||
[:div.library-page-cards-container
|
{:selected selected-library
|
||||||
(for [item items]
|
:section section
|
||||||
(let [item (assoc item :key (:id item))]
|
:library-id library-id
|
||||||
(case section
|
:team-id team-id
|
||||||
:icons [:& library-icon-card item]
|
:on-delete-selected
|
||||||
:images [:& library-image-card item]
|
(fn []
|
||||||
:palettes [:& library-color-card item ])))]])]))
|
(when (-> @state :selected count (> 0))
|
||||||
|
(modal/show!
|
||||||
|
confirm-dialog
|
||||||
|
{:on-accept #(st/emit! (dlib/batch-delete-item section library-id (:selected @state)))
|
||||||
|
:message (str "Are you sure you want to delete " (-> @state :selected count) " items?")
|
||||||
|
:accept-text "Delete"})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}]
|
||||||
|
[:*
|
||||||
|
;; TODO: Fix the chunked list
|
||||||
|
#_[:& chunked-list {:items items
|
||||||
|
:initial-size 30
|
||||||
|
:chunk-size 30}
|
||||||
|
(fn [item]
|
||||||
|
(let [item (assoc item :key (:id item))]
|
||||||
|
(case section
|
||||||
|
:icons [:& library-icon-card item]
|
||||||
|
:images [:& library-image-card item]
|
||||||
|
:palettes [:& library-color-card item ])))]
|
||||||
|
(if (> (count items) 0)
|
||||||
|
[:div.library-page-cards-container
|
||||||
|
(for [item items]
|
||||||
|
(let [item (assoc item :key (:id item))
|
||||||
|
props {:item item
|
||||||
|
:key (:id item)
|
||||||
|
:on-select #(swap! state update :selected conj %)
|
||||||
|
:on-unselect #(swap! state update :selected disj %)}]
|
||||||
|
(case section
|
||||||
|
:icons [:& library-icon-card props]
|
||||||
|
:images [:& library-image-card props]
|
||||||
|
:palettes [:& library-color-card props])))]
|
||||||
|
[:div.library-content-empty
|
||||||
|
[:p.library-content-empty-text "You still have no elements in this library"]])]]
|
||||||
|
|
||||||
|
[:div.library-content-empty
|
||||||
|
[:p.library-content-empty-text "You still have no image libraries."]])]))
|
||||||
|
|||||||
@ -57,7 +57,6 @@
|
|||||||
(st/emit! (dw/rename-shape (:id shape) name))
|
(st/emit! (dw/rename-shape (:id shape) name))
|
||||||
(swap! local assoc :edition false)))
|
(swap! local assoc :edition false)))
|
||||||
on-key-down (fn [event]
|
on-key-down (fn [event]
|
||||||
(js/console.log event)
|
|
||||||
(when (kbd/enter? event)
|
(when (kbd/enter? event)
|
||||||
(on-blur event)))
|
(on-blur event)))
|
||||||
on-click (fn [event]
|
on-click (fn [event]
|
||||||
|
|||||||
@ -149,7 +149,7 @@
|
|||||||
[& params]
|
[& params]
|
||||||
{:pre [(even? (count params))]}
|
{:pre [(even? (count params))]}
|
||||||
(str/join " " (reduce (fn [acc [k v]]
|
(str/join " " (reduce (fn [acc [k v]]
|
||||||
(if (true? v)
|
(if (and k (true? v))
|
||||||
(conj acc (name k))
|
(conj acc (name k))
|
||||||
acc))
|
acc))
|
||||||
[]
|
[]
|
||||||
|
|||||||
@ -142,8 +142,7 @@
|
|||||||
y (.-clientY event)]
|
y (.-clientY event)]
|
||||||
(gpt/point x y)))
|
(gpt/point x y)))
|
||||||
|
|
||||||
(defn get-offset-position
|
(defn focus!
|
||||||
[event]
|
[node]
|
||||||
(let [x (.-offsetX event)
|
(.focus node))
|
||||||
y (.-offsetY event)]
|
|
||||||
(gpt/point x y)))
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user