mirror of
https://github.com/penpot/penpot.git
synced 2025-05-21 19:06:11 +02:00
670 lines
29 KiB
Clojure
670 lines
29 KiB
Clojure
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
;;
|
|
;; Copyright (c) KALEIDOS INC
|
|
|
|
(ns app.main.ui.workspace.libraries
|
|
(:require-macros [app.main.style :as stl])
|
|
(: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.config :as cf]
|
|
[app.main.data.dashboard :as dd]
|
|
[app.main.data.modal :as modal]
|
|
[app.main.data.notifications :as ntf]
|
|
[app.main.data.profile :as du]
|
|
[app.main.data.team :as dtm]
|
|
[app.main.data.workspace.colors :as mdc]
|
|
[app.main.data.workspace.libraries :as dwl]
|
|
[app.main.refs :as refs]
|
|
[app.main.render :refer [component-svg]]
|
|
[app.main.store :as st]
|
|
[app.main.ui.components.color-bullet :as cb]
|
|
[app.main.ui.components.link-button :as lb]
|
|
[app.main.ui.components.search-bar :refer [search-bar]]
|
|
[app.main.ui.components.title-bar :refer [title-bar]]
|
|
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
|
[app.main.ui.hooks :as h]
|
|
[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.strings :refer [matches-search]]
|
|
[beicon.v2.core :as rx]
|
|
[cuerdas.core :as str]
|
|
[okulary.core :as l]
|
|
[rumext.v2 :as mf]))
|
|
|
|
(def ^:private close-icon
|
|
(i/icon-xref :close (stl/css :close-icon)))
|
|
|
|
(def ^:private add-icon
|
|
(i/icon-xref :add (stl/css :add-icon)))
|
|
|
|
(def ^:private detach-icon
|
|
(i/icon-xref :detach (stl/css :detach-icon)))
|
|
|
|
(def ^:private library-icon
|
|
(i/icon-xref :library (stl/css :library-icon)))
|
|
|
|
(def ref:workspace-file
|
|
(l/derived :workspace-file st/state))
|
|
|
|
(defn create-file-library-ref
|
|
[library-id]
|
|
(letfn [(getter-fn [state]
|
|
(let [fdata (let [{:keys [id] :as wfile} (:workspace-data state)]
|
|
(if (= id library-id)
|
|
wfile
|
|
(dm/get-in state [:libraries library-id :data])))]
|
|
{:colors (-> fdata :colors vals)
|
|
:media (-> fdata :media vals)
|
|
:components (ctkl/components-seq fdata)
|
|
:typographies (-> fdata :typographies vals)}))]
|
|
(l/derived getter-fn st/state =)))
|
|
|
|
(defn- describe-library
|
|
[components-count graphics-count colors-count typography-count]
|
|
(let [all-zero? (and (zero? components-count) (zero? graphics-count) (zero? colors-count) (zero? typography-count))]
|
|
(str
|
|
(str/join " · "
|
|
(cond-> []
|
|
(or all-zero? (pos? components-count))
|
|
(conj (tr "workspace.libraries.components" components-count))
|
|
|
|
(or all-zero? (pos? graphics-count))
|
|
(conj (tr "workspace.libraries.graphics" graphics-count))
|
|
|
|
(or all-zero? (pos? colors-count))
|
|
(conj (tr "workspace.libraries.colors" colors-count))
|
|
|
|
(or all-zero? (pos? typography-count))
|
|
(conj (tr "workspace.libraries.typography" typography-count))))
|
|
"\u00A0")))
|
|
|
|
(mf/defc describe-library-blocks*
|
|
{::mf/props :obj
|
|
::mf/private true}
|
|
[{:keys [components-count graphics-count colors-count typography-count]}]
|
|
[:*
|
|
(when (pos? components-count)
|
|
[:li {:class (stl/css :element-count)}
|
|
(tr "workspace.libraries.components" components-count)])
|
|
|
|
(when (pos? graphics-count)
|
|
[:li {:class (stl/css :element-count)}
|
|
(tr "workspace.libraries.graphics" graphics-count)])
|
|
|
|
(when (pos? colors-count)
|
|
[:li {:class (stl/css :element-count)}
|
|
(tr "workspace.libraries.colors" colors-count)])
|
|
|
|
(when (pos? typography-count)
|
|
[:li {:class (stl/css :element-count)}
|
|
(tr "workspace.libraries.typography" typography-count)])])
|
|
|
|
(mf/defc sample-library-entry*
|
|
{::mf/props :obj
|
|
::mf/private true}
|
|
[{:keys [library importing]}]
|
|
(let [id (:id library)
|
|
importing? (deref importing)
|
|
|
|
on-error
|
|
(mf/use-fn
|
|
(fn [_]
|
|
(reset! importing nil)
|
|
(rx/of (ntf/error (tr "dashboard.libraries-and-templates.import-error")))))
|
|
|
|
on-success
|
|
(mf/use-fn
|
|
(fn [_]
|
|
(st/emit! (dtm/fetch-shared-files))))
|
|
|
|
import-library
|
|
(mf/use-fn
|
|
(fn [_]
|
|
(reset! importing id)
|
|
(st/emit! (dd/clone-template
|
|
(with-meta {:template-id id}
|
|
{:on-success on-success
|
|
:on-error on-error})))))]
|
|
|
|
[:div {:class (stl/css :sample-library-item)
|
|
:key (dm/str id)}
|
|
[:div {:class (stl/css :sample-library-item-name)} (:name library)]
|
|
[:input {:class (stl/css-case :sample-library-button true
|
|
:sample-library-add (nil? importing?)
|
|
:sample-library-adding (some? importing?))
|
|
:type "button"
|
|
:value (if (= importing? id) (tr "labels.adding") (tr "labels.add"))
|
|
:on-click import-library}]]))
|
|
|
|
(mf/defc libraries-tab*
|
|
{::mf/props :obj
|
|
::mf/private true}
|
|
[{:keys [file-id is-shared linked-libraries shared-libraries]}]
|
|
(let [search-term* (mf/use-state "")
|
|
search-term (deref search-term*)
|
|
library-ref (mf/with-memo [file-id]
|
|
(create-file-library-ref file-id))
|
|
library (deref library-ref)
|
|
colors (:colors library)
|
|
components (:components library)
|
|
media (:media library)
|
|
typographies (:typographies library)
|
|
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
|
|
|
|
empty-library? (and
|
|
(zero? (count colors))
|
|
(zero? (count components))
|
|
(zero? (count media))
|
|
(zero? (count typographies)))
|
|
|
|
shared-libraries
|
|
(mf/with-memo [shared-libraries linked-libraries file-id search-term]
|
|
(when shared-libraries
|
|
(->> (vals shared-libraries)
|
|
(remove #(= (:id %) file-id))
|
|
(remove #(contains? linked-libraries (:id %)))
|
|
(filter #(matches-search (:name %) search-term))
|
|
(sort-by (comp str/lower :name)))))
|
|
|
|
linked-libraries
|
|
(mf/with-memo [linked-libraries]
|
|
(->> (vals linked-libraries)
|
|
(sort-by (comp str/lower :name))))
|
|
|
|
importing* (mf/use-state nil)
|
|
sample-libraries [{:id "penpot-design-system", :name "Design system example"}
|
|
{:id "wireframing-kit", :name "Wireframe library"}
|
|
{:id "whiteboarding-kit", :name "Whiteboarding Kit"}]
|
|
|
|
change-search-term
|
|
(mf/use-fn
|
|
(fn [event]
|
|
(reset! search-term* event)))
|
|
|
|
link-library
|
|
(mf/use-fn
|
|
(mf/deps file-id)
|
|
(fn [event]
|
|
(let [library-id (some-> (dom/get-current-target event)
|
|
(dom/get-data "library-id")
|
|
(parse-uuid))]
|
|
(reset! selected library-id)
|
|
(st/emit! (dwl/link-file-to-library file-id library-id)))))
|
|
|
|
unlink-library
|
|
(mf/use-fn
|
|
(mf/deps file-id)
|
|
(fn [event]
|
|
(let [library-id (some-> (dom/get-current-target event)
|
|
(dom/get-data "library-id")
|
|
(parse-uuid))]
|
|
(when (= library-id @selected)
|
|
(reset! selected :file))
|
|
(st/emit! (dwl/unlink-file-from-library file-id library-id)
|
|
(dwl/sync-file file-id library-id)))))
|
|
|
|
on-delete-accept
|
|
(mf/use-fn
|
|
(mf/deps file-id)
|
|
#(st/emit! (dwl/set-file-shared file-id false)
|
|
(modal/show :libraries-dialog {})))
|
|
|
|
on-delete-cancel
|
|
(mf/use-fn #(st/emit! (modal/show :libraries-dialog {})))
|
|
|
|
publish
|
|
(mf/use-fn
|
|
(mf/deps file-id)
|
|
(fn [event]
|
|
(let [input-node (dom/get-target event)
|
|
publish-library #(st/emit! (dwl/set-file-shared file-id true))
|
|
cancel-publish #(st/emit! (modal/show :libraries-dialog {}))]
|
|
(if empty-library?
|
|
(st/emit! (modal/show
|
|
{:type :confirm
|
|
:title (tr "modals.publish-empty-library.title")
|
|
:message (tr "modals.publish-empty-library.message")
|
|
:accept-label (tr "modals.publish-empty-library.accept")
|
|
:on-accept publish-library
|
|
:on-cancel cancel-publish}))
|
|
(publish-library))
|
|
(dom/blur! input-node))))
|
|
|
|
unpublish
|
|
(mf/use-fn
|
|
(mf/deps file-id)
|
|
(fn [_]
|
|
(st/emit! (modal/show
|
|
{:type :delete-shared-libraries
|
|
:ids #{file-id}
|
|
:origin :unpublish
|
|
:on-accept on-delete-accept
|
|
:on-cancel on-delete-cancel
|
|
:count-libraries 1}))))]
|
|
|
|
[:div {:class (stl/css :libraries-content)}
|
|
[:div {:class (stl/css :lib-section)}
|
|
[:& title-bar {:collapsable false
|
|
:title (tr "workspace.libraries.in-this-file")
|
|
:class (stl/css :title-spacing-lib)}]
|
|
[:div {:class (stl/css :section-list)}
|
|
|
|
[:div {:class (stl/css :section-list-item)}
|
|
[:div {:class (stl/css :item-content)}
|
|
[:div {:class (stl/css :item-name)} (tr "workspace.libraries.file-library")]
|
|
[:ul {:class (stl/css :item-contents)}
|
|
[:> describe-library-blocks* {:components-count (count components)
|
|
:graphics-count (count media)
|
|
:colors-count (count colors)
|
|
:typography-count (count typographies)}]]]
|
|
(if ^boolean is-shared
|
|
[:input {:class (stl/css :item-unpublish)
|
|
:type "button"
|
|
:value (tr "common.unpublish")
|
|
:on-click unpublish}]
|
|
[:input {:class (stl/css :item-publish)
|
|
:type "button"
|
|
:value (tr "common.publish")
|
|
:on-click publish}])]
|
|
|
|
(for [{:keys [id name] :as library} linked-libraries]
|
|
[:div {:class (stl/css :section-list-item)
|
|
:key (dm/str id)
|
|
:data-testid "library-item"}
|
|
[:div {:class (stl/css :item-content)}
|
|
[:div {:class (stl/css :item-name)} name]
|
|
[:ul {:class (stl/css :item-contents)}
|
|
(let [components-count (count (or (ctkl/components-seq (:data library)) []))
|
|
graphics-count (count (dm/get-in library [:data :media] []))
|
|
colors-count (count (dm/get-in library [:data :colors] []))
|
|
typography-count (count (dm/get-in library [:data :typographies] []))]
|
|
[:> describe-library-blocks* {:components-count components-count
|
|
:graphics-count graphics-count
|
|
:colors-count colors-count
|
|
:typography-count typography-count}])]]
|
|
|
|
[:button {:class (stl/css :item-button)
|
|
:type "button"
|
|
:title (tr "workspace.libraries.unlink-library-btn")
|
|
:data-library-id (dm/str id)
|
|
:on-click unlink-library}
|
|
detach-icon]])]]
|
|
|
|
[:div {:class (stl/css :shared-section)}
|
|
[:& title-bar {:collapsable false
|
|
:title (tr "workspace.libraries.shared-libraries")
|
|
:class (stl/css :title-spacing-lib)}]
|
|
[:& search-bar {:on-change change-search-term
|
|
:value search-term
|
|
:placeholder (tr "workspace.libraries.search-shared-libraries")
|
|
:icon (mf/html [:span {:class (stl/css :search-icon)} i/search])}]
|
|
|
|
(if (seq shared-libraries)
|
|
[:div {:class (stl/css :section-list-shared)}
|
|
(for [{:keys [id name] :as library} shared-libraries]
|
|
[:div {:class (stl/css :section-list-item)
|
|
:key (dm/str id)
|
|
:data-testid "library-item"}
|
|
[:div {:class (stl/css :item-content)}
|
|
[:div {:class (stl/css :item-name)} name]
|
|
[:ul {:class (stl/css :item-contents)}
|
|
(let [components-count (dm/get-in library [:library-summary :components :count] 0)
|
|
graphics-count (dm/get-in library [:library-summary :media :count] 0)
|
|
colors-count (dm/get-in library [:library-summary :colors :count] 0)
|
|
typography-count (dm/get-in library [:library-summary :typographies :count] 0)]
|
|
[:> describe-library-blocks* {:components-count components-count
|
|
:graphics-count graphics-count
|
|
:colors-count colors-count
|
|
:typography-count typography-count}])]]
|
|
[:button {:class (stl/css :item-button-shared)
|
|
:data-library-id (dm/str id)
|
|
:title (tr "workspace.libraries.shared-library-btn")
|
|
:on-click link-library}
|
|
add-icon]])]
|
|
|
|
(when (empty? shared-libraries)
|
|
[:div {:class (stl/css :section-list-empty)}
|
|
(cond
|
|
(nil? shared-libraries)
|
|
(tr "workspace.libraries.loading")
|
|
|
|
(and (str/empty? search-term) (cf/external-feature-flag "templates-03" "test"))
|
|
[:*
|
|
[:div {:class (stl/css :sample-libraries-info)}
|
|
(tr "workspace.libraries.empty.no-libraries")
|
|
[:a {:target "_blank"
|
|
:class (stl/css :sample-libraries-link)
|
|
:href "https://penpot.app/libraries-templates"}
|
|
(tr "workspace.libraries.empty.some-templates")]]
|
|
[:div {:class (stl/css :sample-libraries-container)}
|
|
(tr "workspace.libraries.empty.add-some")
|
|
(for [library sample-libraries]
|
|
[:> sample-library-entry*
|
|
{:library library
|
|
:importing importing*}])]]
|
|
|
|
(str/empty? search-term)
|
|
[:*
|
|
[:span {:class (stl/css :empty-state-icon)}
|
|
library-icon]
|
|
(tr "workspace.libraries.no-shared-libraries-available")
|
|
(when (cf/external-feature-flag "templates-01" "test")
|
|
[:div {:class (stl/css :templates-info)}
|
|
(tr "workspace.libraries.more-templates")
|
|
[:a {:target "_blank"
|
|
:class (stl/css :templates-info-link)
|
|
:href "https://penpot.app/libraries-templates"}
|
|
(tr "workspace.libraries.more-templates-link")]])]
|
|
|
|
:else
|
|
(tr "workspace.libraries.no-matches-for" search-term))]))]]))
|
|
|
|
(defn- extract-assets
|
|
[file-data library summary?]
|
|
(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}]))
|
|
|
|
(mf/defc updates-tab*
|
|
{::mf/props :obj
|
|
::mf/private true}
|
|
[{:keys [file-id file-data libraries]}]
|
|
(let [summary?* (mf/use-state true)
|
|
summary? (deref summary?*)
|
|
updating? (mf/deref refs/updating-library)
|
|
|
|
see-all-assets
|
|
(mf/use-fn
|
|
(fn []
|
|
(reset! summary?* false)))
|
|
|
|
libs-assets (mf/with-memo [file-data libraries summary?*]
|
|
(->> (vals libraries)
|
|
(map #(extract-assets file-data % summary?))
|
|
(filter (fn [[_ _ {:keys [components colors typographies]}]]
|
|
(or (seq components)
|
|
(seq colors)
|
|
(seq typographies))))))
|
|
|
|
update (mf/use-fn
|
|
(mf/deps file-id)
|
|
(fn [event]
|
|
(when-not updating?
|
|
(let [library-id (some-> (dom/get-target event)
|
|
(dom/get-data "library-id")
|
|
(parse-uuid))]
|
|
(st/emit!
|
|
(dwl/set-updating-library true)
|
|
(dwl/sync-file file-id library-id))))))]
|
|
|
|
[:div {:class (stl/css :updates-content)}
|
|
[:div {:class (stl/css :update-section)}
|
|
(if (empty? libs-assets)
|
|
[:div {:class (stl/css :section-list-empty)}
|
|
[:span {:class (stl/css :empty-state-icon)}
|
|
library-icon]
|
|
(tr "workspace.libraries.no-libraries-need-sync")]
|
|
[:*
|
|
[:div {:class (stl/css :section-title)} (tr "workspace.libraries.library-updates")]
|
|
|
|
[:div {:class (stl/css :section-list)}
|
|
(for [[{:keys [id name] :as library}
|
|
exceeded
|
|
{:keys [components colors typographies]}] libs-assets]
|
|
[:div {:class (stl/css :section-list-item)
|
|
:key (dm/str id)}
|
|
[:div {:class (stl/css :item-content)}
|
|
[:div {:class (stl/css :item-name)} name]
|
|
[:ul {:class (stl/css :item-contents)} (describe-library
|
|
(count components)
|
|
0
|
|
(count colors)
|
|
(count typographies))]]
|
|
[:button {:type "button"
|
|
:class (stl/css :item-update)
|
|
:disabled updating?
|
|
:data-library-id (dm/str id)
|
|
:on-click update}
|
|
(tr "workspace.libraries.update")]
|
|
|
|
[:div {:class (stl/css :libraries-updates)}
|
|
(when-not (empty? components)
|
|
[:div {:class (stl/css :libraries-updates-column)}
|
|
(for [component components]
|
|
[:div {:class (stl/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
|
|
:class (stl/css :component-svg)
|
|
:objects (:objects component)}]
|
|
[:div {:class (stl/css :name-block)}
|
|
[:span {:class (stl/css :item-name)
|
|
:title (:name component)}
|
|
(:name component)]]])])
|
|
(when (:components exceeded)
|
|
[:div {:class (stl/css :libraries-updates-item)
|
|
:key (uuid/next)}
|
|
[:div {:class (stl/css :name-block :ellipsis)}
|
|
[:span {:class (stl/css :item-name)} "(...)"]]])])
|
|
|
|
(when-not (empty? colors)
|
|
[:div {:class (stl/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 (stl/css :libraries-updates-item)
|
|
:key (dm/str (:id color))}
|
|
[:*
|
|
[:& cb/color-bullet {:color {:color (:color color)
|
|
:id (:id color)
|
|
:opacity (:opacity color)}}]
|
|
[:div {:class (stl/css :name-block)}
|
|
[:span {:class (stl/css :item-name)
|
|
:title (:name color)}
|
|
(:name color)]
|
|
(when-not (= (:name color) default-name)
|
|
[:span.color-value (:color color)])]]]))
|
|
(when (:colors exceeded)
|
|
[:div {:class (stl/css :libraries-updates-item)
|
|
:key (uuid/next)}
|
|
[:div {:class (stl/css :name-block.ellipsis)}
|
|
[:span {:class (stl/css :item-name)} "(...)"]]])])
|
|
|
|
(when-not (empty? typographies)
|
|
[:div {:class (stl/css :libraries-updates-column)}
|
|
(for [typography typographies]
|
|
[:div {:class (stl/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 (stl/css :name-block)}
|
|
[:span {:class (stl/css :item-name)
|
|
:title (:name typography)}
|
|
(:name typography)]]]])
|
|
(when (:typographies exceeded)
|
|
[:div {:class (stl/css :libraries-updates-item)
|
|
:key (uuid/next)}
|
|
[:div {:class (stl/css :name-block.ellipsis)}
|
|
[:span {:class (stl/css :item-name)} "(...)"]]])])]
|
|
|
|
(when (or (pos? (:components exceeded))
|
|
(pos? (:colors exceeded))
|
|
(pos? (:typographies exceeded)))
|
|
[:& lb/link-button {:on-click see-all-assets
|
|
:class (stl/css :libraries-updates-see-all)
|
|
:value (str "(" (tr "workspace.libraries.update.see-all-changes") ")")}])])]])]]))
|
|
(mf/defc libraries-dialog
|
|
{::mf/register modal/components
|
|
::mf/register-as :libraries-dialog}
|
|
[{:keys [starting-tab] :as props :or {starting-tab :libraries}}]
|
|
(let [file-data (mf/deref refs/workspace-data)
|
|
file (mf/deref ref:workspace-file)
|
|
|
|
file-id (:id file)
|
|
shared? (:is-shared file)
|
|
|
|
libraries (mf/deref refs/libraries)
|
|
libraries (mf/with-memo [libraries]
|
|
(d/removem (fn [[_ val]] (:is-indirect val)) libraries))
|
|
|
|
shared-libraries
|
|
(mf/deref refs/shared-files)
|
|
|
|
close-dialog-outside
|
|
(mf/use-fn
|
|
(fn [event]
|
|
(when (= (dom/get-target event) (dom/get-current-target event))
|
|
(modal/hide!))))
|
|
|
|
close-dialog
|
|
(mf/use-fn
|
|
(fn [_]
|
|
(modal/hide!)
|
|
(modal/disallow-click-outside!)))
|
|
|
|
libraries-tab
|
|
(mf/html [:> libraries-tab*
|
|
{:file-id file-id
|
|
:is-shared shared?
|
|
:linked-libraries libraries
|
|
:shared-libraries shared-libraries}])
|
|
|
|
updates-tab
|
|
(mf/html [:> updates-tab*
|
|
{:file-id file-id
|
|
:file-data file-data
|
|
:libraries libraries}])
|
|
|
|
tabs
|
|
#js [#js {:label (tr "workspace.libraries.libraries")
|
|
:id "libraries"
|
|
:content libraries-tab}
|
|
#js {:label (tr "workspace.libraries.updates")
|
|
:id "updates"
|
|
:content updates-tab}]]
|
|
|
|
(mf/with-effect []
|
|
(st/emit! (dtm/fetch-shared-files)))
|
|
|
|
[:div {:class (stl/css :modal-overlay) :on-click close-dialog-outside :data-testid "libraries-modal"}
|
|
[:div {:class (stl/css :modal-dialog)}
|
|
[:button {:class (stl/css :close-btn)
|
|
:on-click close-dialog
|
|
:aria-label (tr "labels.close")
|
|
:data-testid "close-libraries"}
|
|
close-icon]
|
|
[:div {:class (stl/css :modal-title)}
|
|
(tr "workspace.libraries.libraries")]
|
|
|
|
[:> tab-switcher* {:tabs tabs
|
|
:default-selected (dm/str starting-tab)}]]]))
|
|
|
|
(mf/defc v2-info-dialog
|
|
{::mf/register modal/components
|
|
::mf/register-as :v2-info}
|
|
[]
|
|
(let [handle-gotit-click
|
|
(mf/use-fn
|
|
(fn []
|
|
(modal/hide!)
|
|
(st/emit! (du/update-profile-props {:v2-info-shown true}))))]
|
|
|
|
[:div {:class (stl/css :modal-overlay)}
|
|
[:div {:class (stl/css :modal-dialog :modal-v2-info)}
|
|
[:div {:class (stl/css :modal-v2-title)}
|
|
"IMPORTANT INFORMATION ABOUT NEW COMPONENTS"]
|
|
[:div {:class (stl/css :modal-content)}
|
|
[:div {:class (stl/css :info-content)}
|
|
[:div {:class (stl/css :info-block)}
|
|
[:div {:class (stl/css :info-icon)} i/v2-icon-1]
|
|
[:div {:class (stl/css :info-block-title)}
|
|
"One physical source of truth"]
|
|
[:div {:class (stl/css :info-block-content)}
|
|
"Main components are now found at the design space. They act as a single source "
|
|
"of truth and can be worked on with their copies. This ensures consistency and "
|
|
"allows better control and synchronization."]]
|
|
|
|
[:div {:class (stl/css :info-block)}
|
|
[:div {:class (stl/css :info-icon)} i/v2-icon-2]
|
|
[:div {:class (stl/css :info-block-title)}
|
|
"Swap components"]
|
|
[:div {:class (stl/css :info-block-content)}
|
|
"Now, you can replace one component copy with another within your libraries. "
|
|
"The swap components functionality streamlines making changes, testing "
|
|
"variations, or updating elements without extensive manual adjustments."]]
|
|
|
|
[:div {:class (stl/css :info-block)}
|
|
[:div {:class (stl/css :info-icon)} i/v2-icon-3]
|
|
[:div {:class (stl/css :info-block-title)}
|
|
"Graphic assets no longer exist"]
|
|
[:div {:class (stl/css :info-block-content)}
|
|
"Graphic assets now disappear, so that all graphic assets become components. "
|
|
"This way, swapping between them is possible, and we avoid confusion about "
|
|
"what should go in each typology."]]
|
|
|
|
[:div {:class (stl/css :info-block)}
|
|
[:div {:class (stl/css :info-icon)} i/v2-icon-4]
|
|
[:div {:class (stl/css :info-block-title)}
|
|
"Main components page"]
|
|
[:div {:class (stl/css :info-block-content)}
|
|
"You might find that a new page called 'Main components' has appeared in "
|
|
"your file. On that page, you'll find all the main components that were "
|
|
"created in your files previously to this new version."]]]
|
|
|
|
[:div {:class (stl/css :info-bottom)}
|
|
[:button {:class (stl/css :primary-button)
|
|
:on-click handle-gotit-click} "I GOT IT"]]]]]))
|