diff --git a/common/src/app/common/types/colors_list.cljc b/common/src/app/common/types/colors_list.cljc index d479006697..1134a4d169 100644 --- a/common/src/app/common/types/colors_list.cljc +++ b/common/src/app/common/types/colors_list.cljc @@ -51,4 +51,6 @@ (->> (ctc/get-all-colors shape) (keep #(get-ref-color (:data library) %)) (remove #(< (:modified-at %) since-date)) ;; Note that :modified-at may be nil - (map #(vector (:id shape) (:id %) :color)))) + (map (fn [color] {:shape-id (:id shape) + :asset-id (:id color) + :asset-type :color})))) diff --git a/common/src/app/common/types/components_list.cljc b/common/src/app/common/types/components_list.cljc index 7ef285612b..fa9e7e7c27 100644 --- a/common/src/app/common/types/components_list.cljc +++ b/common/src/app/common/types/components_list.cljc @@ -116,7 +116,9 @@ (let [component (get-component (:data library) (:component-id shape))] (if (< (:modified-at component) since-date) ;; Note that :modified-at may be nil [] - [[(:id shape) (:component-id shape) :component]])) + [{:shape-id (:id shape) + :asset-id (:component-id shape) + :asset-type :component}])) [])) (defn get-component-annotation diff --git a/common/src/app/common/types/file.cljc b/common/src/app/common/types/file.cljc index 165611f8ba..85660994d2 100644 --- a/common/src/app/common/types/file.cljc +++ b/common/src/app/common/types/file.cljc @@ -223,7 +223,7 @@ "Add an :objects property to the component, with only the shapes that belong to it" [file-data component] (let [components-v2 (dm/get-in file-data [:options :components-v2])] - (if (and components-v2 component (nil? (:objects component))) ;; This operation may be called twice, e.g. in an idempotent change + (if (and components-v2 component (empty? (:objects component))) ;; This operation may be called twice, e.g. in an idempotent change (let [component-page (get-component-page file-data component) page-objects (:objects component-page) objects (->> (cons (:main-instance-id component) @@ -324,14 +324,15 @@ been modified after the given date." [file-data library since-date] (letfn [(used-assets-shape [shape] - (concat - (ctkl/used-components-changed-since shape library since-date) - (ctcl/used-colors-changed-since shape library since-date) - (ctyl/used-typographies-changed-since shape library since-date))) + (concat + (ctkl/used-components-changed-since shape library since-date) + (ctcl/used-colors-changed-since shape library since-date) + (ctyl/used-typographies-changed-since shape library since-date))) (used-assets-container [container] - (->> (mapcat used-assets-shape (ctn/shapes-seq container)) - (map #(cons (:id container) %))))] + (->> (ctn/shapes-seq container) + (mapcat used-assets-shape) + (map #(assoc % :container-id (:id container)))))] (mapcat used-assets-container (containers-seq file-data)))) diff --git a/common/src/app/common/types/typographies_list.cljc b/common/src/app/common/types/typographies_list.cljc index 04c19075cd..0ef3e7c5e7 100644 --- a/common/src/app/common/types/typographies_list.cljc +++ b/common/src/app/common/types/typographies_list.cljc @@ -53,4 +53,6 @@ txt/node-seq (keep #(get-ref-typography (:data library) %)) (remove #(< (:modified-at %) since-date)) ;; Note that :modified-at may be nil - (map #(vector (:id shape) (:id %) :typography)))) + (map (fn [node] {:shape-id (:id shape) + :asset-id (:id node) + :asset-type :typography})))) diff --git a/frontend/resources/styles/common/framework.scss b/frontend/resources/styles/common/framework.scss index ee9b1eee02..6c51d92eec 100644 --- a/frontend/resources/styles/common/framework.scss +++ b/frontend/resources/styles/common/framework.scss @@ -62,6 +62,16 @@ } .btn-warning { + @extend %btn; + background: $color-warning; + color: $color-white; + &:hover { + background: $color-warning-dark; + color: $color-white; + } +} + +.btn-danger { @extend %btn; background: $color-danger; color: $color-white; @@ -1093,6 +1103,10 @@ input[type="range"]:focus::-ms-fill-upper { } } } + + .link { + color: $color-info; + } } .btn-close { @@ -1215,7 +1229,7 @@ input[type="range"]:focus::-ms-fill-upper { top: 70px; left: 0; right: 0; - width: 35rem; + width: 40rem; margin-left: auto; margin-right: auto; z-index: 20; diff --git a/frontend/resources/styles/main/partials/modal.scss b/frontend/resources/styles/main/partials/modal.scss index b4a0194bb6..83390225cd 100644 --- a/frontend/resources/styles/main/partials/modal.scss +++ b/frontend/resources/styles/main/partials/modal.scss @@ -723,6 +723,22 @@ color: $color-primary; background: $color-black; } + + &.btn-gray { + background: $color-gray-10; + border-color: $color-gray-10; + color: $color-black; + cursor: unset; + + &:hover { + color: $color-black; + } + } + + &.btn-warning { + background: $color-warning; + border-color: $color-warning; + } } } } @@ -791,6 +807,67 @@ } } } + + .libraries-updates { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + grid-gap: $size-5; + font-size: $fs12; + margin-top: $size-4; + + .libraries-updates-item { + display: flex; + align-items: center; + + &:not(:first-child) { + margin-top: $size-2; + } + + & svg { + background-color: $color-canvas; + border-radius: $br4; + border: 2px solid transparent; + height: 24px; + width: 24px; + min-height: 24px; + min-width: 24px; + margin-right: $size-2; + } + + & .color-bullet { + margin-right: $size-2; + } + + & .typography-sample { + margin-right: $size-2; + } + + & .name-block { + color: $color-gray-20; + width: calc(100% - 24px - #{$size-2}); + + &.ellipsis { + padding-left: calc(24px + #{$size-2}); + } + } + + & .item-name { + display: block; + margin: 0; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + } + } + + .libraries-updates-see-all { + margin-top: $size-2; + text-align: right; + cursor: pointer; + color: $color-info; + text-decoration: underline; + } } } diff --git a/frontend/resources/styles/main/partials/project-bar.scss b/frontend/resources/styles/main/partials/project-bar.scss index dff2da1e78..dc8e761302 100644 --- a/frontend/resources/styles/main/partials/project-bar.scss +++ b/frontend/resources/styles/main/partials/project-bar.scss @@ -34,7 +34,8 @@ } .btn-primary, - .btn-warning { + .btn-warning, + .btn-danger { font-size: $fs12; margin-bottom: 0.5rem; padding: 8px $size-2; diff --git a/frontend/resources/styles/main/partials/share-link.scss b/frontend/resources/styles/main/partials/share-link.scss index 920f67344b..8b1d0225f0 100644 --- a/frontend/resources/styles/main/partials/share-link.scss +++ b/frontend/resources/styles/main/partials/share-link.scss @@ -70,7 +70,8 @@ } .btn-primary, .btn-secondary, - .btn-warning { + .btn-warning, + .btn-danger { width: 126px; margin-bottom: 0px; diff --git a/frontend/src/app/main/data/messages.cljs b/frontend/src/app/main/data/messages.cljs index 8ace432288..5730d5502b 100644 --- a/frontend/src/app/main/data/messages.cljs +++ b/frontend/src/app/main/data/messages.cljs @@ -32,6 +32,11 @@ [:timeout {:optional true} [:maybe :int]] [:actions {:optional true} + [:vector + [:map + [:label :string] + [:callback ::sm/fn]]]] + [:links {:optional true} [:vector [:map [:label :string] @@ -132,12 +137,13 @@ :tag tag}))) (defn info-dialog - ([content controls actions] - (info-dialog content controls actions nil)) - ([content controls actions tag] - (show {:content content + [& {:keys [content controls links actions tag] + :or {controls :none links nil tag nil}}] + (show (d/without-nils + {:content content :type :info :position :floating :controls controls + :links links :actions actions :tag tag}))) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index d4759e711c..e048c11d19 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -24,6 +24,7 @@ [app.common.uuid :as uuid] [app.main.data.events :as ev] [app.main.data.messages :as msg] + [app.main.data.modal :as modal] [app.main.data.workspace :as-alias dw] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.groups :as dwg] @@ -821,9 +822,7 @@ (defn assets-need-sync "Get a lazy sequence of all the assets of each type in the library that have been modified after the last sync of the library. The sync date may be - overriden by providing a ignore-until parameter. - - The sequence items are tuples of (page-id shape-id asset-id asset-type)." + overriden by providing a ignore-until parameter." ([library file-data] (assets-need-sync library file-data nil)) ([library file-data ignore-until] (let [sync-date (max (:synced-at library) (or ignore-until 0))] @@ -840,6 +839,8 @@ ignore-until (dm/get-in state [:workspace-file :ignore-sync-until]) libraries-need-sync (filter #(seq (assets-need-sync % file-data ignore-until)) (vals (get state :workspace-libraries))) + do-more-info #(do (modal/show! :libraries-dialog {:starting-tab :updates}) + (st/emit! msg/hide)) do-update #(do (apply st/emit! (map (fn [library] (sync-file (:current-file-id state) (:id library))) @@ -850,13 +851,15 @@ (when (seq libraries-need-sync) (rx/of (msg/info-dialog - (tr "workspace.updates.there-are-updates") - :inline-actions - [{:label (tr "workspace.updates.update") - :callback do-update} - {:label (tr "workspace.updates.dismiss") - :callback do-dismiss}] - :sync-dialog))))))) + :content (tr "workspace.updates.there-are-updates") + :controls :inline-actions + :links [{:label (tr "workspace.updates.more-info") + :callback do-more-info}] + :actions [{:label (tr "workspace.updates.update") + :callback do-update} + {:label (tr "workspace.updates.dismiss") + :callback do-dismiss}] + :tag :sync-dialog))))))) (defn watch-component-changes "Watch the state for changes that affect to any main instance. If a change is detected will throw diff --git a/frontend/src/app/main/ui/messages.cljs b/frontend/src/app/main/ui/messages.cljs index ae7e53930e..2f0ec0e51f 100644 --- a/frontend/src/app/main/ui/messages.cljs +++ b/frontend/src/app/main/ui/messages.cljs @@ -15,7 +15,7 @@ [rumext.v2 :as mf])) (mf/defc banner - [{:keys [type position status controls content actions on-close data-test role] :as props}] + [{:keys [type position status controls content links actions on-close data-test role] :as props}] [:div.banner {:class (dom/classnames :warning (= type :warning) :error (= type :error) @@ -37,7 +37,12 @@ :bottom-actions (= controls :bottom-actions)) :data-test data-test :role role} - content + [:span + content + (for [link links] + [:* {:key (uuid/next)} + " " [:a.link {:on-click (:callback link)} + (:label link)]])] (when (or (= controls :bottom-actions) (= controls :inline-actions)) [:div.actions (for [action actions] diff --git a/frontend/src/app/main/ui/settings/delete_account.cljs b/frontend/src/app/main/ui/settings/delete_account.cljs index 766f3d01d4..9a1961f1a6 100644 --- a/frontend/src/app/main/ui/settings/delete_account.cljs +++ b/frontend/src/app/main/ui/settings/delete_account.cljs @@ -51,7 +51,7 @@ [:div.modal-footer [:div.action-buttons - [:button.btn-warning.btn-large {:on-click on-accept + [:button.btn-danger.btn-large {:on-click on-accept :data-test "delete-account-btn"} (tr "modals.delete-account.confirm")] [:button.btn-secondary.btn-large {:on-click on-close} diff --git a/frontend/src/app/main/ui/viewer/share_link.cljs b/frontend/src/app/main/ui/viewer/share_link.cljs index 9ae7f1b2ad..a6662fa160 100644 --- a/frontend/src/app/main/ui/viewer/share_link.cljs +++ b/frontend/src/app/main/ui/viewer/share_link.cljs @@ -193,7 +193,7 @@ {:type "button" :on-click #(reset! confirm* false) :value (tr "labels.cancel")}] - [:input.btn-warning + [:input.btn-danger {:type "button" :on-click delete-link :value (tr "common.share-link.destroy-link")}]]] diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index 578a1c3cc4..14862dc1f0 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -9,17 +9,24 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.types.colors-list :as ctcl] [app.common.types.components-list :as ctkl] + [app.common.types.file :as ctf] + [app.common.types.typographies-list :as ctyl] + [app.common.uuid :as uuid] [app.main.data.modal :as modal] [app.main.data.workspace.libraries :as dwl] [app.main.features :as features] [app.main.refs :as refs] + [app.main.render :refer [component-svg]] [app.main.store :as st] + [app.main.ui.components.color-bullet :as bc] [app.main.ui.components.search-bar :refer [search-bar]] [app.main.ui.components.tab-container :refer [tab-container tab-element]] [app.main.ui.components.title-bar :refer [title-bar]] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] + [app.util.color :as uc] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] @@ -390,8 +397,65 @@ (mf/defc updates-tab {::mf/wrap-props false} [{:keys [file-id file-data libraries]}] - (let [libraries (mf/with-memo [file-data libraries] - (filter #(seq (dwl/assets-need-sync % file-data)) (vals libraries))) + (let [summary?* (mf/use-state true) + updating?* (mf/use-state false) + summary? (deref summary?*) + updating? (deref updating?*) + + see-all-assets + (fn [] + (reset! summary?* false)) + + extract-assets + (fn [library] + (let [exceeded (volatile! {:components false + :colors false + :typographies false}) + + truncate (fn [asset-type items] + (if (and summary? (> (count items) 5)) + (do + (vswap! exceeded assoc asset-type true) + (take 5 items)) + items)) + + assets (dwl/assets-need-sync library file-data) + + component-ids (into #{} (->> assets + (filter #(= (:asset-type %) :component)) + (map :asset-id))) + color-ids (into #{} (->> assets + (filter #(= (:asset-type %) :color)) + (map :asset-id))) + typography-ids (into #{} (->> assets + (filter #(= (:asset-type %) :typography)) + (map :asset-id))) + + components (->> component-ids + (map #(ctkl/get-component (:data library) %)) + (sort-by #(str/lower (:name %))) + (truncate :components)) + colors (->> color-ids + (map #(ctcl/get-color (:data library) %)) + (sort-by #(str/lower (:name %))) + (truncate :colors)) + typographies (->> typography-ids + (map #(ctyl/get-typography (:data library) %)) + (sort-by #(str/lower (:name %))) + (truncate :typographies))] + + [library @exceeded {:components components + :colors colors + :typographies typographies}])) + + libs-assets (mf/with-memo [file-data libraries summary?*] + (->> (vals libraries) + (map extract-assets) + (filter (fn [[_ _ {:keys [components colors typographies]}]] + (or (seq components) + (seq colors) + (seq typographies)))))) + new-css-system (mf/use-ctx ctx/new-css-system) update (mf/use-fn @@ -400,51 +464,205 @@ (let [library-id (some-> (dom/get-target event) (dom/get-data "library-id") (parse-uuid))] + (reset! updating?* true) (st/emit! (dwl/sync-file file-id library-id)))))] + (if new-css-system [:div {:class (css :section)} - (if (empty? libraries) + (if (empty? libs-assets) [:div {:class (css :section-list-empty)} (tr "workspace.libraries.no-libraries-need-sync")] [:* - [:div {:class (css :section-title)} (tr "workspace.libraries.library")] + [:div {:class (css :section-title)} (tr "workspace.libraries.library-updates")] [:div {:class (css :section-list)} - (for [{:keys [id name] :as library} libraries] + (for [[{:keys [id name] :as library} + exceeded + {:keys [components colors typographies]}] libs-assets] [:div {:class (css :section-list-item) :key (dm/str id)} [:div [:div {:class (css :item-name)} name] - [:div {:class (css :item-contents)} (describe-external-library library)]] - [:input {:class (css :item-update) - :type "button" + [:div {:class (css :item-contents)} (describe-library + (count components) + 0 + (count colors) + (count typographies))]] + [:input {:type "button" + :class (dom/classnames (css :item-update) true + (css :btn-gray) updating? + (css :btn-warning) (not updating?)) :value (tr "workspace.libraries.update") :data-library-id (dm/str id) - :on-click update}]])]])] + :on-click update}] + + [:div {:class (css :libraries-updates)} + (when-not (empty? components) + [:div {:class (css :libraries-updates-column)} + (for [component components] + [:div {:class (css :libraries-updates-item) + :key (dm/str (:id component))} + (let [component (ctf/load-component-objects (:data library) component) + root-shape (ctf/get-component-root (:data library) component)] + [:* + [:& component-svg {:root-shape root-shape + :objects (:objects component)}] + [:div {:class (css :name-block)} + [:span {:class (css :item-name) + :title (:name component)} + (:name component)]]])]) + (when (:components exceeded) + [:div {:class (css :libraries-updates-item) + :key (uuid/next)} + [:div {:class (css :name-block.ellipsis)} + [:span {:class (css :item-name)} "(...)"]]])]) + + (when-not (empty? colors) + [:div {:class (css :libraries-updates-column) + :style #js {"--bullet-size" "24px"}} + (for [color colors] + (let [default-name (cond + (:gradient color) (uc/gradient-type->string (get-in color [:gradient :type])) + (:color color) (:color color) + :else (:value color))] + [:div {:class (css :libraries-updates-item) + :key (dm/str (:id color))} + [:* + [:& bc/color-bullet {:color {:color (:color color) + :opacity (:opacity color)}}] + [:div {:class (css :name-block)} + [:span {:class (css :item-name) + :title (:name color)} + (:name color)] + (when-not (= (:name color) default-name) + [:span.color-value (:color color)])]]])) + (when (:colors exceeded) + [:div {:class (css :libraries-updates-item) + :key (uuid/next)} + [:div {:class (css :name-block.ellipsis)} + [:span {:class (css :item-name)} "(...)"]]])]) + + (when-not (empty? typographies) + [:div {:class (css :libraries-updates-column)} + (for [typography typographies] + [:div {:class (css :libraries-updates-item) + :key (dm/str (:id typography))} + [:* + [:div {:style {:font-family (:font-family typography) + :font-weight (:font-weight typography) + :font-style (:font-style typography)}} + (tr "workspace.assets.typography.sample")] + [:div {:class (css :name-block)} + [:span {:class (css :item-name) + :title (:name typography)} + (:name typography)]]]]) + (when (:typographies exceeded) + [:div {:class (css :libraries-updates-item) + :key (uuid/next)} + [:div {:class (css :name-block.ellipsis)} + [:span {:class (css :item-name)} "(...)"]]])])] + + (when (or (pos? (:components exceeded)) + (pos? (:colors exceeded)) + (pos? (:typographies exceeded))) + [:div {:class (css :libraries-updates-see-all) + :on-click see-all-assets} + "(" (tr "workspace.libraries.update.see-all-changes") ")"])])]])] [:div.section - (if (empty? libraries) + (if (empty? libs-assets) [:div.section-list-empty i/library (tr "workspace.libraries.no-libraries-need-sync")] [:* - [:div.section-title (tr "workspace.libraries.library")] + [:div.section-title (tr "workspace.libraries.library-updates")] [:div.section-list - (for [{:keys [id name] :as library} libraries] + (for [[{:keys [id name] :as library} + exceeded + {:keys [components colors typographies]}] libs-assets] [:div.section-list-item {:key (dm/str id)} [:div.item-name name] - [:div.item-contents (describe-external-library library)] + [:div.item-contents (describe-library + (count components) + 0 + (count colors) + (count typographies))] [:input.item-button {:type "button" + :class (dom/classnames :btn-gray updating? + :btn-warning (not updating?)) :value (tr "workspace.libraries.update") :data-library-id (dm/str id) - :on-click update}]])]])]))) + :on-click update}] + + [:div.libraries-updates + (when-not (empty? components) + [:div.libraries-updates-column + (for [component components] + [:div.libraries-updates-item {:key (dm/str (:id component))} + (let [component (ctf/load-component-objects (:data library) component) + root-shape (ctf/get-component-root (:data library) component)] + [:* + [:& component-svg {:root-shape root-shape + :objects (:objects component)}] + [:div.name-block + [:span.item-name {:title (:name component)} + (:name component)]]])]) + (when (:components exceeded) + [:div.libraries-updates-item {:key (uuid/next)} + [:div.name-block.ellipsis + [:span.item-name "(...)"]]])]) + + (when-not (empty? colors) + [:div.libraries-updates-column {:style #js {"--bullet-size" "24px"}} + (for [color colors] + (let [default-name (cond + (:gradient color) (uc/gradient-type->string (get-in color [:gradient :type])) + (:color color) (:color color) + :else (:value color))] + [:div.libraries-updates-item {:key (dm/str (:id color))} + [:* + [:& bc/color-bullet {:color {:color (:color color) + :opacity (:opacity color)}}] + [:div.name-block + [:span.item-name {:title (:name color)} + (:name color)] + (when-not (= (:name color) default-name) + [:span.color-value (:color color)])]]])) + (when (:colors exceeded) + [:div.libraries-updates-item {:key (uuid/next)} + [:div.name-block.ellipsis + [:span.item-name "(...)"]]])]) + + (when-not (empty? typographies) + [:div.libraries-updates-column + (for [typography typographies] + [:div.libraries-updates-item {:key (dm/str (:id typography))} + [:* + [:div.typography-sample + {:style {:font-family (:font-family typography) + :font-weight (:font-weight typography) + :font-style (:font-style typography)}} + (tr "workspace.assets.typography.sample")] + [:div.name-block + [:span.item-name {:title (:name typography)} + (:name typography)]]]]) + (when (:typographies exceeded) + [:div.libraries-updates-item {:key (uuid/next)} + [:div.name-block.ellipsis + [:span.item-name "(...)"]]])])] + + (when (or (pos? (:components exceeded)) + (pos? (:colors exceeded)) + (pos? (:typographies exceeded))) + [:div.libraries-updates-see-all {:on-click see-all-assets} + "(" (tr "workspace.libraries.update.see-all-changes") ")"])])]])]))) (mf/defc libraries-dialog {::mf/register modal/components ::mf/register-as :libraries-dialog} - [] - (let [new-css-system (features/use-feature :new-css-system) + [{:keys [starting-tab] :as props :or {starting-tab :libraries}}] + (let [new-css-system (features/use-feature :new-css-system) project (mf/deref refs/workspace-project) file-data (mf/deref refs/workspace-data) file (mf/deref ref:workspace-file) @@ -453,7 +671,7 @@ file-id (:id file) shared? (:is-shared file) - selected-tab* (mf/use-state :libraries) + selected-tab* (mf/use-state starting-tab) selected-tab (deref selected-tab*) libraries (mf/deref refs/workspace-libraries) diff --git a/frontend/src/app/main/ui/workspace/libraries.css.json b/frontend/src/app/main/ui/workspace/libraries.css.json index 5dd76fdba8..4d4d0de069 100644 --- a/frontend/src/app/main/ui/workspace/libraries.css.json +++ b/frontend/src/app/main/ui/workspace/libraries.css.json @@ -1 +1 @@ -{"button-primary":"workspace_libraries_button-primary_Hsioh","modal-overlay":"workspace_libraries_modal-overlay_qC-df","modal-dialog":"workspace_libraries_modal-dialog_Kj293","modal-content":"workspace_libraries_modal-content_4EVEQ","libraries-content":"workspace_libraries_libraries-content_ycQdm","section":"workspace_libraries_section_SUsgi","section-list":"workspace_libraries_section-list_lGSrM","section-list-item":"workspace_libraries_section-list-item_hwASN","item-publish":"workspace_libraries_item-publish_ZMopF","item-unpublish":"workspace_libraries_item-unpublish_1seca","item-update":"workspace_libraries_item-update_GklIE","section-list-shared":"workspace_libraries_section-list-shared_XZE10","updates-content":"workspace_libraries_updates-content_lqMoE","button-secondary":"workspace_libraries_button-secondary_l5M0x","item-button":"workspace_libraries_item-button_dKUeX","item-button-shared":"workspace_libraries_item-button-shared_hxOmT","button-tertiary":"workspace_libraries_button-tertiary_C54rH","close":"workspace_libraries_close_bED7B","button-tag":"workspace_libraries_button-tag_wAh-s","button-icon":"workspace_libraries_button-icon_kxS7q","item-button-icon":"workspace_libraries_item-button-icon_CeJWg","button-icon-small":"workspace_libraries_button-icon-small_Q9eo3","section-list-empty":"workspace_libraries_section-list-empty_mOKkJ","libraries-search":"workspace_libraries_libraries-search_JS70w","search-icon":"workspace_libraries_search-icon_y7N9S","asset-element":"workspace_libraries_asset-element_-FuJl","new-scrollbar":"workspace_libraries_new-scrollbar_9V-Nb","menu-dropdown":"workspace_libraries_menu-dropdown_frrTQ","menu-item":"workspace_libraries_menu-item_1PSqe","shortcut":"workspace_libraries_shortcut_ZBbd3","shortcut-key":"workspace_libraries_shortcut-key_qBs5D","user-icon":"workspace_libraries_user-icon_IjCsd","modal-title":"workspace_libraries_modal-title_Z1xKU","libraries-header":"workspace_libraries_libraries-header_-W6bJ","item-name":"workspace_libraries_item-name_Zjbsw","item-contents":"workspace_libraries_item-contents_EPTF6","section-title":"workspace_libraries_section-title_7rsm7","element-count":"workspace_libraries_element-count_07SV2","spin-animation":"workspace_libraries_spin-animation_mW-An"} \ No newline at end of file +{"button-primary":"workspace_libraries_button-primary_Hsioh","modal-overlay":"workspace_libraries_modal-overlay_qC-df","modal-dialog":"workspace_libraries_modal-dialog_Kj293","modal-content":"workspace_libraries_modal-content_4EVEQ","libraries-content":"workspace_libraries_libraries-content_ycQdm","section":"workspace_libraries_section_SUsgi","section-list":"workspace_libraries_section-list_lGSrM","section-list-item":"workspace_libraries_section-list-item_hwASN","item-publish":"workspace_libraries_item-publish_ZMopF","item-unpublish":"workspace_libraries_item-unpublish_1seca","item-update":"workspace_libraries_item-update_GklIE","section-list-shared":"workspace_libraries_section-list-shared_XZE10","updates-content":"workspace_libraries_updates-content_lqMoE","button-secondary":"workspace_libraries_button-secondary_l5M0x","item-button":"workspace_libraries_item-button_dKUeX","item-button-shared":"workspace_libraries_item-button-shared_hxOmT","button-tertiary":"workspace_libraries_button-tertiary_C54rH","close":"workspace_libraries_close_bED7B","button-tag":"workspace_libraries_button-tag_wAh-s","button-icon":"workspace_libraries_button-icon_kxS7q","item-button-icon":"workspace_libraries_item-button-icon_CeJWg","button-icon-small":"workspace_libraries_button-icon-small_Q9eo3","section-list-empty":"workspace_libraries_section-list-empty_mOKkJ","libraries-search":"workspace_libraries_libraries-search_JS70w","search-icon":"workspace_libraries_search-icon_y7N9S","asset-element":"workspace_libraries_asset-element_-FuJl","new-scrollbar":"workspace_libraries_new-scrollbar_9V-Nb","menu-dropdown":"workspace_libraries_menu-dropdown_frrTQ","menu-item":"workspace_libraries_menu-item_1PSqe","shortcut":"workspace_libraries_shortcut_ZBbd3","shortcut-key":"workspace_libraries_shortcut-key_qBs5D","user-icon":"workspace_libraries_user-icon_IjCsd","modal-title":"workspace_libraries_modal-title_Z1xKU","libraries-header":"workspace_libraries_libraries-header_-W6bJ","item-name":"workspace_libraries_item-name_Zjbsw","item-contents":"workspace_libraries_item-contents_EPTF6","btn-gray":"workspace_libraries_btn-gray_F54JC","btn-warning":"workspace_libraries_btn-warning_abcYL","section-title":"workspace_libraries_section-title_7rsm7","libraries-updates":"workspace_libraries_libraries-updates_RLtH8","libraries-updates-item":"workspace_libraries_libraries-updates-item_QwZMY","name-block":"workspace_libraries_name-block_RcVh4","ellipsis":"workspace_libraries_ellipsis_I5JtE","libraries-updates-see-all":"workspace_libraries_libraries-updates-see-all_-G5EO","element-count":"workspace_libraries_element-count_07SV2","spin-animation":"workspace_libraries_spin-animation_mW-An"} \ No newline at end of file diff --git a/frontend/src/app/main/ui/workspace/libraries.scss b/frontend/src/app/main/ui/workspace/libraries.scss index 06e330f261..02acf20782 100644 --- a/frontend/src/app/main/ui/workspace/libraries.scss +++ b/frontend/src/app/main/ui/workspace/libraries.scss @@ -96,6 +96,22 @@ padding: $s-8 $s-24; border-radius: $br-8; } + .item-update { + margin-right: $s-2; + &.btn-gray { + background: var(--light-gray-4); + border-color: var(--light-gray-4); + color: var(--dark-gray-4); + cursor: unset; + &:hover { + color: var(--dark-gray-4); + } + } + &.btn-warning { + background: var(--light-warning-color); + border-color: var(--light-warning-color); + } + } .item-unpublish { @extend .button-secondary; } @@ -153,6 +169,60 @@ } } } + .libraries-updates { + display: grid; + grid-column: span 3; + grid-template-columns: repeat(auto-fill, minmax($s-160, 1fr)); + grid-gap: $s-24; + font-size: $fs12; + margin-top: $s-16; + + .libraries-updates-item { + display: flex; + align-items: center; + + &:not(:first-child) { + margin-top: $s-8; + } + + & svg { + background-color: var(--canvas-color); + border-radius: $br-4; + border: $s-2 solid transparent; + height: $s-24; + width: $s-24; + min-height: $s-24; + min-width: $s-24; + } + + & .name-block { + color: var(--gray-20-color); + margin-left: $s-8; + width: $s-168; + + &.ellipsis { + padding-left: calc($s-24 + #{$s-8}); + } + } + + & .item-name { + display: block; + margin: 0; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + } + } + .libraries-updates-see-all { + grid-column: span 3; + margin-top: $s-8; + margin-right: $s-8; + text-align: right; + cursor: pointer; + color: var (--info-color); + text-decoration: underline; + } } .updates-content { grid-template-columns: 1fr; diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs index 677b459dbe..a4b3cfc391 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets/colors.cljs @@ -45,7 +45,6 @@ (:value color) (dissoc :value) true (assoc :file-id file-id))) - color-id (:id color) item-ref (mf/use-ref) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index f371267ff9..03052518de 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -3351,6 +3351,10 @@ msgstr "LIBRARIES" msgid "workspace.libraries.library" msgstr "LIBRARY" +#: src/app/main/ui/workspace/libraries.cljs +msgid "workspace.libraries.library-updates" +msgstr "LIBRARY UPDATES" + #: src/app/main/ui/workspace/libraries.cljs msgid "workspace.libraries.no-libraries-need-sync" msgstr "There are no Shared Libraries that need update" @@ -3391,6 +3395,10 @@ msgstr "Update" msgid "workspace.libraries.updates" msgstr "UPDATES" +#: src/app/main/data/workspace/libraries.cljs +msgid "workspace.libraries.update.see-all-changes" +msgstr "see all changes" + #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs msgid "workspace.options.add-interaction" msgstr "Click the + button to add interactions." @@ -4784,6 +4792,10 @@ msgstr "Operation over %s" msgid "workspace.undo.title" msgstr "History" +#: src/app/main/data/workspace/libraries.cljs +msgid "workspace.updates.more-info" +msgstr "More info" + #: src/app/main/data/workspace/libraries.cljs msgid "workspace.updates.dismiss" msgstr "Dismiss" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 331d79b907..5b5ae1a8d7 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -3440,6 +3440,10 @@ msgstr "BIBLIOTECAS" msgid "workspace.libraries.library" msgstr "BIBLIOTECA" +#: src/app/main/ui/workspace/libraries.cljs +msgid "workspace.libraries.library-updates" +msgstr "ACTUALIZACIONES DE BIBLIOTECAS" + #: src/app/main/ui/workspace/libraries.cljs msgid "workspace.libraries.no-libraries-need-sync" msgstr "No hay bibliotecas que necesiten ser actualizadas" @@ -3480,6 +3484,10 @@ msgstr "Actualizar" msgid "workspace.libraries.updates" msgstr "ACTUALIZACIONES" +#: src/app/main/data/workspace/libraries.cljs +msgid "workspace.updates.see-all-changes" +msgstr "ver todos los cambios" + #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs msgid "workspace.options.add-interaction" msgstr "Pulsa el botón + para añadir interacciones." @@ -4902,6 +4910,10 @@ msgstr "Operación sobre %s" msgid "workspace.undo.title" msgstr "Histórico" +#: src/app/main/data/workspace/libraries.cljs +msgid "workspace.updates.more-info" +msgstr "Más información" + #: src/app/main/data/workspace/libraries.cljs msgid "workspace.updates.dismiss" msgstr "Ignorar"