diff --git a/frontend/resources/images/icons/tick.svg b/frontend/resources/images/icons/tick.svg new file mode 100644 index 000000000..88d3be0aa --- /dev/null +++ b/frontend/resources/images/icons/tick.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/resources/styles/main/partials/color-palette.scss b/frontend/resources/styles/main/partials/color-palette.scss index cb84e3156..42a7f3a58 100644 --- a/frontend/resources/styles/main/partials/color-palette.scss +++ b/frontend/resources/styles/main/partials/color-palette.scss @@ -52,24 +52,30 @@ left: 280px; width: calc(100% - 280px); } + + & .context-menu-items { + bottom: 1.5rem; + top: initial; + min-width: 10rem; + } } .color-palette-actions { - display: flex; - flex-direction: column; - flex-shrink: 0; - margin-right: .5rem; - - border: 1px solid #1F1F1F; - align-self: stretch; - padding: 0.5rem; - justify-content: center; - - .color-palette-buttons { - align-items: center; + align-self: stretch; + border: 1px solid #1F1F1F; + cursor: pointer; display: flex; - justify-content: space-around; - } + flex-direction: column; + flex-shrink: 0; + justify-content: center; + margin-right: .5rem; + padding: 0.5rem; + + .color-palette-buttons { + align-items: center; + display: flex; + justify-content: space-around; + } } .color-palette-actions-button { @@ -115,6 +121,7 @@ display: flex; overflow: hidden; width: 100%; + height: 4.8rem; padding: 0.25rem; } diff --git a/frontend/resources/styles/main/partials/context-menu.scss b/frontend/resources/styles/main/partials/context-menu.scss index e6acef56b..58735efef 100644 --- a/frontend/resources/styles/main/partials/context-menu.scss +++ b/frontend/resources/styles/main/partials/context-menu.scss @@ -17,7 +17,9 @@ border-radius: $br-small; box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25); left: -$size-4; + max-height: 30rem; min-width: 7rem; + overflow: auto; position: absolute; top: $size-3; } @@ -27,9 +29,25 @@ display: block; font-size: $fs12; padding: $size-2 $size-4; + white-space: nowrap; &:hover { color: $color-black; - background: $color-primary-lighter; + background-color: $color-primary-lighter; } } + +.context-menu.is-selectable { + & .context-menu-action { + padding-left: 1.5rem; + } + + & .context-menu-item.is-selected .context-menu-action { + background-image: url(/images/icons/tick.svg); + background-repeat: no-repeat; + background-position: 5% 48%; + background-size: 10px; + font-weight: bold; + } +} + diff --git a/frontend/resources/styles/main/partials/sidebar.scss b/frontend/resources/styles/main/partials/sidebar.scss index 9bf242cce..0200bfda2 100644 --- a/frontend/resources/styles/main/partials/sidebar.scss +++ b/frontend/resources/styles/main/partials/sidebar.scss @@ -21,7 +21,8 @@ .settings-bar-inside { align-items: center; display: grid; - + grid-template-columns: 100%; + &[data-layout*='layers'] { grid-template-rows: 30% 70%; } diff --git a/frontend/resources/styles/main/partials/workspace-libraries.scss b/frontend/resources/styles/main/partials/workspace-libraries.scss index 9415c2fc3..fe4a8c2f3 100644 --- a/frontend/resources/styles/main/partials/workspace-libraries.scss +++ b/frontend/resources/styles/main/partials/workspace-libraries.scss @@ -3,6 +3,11 @@ grid-template-columns: repeat(2, 50%); padding: 0.5rem; align-items: center; + + & .context-menu-items { + left: initial; + right: 0; + } } .libraries-window-bar-title { diff --git a/frontend/src/uxbox/main/data/colors.cljs b/frontend/src/uxbox/main/data/colors.cljs index 812844ab0..5639ab5e8 100644 --- a/frontend/src/uxbox/main/data/colors.cljs +++ b/frontend/src/uxbox/main/data/colors.cljs @@ -266,4 +266,4 @@ ptk/UpdateEvent (update [_ state] (-> state - (update-in [:library :selected-items library-id] #(into [item] %) ))))) + (update-in [:library-items :palettes library-id] #(into [item] %) ))))) diff --git a/frontend/src/uxbox/main/data/icons.cljs b/frontend/src/uxbox/main/data/icons.cljs index 132f881fb..ee0d5717f 100644 --- a/frontend/src/uxbox/main/data/icons.cljs +++ b/frontend/src/uxbox/main/data/icons.cljs @@ -203,7 +203,7 @@ (update [_ state] (let [{:keys [id] :as item} (assoc item :type :icon)] (-> state - (update-in [:library :selected-items library-id] #(into [item] %))))))) + (update-in [:library-items :icons library-id] #(into [item] %))))))) ;; ;; --- Icon Persisted ;; diff --git a/frontend/src/uxbox/main/data/images.cljs b/frontend/src/uxbox/main/data/images.cljs index d9a5614a4..38dfcb8c9 100644 --- a/frontend/src/uxbox/main/data/images.cljs +++ b/frontend/src/uxbox/main/data/images.cljs @@ -395,5 +395,5 @@ ptk/UpdateEvent (update [_ state] (-> state - (update-in [:library :selected-items library-id] #(into [item] %)))))) + (update-in [:library-items :images library-id] #(into [item] %)))))) diff --git a/frontend/src/uxbox/main/data/library.cljs b/frontend/src/uxbox/main/data/library.cljs index 6b7ac9d70..f7596e980 100644 --- a/frontend/src/uxbox/main/data/library.cljs +++ b/frontend/src/uxbox/main/data/library.cljs @@ -56,15 +56,15 @@ :images :images :palettes :colors)] (->> (rp/query! method {:library-id library-id}) - (rx/map (partial retrieve-library-data-result library-id))))))) + (rx/map (partial retrieve-library-data-result type library-id))))))) (defn retrieve-library-data-result - [library-id data] + [type library-id data] (ptk/reify ::retrieve-library-data-result ptk/UpdateEvent (update [_ state] (-> state - (assoc-in [:library :selected-items library-id] data))))) + (assoc-in [:library-items type library-id] data))))) ;; Create library @@ -178,7 +178,7 @@ (let [update-fn (fn [items] (filterv #(not= item-id (:id %)) items))] (-> state - (update-in [:library :selected-items library-id] update-fn)))))) + (update-in [:library-items type library-id] update-fn)))))) ;; Batch delete @@ -207,4 +207,4 @@ update-fn (fn [items] (filterv #(not (item-ids-set (:id %))) items))] (-> state - (update-in [:library :selected-items library-id] update-fn)))))) + (update-in [:library-items type library-id] update-fn)))))) diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs index 838c67f46..f633fb0bd 100644 --- a/frontend/src/uxbox/main/data/workspace.cljs +++ b/frontend/src/uxbox/main/data/workspace.cljs @@ -270,9 +270,7 @@ (declare initialize-alignment) -#_(def default-layout #{:sitemap :layers :element-options :rules}) -(def default-layout #{:libraries :rules :colorpalette}) - +(def default-layout #{:sitemap :layers :element-options :rules}) (def workspace-default {:zoom 1 diff --git a/frontend/src/uxbox/main/ui/components/context_menu.cljs b/frontend/src/uxbox/main/ui/components/context_menu.cljs index 2c7d85a2f..1023ff301 100644 --- a/frontend/src/uxbox/main/ui/components/context_menu.cljs +++ b/frontend/src/uxbox/main/ui/components/context_menu.cljs @@ -3,7 +3,8 @@ [rumext.alpha :as mf] [goog.object :as gobj] [uxbox.main.ui.components.dropdown :refer [dropdown-container]] - [uxbox.util.uuid :as uuid])) + [uxbox.util.uuid :as uuid] + [uxbox.util.data :refer [classnames]])) (mf/defc context-menu {::mf/wrap-props false} @@ -13,12 +14,17 @@ (assert (vector? (gobj/get props "options")) "missing `options` prop") (let [open? (gobj/get props "show") - options (gobj/get props "options")] + options (gobj/get props "options") + is-selectable (gobj/get props "selectable") + selected (gobj/get props "selected")] + (println "selected" selected) (when open? [:> dropdown-container props - [:div.context-menu {:class (when open? "is-open")} + [:div.context-menu {:class (classnames :is-open open? + :is-selectable is-selectable)} [:ul.context-menu-items (for [[action-name action-handler] options] - [:li.context-menu-item {:key action-name} + [:li.context-menu-item {:class (classnames :is-selected (and selected (= action-name selected))) + :key action-name} [:a.context-menu-action {:on-click action-handler} action-name]])]]]))) diff --git a/frontend/src/uxbox/main/ui/dashboard/library.cljs b/frontend/src/uxbox/main/ui/dashboard/library.cljs index 7db1aa722..d432d6eb5 100644 --- a/frontend/src/uxbox/main/ui/dashboard/library.cljs +++ b/frontend/src/uxbox/main/ui/dashboard/library.cljs @@ -305,8 +305,8 @@ (-> (comp (l/key :library) (l/key section) (l/key team-id)) (l/derive st/state))) -(defn selected-items-ref [library-id] - (-> (comp (l/key :library) (l/key :selected-items) (l/key library-id)) +(defn selected-items-ref [section library-id] + (-> (comp (l/key :library-items) (l/key section) (l/key library-id)) (l/derive st/state))) (def last-deleted-library-ref @@ -317,7 +317,7 @@ [{:keys [team-id library-id section]}] (let [state (mf/use-state {:selected #{}}) libraries (mf/deref (libraries-ref section team-id)) - items (mf/deref (selected-items-ref library-id)) + items (mf/deref (selected-items-ref section library-id)) last-deleted-library (mf/deref last-deleted-library-ref) selected-library (first (filter #(= (:id %) library-id) libraries))] diff --git a/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs b/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs index 3085ad7bc..2ba95faa2 100644 --- a/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs +++ b/frontend/src/uxbox/main/ui/workspace/colorpalette.cljs @@ -13,16 +13,26 @@ [uxbox.builtins.icons :as i] [uxbox.main.data.colors :as udc] [uxbox.main.data.workspace :as udw] + [uxbox.main.data.library :as dlib] [uxbox.main.store :as st] [uxbox.main.ui.keyboard :as kbd] [uxbox.util.color :refer [hex->rgb]] [uxbox.util.data :refer [read-string seek]] - [uxbox.util.dom :as dom])) + [uxbox.util.dom :as dom] + [uxbox.main.ui.components.context-menu :refer [context-menu]])) ;; --- Refs -(def collections-iref - (-> (l/key :colors-collections) +(def project-ref + (-> (l/key :workspace-project) + (l/derive st/state))) + +(def libraries-ref + (-> (comp (l/key :library) (l/key :palettes)) + (l/derive st/state))) + +(defn selected-items-ref [library-id] + (-> (comp (l/key :library-items) (l/key :palettes) (l/key library-id)) (l/derive st/state))) ;; --- Components @@ -30,8 +40,6 @@ (mf/defc palette-item [{:keys [color] :as props}] (let [rgb-vec (hex->rgb color) - rgb-color (apply str "" (interpose ", " rgb-vec)) - select-color (fn [event] (if (kbd/shift? event) @@ -41,93 +49,85 @@ [:div.color-cell {:key (str color) :on-click select-color} [:span.color {:style {:background color}}] - [:span.color-text color] - #_[:span.color-text rgb-color]])) + [:span.color-text color]])) (mf/defc palette - [{:keys [colls left-sidebar?] :as props}] - (let [local (mf/use-state {}) - colls (->> colls - (filter :id) - (sort-by :name)) + [{:keys [libraries left-sidebar?] :as props}] - coll (or (:selected @local) - (first colls)) + (when (and libraries (-> libraries count (> 0))) + (let [state (mf/use-state {:show-menu false + :selected-library (-> libraries first :id)})] + (mf/use-effect (mf/deps (:selected-library @state)) + #(st/emit! (dlib/retrieve-library-data :palettes (:selected-library @state)))) + + (let [items (-> (:selected-library @state) selected-items-ref mf/deref) + doc-width (.. js/document -documentElement -clientWidth) + width (:width @state (* doc-width 0.84)) + offset (:offset @state 0) + visible (/ width 86) + invisible (- (count items) visible) + close #(st/emit! (udw/toggle-layout-flag :colorpalette)) + container (mf/use-ref nil) + container-child (mf/use-ref nil) - doc-width (.. js/document -documentElement -clientWidth) - width (:width @local (* doc-width 0.84)) - offset (:offset @local 0) - visible (/ width 86) - invisible (- (count (:colors coll)) visible) - close #(st/emit! (udw/toggle-layout-flag :colorpalette)) + on-left-arrow-click + (fn [event] + (when (> offset 0) + (let [element (mf/ref-val container-child)] + (swap! state update :offset dec)))) - container (mf/use-ref nil) - container-child (mf/use-ref nil) + on-right-arrow-click + (fn [event] + (when (< offset invisible) + (let [element (mf/ref-val container-child)] + (swap! state update :offset inc)))) - select-coll - (fn [event] - (let [id (read-string (dom/event->value event)) - selected (seek #(= id (:id %)) colls)] - (swap! local assoc :selected selected :position 0))) + on-scroll + (fn [event] + (if (pos? (.. event -nativeEvent -deltaY)) + (on-right-arrow-click event) + (on-left-arrow-click event))) - on-left-arrow-click - (fn [event] - (when (> offset 0) - (let [element (mf/ref-val container-child)] - (swap! local update :offset dec)))) + after-render + (fn [] + (let [dom (mf/ref-val container) + width (.-clientWidth dom)] + (when (not= (:width @state) width) + (swap! state assoc :width width)))) - on-right-arrow-click - (fn [event] - (when (< offset invisible) - (let [element (mf/ref-val container-child)] - (swap! local update :offset inc)))) + handle-click + (fn [library] + (swap! state assoc :selected-library (:id library)))] - on-scroll - (fn [event] - (if (pos? (.. event -nativeEvent -deltaY)) - (on-right-arrow-click event) - (on-left-arrow-click event))) + (mf/use-effect nil after-render) - after-render - (fn [] - (let [dom (mf/ref-val container) - width (.-clientWidth dom)] - (when (not= (:width @local) width) - (swap! local assoc :width width))))] + [:div.color-palette {:class (when left-sidebar? "left-sidebar-open")} + [:& context-menu {:selectable true + :selected (->> libraries (filter #(= (:id %) (:selected-library @state))) first :name) + :show (:show-menu @state) + :on-close #(swap! state assoc :show-menu false) + :options (mapv #(vector (:name %) (partial handle-click %)) libraries)} ] + [:div.color-palette-actions + {:on-click #(swap! state assoc :show-menu true)} + [:div.color-palette-actions-button i/actions]] - (mf/use-effect nil after-render) + [:span.left-arrow {:on-click on-left-arrow-click} i/arrow-slide] - [:div.color-palette {:class (when left-sidebar? "left-sidebar-open")} - [:div.color-palette-actions - [:div.color-palette-actions-button i/actions] - #_[:select.input-select {:on-change select-coll - :default-value (pr-str (:id coll))} - (for [item colls] - [:option {:key (:id item) :value (pr-str (:id item))} - (:name item)])] + [:div.color-palette-content {:ref container :on-wheel on-scroll} + [:div.color-palette-inside {:ref container-child + :style {:position "relative" + :width (str (* 86 (count items)) "px") + :right (str (* 86 offset) "px")}} + (for [item items] + [:& palette-item {:color (:content item) :key (:id item)}])]] - #_[:div.color-palette-buttons - [:div.btn-palette.edit.current i/pencil] - [:div.btn-palette.create i/close]]] - - [:span.left-arrow {:on-click on-left-arrow-click} i/arrow-slide] - - [:div.color-palette-content {:ref container :on-wheel on-scroll} - [:div.color-palette-inside {:ref container-child - :style {:position "relative" - :width (str (* 86 (count (:colors coll))) "px") - :right (str (* 86 offset) "px")}} - #_(for [color (:colors coll)] - [:& palette-item {:color color :key color}]) - (for [color (range 0 20)] - [:& palette-item {:color "#FFFF00" :key color}])]] - - [:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide] - #_[:span.close-palette {:on-click close} i/close]])) + [:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide]])))) (mf/defc colorpalette [{:keys [left-sidebar?]}] - (let [colls (mf/deref collections-iref)] - #_(mf/use-effect #(st/emit! (udc/fetch-collections))) + (let [team-id (-> project-ref mf/deref :team-id) + libraries (-> libraries-ref mf/deref vals flatten)] + (mf/use-effect #(st/emit! (dlib/retrieve-libraries :palettes))) + (mf/use-effect #(st/emit! (dlib/retrieve-libraries :palettes team-id))) [:& palette {:left-sidebar? left-sidebar? - :colls (vals colls)}])) + :libraries libraries}])) diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs index a61463c1d..18111db70 100644 --- a/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs +++ b/frontend/src/uxbox/main/ui/workspace/sidebar/libraries.cljs @@ -24,7 +24,8 @@ [uxbox.util.uuid :as uuid] [uxbox.util.i18n :as i18n :refer [t]] [uxbox.main.ui.components.tab-container :refer [tab-container tab-element]] - [uxbox.main.data.library :as dlib])) + [uxbox.main.data.library :as dlib] + [uxbox.main.ui.components.context-menu :refer [context-menu]])) (def project-ref (-> (l/key :workspace-project) @@ -34,29 +35,34 @@ (-> (comp (l/key :library) (l/key section)) (l/derive st/state))) -(defn selected-items-ref [library-id] - (-> (comp (l/key :library) (l/key :selected-items) (l/key library-id)) +(defn selected-items-ref [section library-id] + (-> (comp (l/key :library-items) (l/key section) (l/key library-id)) (l/derive st/state))) (mf/defc icons-tab [{:keys [libraries]}] + (when (and libraries (-> libraries count (> 0))) (let [state (mf/use-state {:selected-library (-> libraries first :id)})] + (mf/use-effect (mf/deps libraries) + #(when (not (some (fn [it] (= (:selected-library @state) (-> it :id))) libraries)) + (swap! state assoc :selected-library (-> libraries first :id)))) (mf/use-effect (mf/deps (:selected-library @state)) #(st/emit! (dlib/retrieve-library-data :icons (:selected-library @state)))) [:div.library-tab.icons-tab [:select.input-select.library-tab-libraries - {:on-change #(swap! state assoc :selected-library (-> % dom/get-target dom/get-value))} + {:on-change #(swap! state assoc :selected-library (-> % dom/get-target dom/get-value uuid))} (for [library libraries] [:option.library-tab-libraries-item {:key (:id library) :value (:id library)} (:name library)])] [:div.library-tab-content - (let [items (mf/deref (selected-items-ref (:selected-library @state)))] + (let [items (mf/deref (selected-items-ref :icons (:selected-library @state)))] (for [item items] [:div.library-tab-element - {:key (:id item)} + {:key (:id item) + :on-click #(st/emit! (dw/select-for-drawing :icon item))} [:svg {:view-box (->> item :metadata :view-box (str/join " ")) :width (-> item :metadata :width) :height (-> item :metadat :height) @@ -78,19 +84,30 @@ :value (:id library)} (:name library)])] [:div.library-tab-content - (let [items (mf/deref (selected-items-ref (:selected-library @state)))] + (let [items (mf/deref (selected-items-ref :images (:selected-library @state)))] (for [item items] [:div.library-tab-element - {:key (:id item)} + {:key (:id item) + :on-click #(st/emit! (dw/select-for-drawing :image item))} [:img {:src (:thumb-uri item)}] [:span.library-tab-element-name (:name item)]]))]]))) (mf/defc libraries-toolbox [{:keys [key]}] - (let [team-id (-> project-ref mf/deref :team-id) - locale (i18n/use-locale)] + (let [state (mf/use-state {:menu-open false + :selected :all}) + team-id (-> project-ref mf/deref :team-id) + locale (i18n/use-locale) + key-to-str {:all "All libraries" + :own "My libraries" + :store "Store libraries"} + select-option (fn [option] (swap! state assoc :selected option)) + + filter-libraries (fn [libraries] (case (:selected @state) + :all (-> libraries vals flatten) + :own (libraries team-id) + :store (libraries uuid/zero)))] (mf/use-effect - (mf/deps key) #(do (st/emit! (dlib/retrieve-libraries :icons)) (st/emit! (dlib/retrieve-libraries :images)))) @@ -104,17 +121,27 @@ [:div.libraries-window-bar [:div.libraries-window-bar-title "Libraries"] [:div.libraries-window-bar-options - "All libraries" - [:button {:type "button"} - i/arrow-slide]]] + {:on-click #(swap! state assoc :menu-open true)} + (key-to-str (:selected @state)) + [:button + { + :type "button"} + i/arrow-slide + [:& context-menu {:selectable true + :show (:menu-open @state) + :selected (key-to-str (:selected @state)) + :on-close #(swap! state assoc :menu-open false) + :options (mapv (fn [[key val]] [val #(select-option key)]) key-to-str)}]] + + ]] [:div.tool-window-content [:& tab-container {} [:& tab-element {:id :icons :title "Icons"} - [:& icons-tab {:libraries (-> (libraries-ref :icons) mf/deref vals flatten) }]] + [:& icons-tab {:libraries (-> (libraries-ref :icons) mf/deref filter-libraries) }]] [:& tab-element {:id :images :title "Images"} - [:& images-tab {:libraries (-> (libraries-ref :images) mf/deref vals flatten)}]]]]])) + [:& images-tab {:libraries (-> (libraries-ref :images) mf/deref filter-libraries)}]]]]]))