mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
✨ Add the ability to import tokens from Linked Library
Add the option to import tokens from a linked library. I know there are plans to link the tokens in together with the library. Once this happens this patch can be reverted. Until then it helps a lot to use a design system that relies on themes. Before that someones would need to: * Download the design system / add to their team. * Open the file, download the tokens. For every new file: * Link the Design System library. * Import the tokens file. With this patch all you need to get started is to download the design system and add to your team. From their importing the links is done on the same pop-up that is used to import the tokens. --- Technical considerations: I try adding this as a dialog that is called once the library is imported. I ran into a few issues though: * To find whether the library has tokens (and thus show the dialog) I would need to extend library summary to include tokens. * I couldn't find a reliable way to import the tokens after importing the library without resorting to a timer :/ I'm sure both of those hurdles are doable, I just wasted enough time trying it to the point I decided on a different approach. Signed-off-by: Dalai Felinto <dalai@blender.org> 📎 Fix minor issues and linter reports 📎 Reuse translations
This commit is contained in:
parent
05521a84d4
commit
0ff5574b12
@ -15,6 +15,7 @@
|
||||
- Add woff2 support on user uploaded fonts (by @Nivl) [Github #8248](https://github.com/penpot/penpot/pull/8248)
|
||||
- Option to download custom fonts (by @dfelinto) [Github #8320](https://github.com/penpot/penpot/issues/8320)
|
||||
- Add copy as image to clipboard option to workspace context menu (by @dfelinto) [Github #8313](https://github.com/penpot/penpot/pull/8313)
|
||||
- Import Tokens from linked library [Github #8391](https://github.com/penpot/penpot/pull/8391)
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
|
||||
@ -119,12 +119,13 @@
|
||||
:strict-session-cookies
|
||||
:telemetry
|
||||
:terms-and-privacy-checkbox
|
||||
;; Only for developtment.
|
||||
:tiered-file-data-storage
|
||||
:token-base-font-size
|
||||
:token-color
|
||||
:token-shadow
|
||||
:token-tokenscript
|
||||
:token-import-from-library
|
||||
;; Only for developtment.
|
||||
:transit-readable-response
|
||||
:user-feedback
|
||||
;; TODO: remove this flag.
|
||||
@ -180,7 +181,8 @@
|
||||
:enable-token-color
|
||||
:enable-token-shadow
|
||||
:enable-inspect-styles
|
||||
:enable-feature-fdata-objects-map])
|
||||
:enable-feature-fdata-objects-map
|
||||
:enable-token-import-from-library])
|
||||
|
||||
(defn parse
|
||||
[& flags]
|
||||
|
||||
@ -13,8 +13,10 @@
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.library :as ctl]
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[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]
|
||||
@ -36,6 +38,7 @@
|
||||
[app.main.ui.ds.product.empty-state :refer [empty-state*]]
|
||||
[app.main.ui.hooks :as h]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.workspace.tokens.import-from-library]
|
||||
[app.util.color :as uc]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [c tr]]
|
||||
@ -180,6 +183,12 @@
|
||||
[summary]
|
||||
(boolean (:is-empty summary)))
|
||||
|
||||
(defn- has-tokens?
|
||||
"Check if library has tokens to be imported"
|
||||
[{:keys [data]}]
|
||||
(when-let [tokens-lib (get data :tokens-lib)]
|
||||
(not (ctob/empty-lib? tokens-lib))))
|
||||
|
||||
(mf/defc libraries-tab*
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
@ -230,14 +239,18 @@
|
||||
(keep library-names))))
|
||||
(sort-by (comp str/lower :name))))
|
||||
|
||||
linked-libraries-ids (mf/with-memo [linked-libraries]
|
||||
(into #{} (map :id) linked-libraries))
|
||||
linked-libraries-ids
|
||||
(mf/with-memo [linked-libraries]
|
||||
(into #{} d/xf:map-id linked-libraries))
|
||||
|
||||
importing*
|
||||
(mf/use-state nil)
|
||||
|
||||
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"}]
|
||||
sample-libraries
|
||||
(mf/with-memo []
|
||||
[{:id "penpot-design-system", :name "Design system example"}
|
||||
{:id "wireframing-kit", :name "Wireframe library"}
|
||||
{:id "whiteboarding-kit", :name "Whiteboarding Kit"}])
|
||||
|
||||
|
||||
change-search-term
|
||||
@ -267,6 +280,17 @@
|
||||
(st/emit! (dwl/unlink-file-from-library file-id library-id)
|
||||
(dwl/sync-file file-id library-id)))))
|
||||
|
||||
import-tokens
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn [event]
|
||||
(let [library-id (some-> (dom/get-current-target event)
|
||||
(dom/get-data "library-id")
|
||||
(uuid/parse))]
|
||||
(st/emit! (modal/show
|
||||
:tokens/import-from-library {:file-id file-id
|
||||
:library-id library-id})))))
|
||||
|
||||
on-delete-accept
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
@ -332,8 +356,12 @@
|
||||
:on-click publish}])]
|
||||
|
||||
(for [{:keys [id name data connected-to connected-to-names] :as library} linked-libraries]
|
||||
(let [disabled? (some #(contains? linked-libraries-ids %) connected-to)]
|
||||
[:div {:class (stl/css :section-list-item)
|
||||
(let [disabled? (some #(contains? linked-libraries-ids %) connected-to)
|
||||
has-tokens? (and (has-tokens? library)
|
||||
(contains? cf/flags :token-import-from-library))]
|
||||
[:div {:class (if has-tokens?
|
||||
(stl/css :section-list-item-double-icon)
|
||||
(stl/css :section-list-item))
|
||||
:key (dm/str id)
|
||||
:data-testid "library-item"}
|
||||
[:div {:class (stl/css :item-content)}
|
||||
@ -348,6 +376,15 @@
|
||||
[:span {:class (stl/css :connected-to-values)} (str/join ", " connected-to-names)]
|
||||
[:span ")"]])])]]
|
||||
|
||||
(when ^boolean has-tokens?
|
||||
[:> icon-button*
|
||||
{:type "button"
|
||||
:aria-label (tr "workspace.tokens.import-tokens")
|
||||
:icon i/import-export
|
||||
:data-library-id (dm/str id)
|
||||
:variant "secondary"
|
||||
:on-click import-tokens}])
|
||||
|
||||
[:> icon-button* {:type "button"
|
||||
:aria-label (tr "workspace.libraries.unlink-library-btn")
|
||||
:icon i/detach
|
||||
|
||||
@ -116,6 +116,11 @@
|
||||
border-radius: $br-8;
|
||||
}
|
||||
|
||||
.section-list-item-double-icon {
|
||||
@extend .section-list-item;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
@ -0,0 +1,92 @@
|
||||
;; 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.tokens.import-from-library
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.workspace.tokens.library-edit :as dwtl]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.foundations.typography :as t]
|
||||
[app.main.ui.ds.foundations.typography.heading :refer [heading*]]
|
||||
[app.main.ui.ds.foundations.typography.text :refer [text*]]
|
||||
[app.main.ui.ds.notifications.context-notification :refer [context-notification*]]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[okulary.core :as l]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
|
||||
(mf/defc import-modal-library*
|
||||
{::mf/register modal/components
|
||||
::mf/register-as :tokens/import-from-library}
|
||||
[all-props]
|
||||
(let [{:keys [file-id library-id]}
|
||||
(js->clj all-props :keywordize-keys true)
|
||||
|
||||
library-file-ref (mf/with-memo [library-id]
|
||||
(l/derived (fn [state]
|
||||
(dm/get-in state [:files library-id :data]))
|
||||
st/state))
|
||||
library-data (mf/deref library-file-ref)
|
||||
|
||||
show-libraries-dialog
|
||||
(mf/use-fn
|
||||
(mf/deps file-id)
|
||||
(fn []
|
||||
(modal/hide!)
|
||||
(modal/show! :libraries-dialog {:file-id file-id})))
|
||||
|
||||
cancel
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(show-libraries-dialog)))
|
||||
|
||||
import
|
||||
(mf/use-fn
|
||||
(mf/deps file-id library-id library-data)
|
||||
(fn []
|
||||
(let [tokens-lib (:tokens-lib library-data)]
|
||||
(st/emit! (dwtl/import-tokens-lib tokens-lib)))
|
||||
(show-libraries-dialog)))]
|
||||
|
||||
[:div {:class (stl/css :modal-overlay)}
|
||||
[:div {:class (stl/css :modal-dialog)}
|
||||
[:> icon-button* {:class (stl/css :close-btn)
|
||||
:on-click cancel
|
||||
:aria-label (tr "labels.close")
|
||||
:variant "ghost"
|
||||
:icon i/close}]
|
||||
|
||||
[:div {:class (stl/css :modal-header)}
|
||||
[:> heading* {:level 2
|
||||
:id "modal-title"
|
||||
:typography "headline-large"
|
||||
:class (stl/css :modal-title)}
|
||||
(tr "modals.import-library-tokens.title")]]
|
||||
|
||||
[:div {:class (stl/css :modal-content)}
|
||||
[:> text* {:as "p" :typography t/body-medium} (tr "modals.import-library-tokens.description")]]
|
||||
|
||||
[:> context-notification* {:type :context
|
||||
:appearance "neutral"
|
||||
:level "default"
|
||||
:is-html true}
|
||||
(tr "workspace.tokens.import-warning")]
|
||||
|
||||
[:div {:class (stl/css :modal-footer)}
|
||||
[:div {:class (stl/css :action-buttons)}
|
||||
[:> button* {:on-click cancel
|
||||
:type "button"
|
||||
:variant "secondary"}
|
||||
(tr "labels.cancel")]
|
||||
[:> button* {:on-click import
|
||||
:type "button"
|
||||
:variant "primary"}
|
||||
(tr "modals.import-library-tokens.import")]]]]]))
|
||||
@ -0,0 +1,70 @@
|
||||
// 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
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
|
||||
@use "ds/typography.scss" as t;
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/_sizes.scss" as *;
|
||||
|
||||
.close-btn {
|
||||
position: absolute;
|
||||
inset-block-start: var(--sp-s);
|
||||
inset-inline-end: var(--sp-s);
|
||||
}
|
||||
|
||||
.modal-overlay {
|
||||
--modal-title-foreground-color: var(--color-foreground-primary);
|
||||
--modal-text-foreground-color: var(--color-foreground-secondary);
|
||||
|
||||
@extend .modal-overlay-base;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
inset-inline-start: 0;
|
||||
inset-block-start: 0;
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
background-color: var(--overlay-color);
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
@extend .modal-container-base;
|
||||
inline-size: 100%;
|
||||
max-inline-size: 32rem;
|
||||
max-block-size: unset;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
margin-block-end: var(--sp-xxl);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
@include t.use-typography("headline-medium");
|
||||
color: var(--modal-title-foreground-color);
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@include t.use-typography("body-large");
|
||||
color: var(--modal-text-foreground-color);
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
margin-block-start: var(--sp-xxl);
|
||||
gap: var(--sp-s);
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
@extend .modal-action-btns;
|
||||
gap: var(--sp-s);
|
||||
}
|
||||
@ -1153,6 +1153,20 @@ msgstr "Type to search results"
|
||||
msgid "dashboard.unpublish-shared"
|
||||
msgstr "Unpublish Library"
|
||||
|
||||
#:src/app/main/ui/workspace/tokens/import_from_library.cljs
|
||||
msgid "modals.import-library-tokens.title"
|
||||
msgstr "Import tokens from library?"
|
||||
|
||||
#:src/app/main/ui/workspace/tokens/import_from_library.cljs
|
||||
msgid "modals.import-library-tokens.description"
|
||||
msgstr ""
|
||||
"The library has tokens and themes which "
|
||||
"are likely used by its components."
|
||||
|
||||
#:src/app/main/ui/workspace/tokens/import_from_library.cljs
|
||||
msgid "modals.import-library-tokens.import"
|
||||
msgstr "Import tokens"
|
||||
|
||||
#: src/app/main/ui/settings/options.cljs:74
|
||||
msgid "dashboard.update-settings"
|
||||
msgstr "Update settings"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user