diff --git a/frontend/src/app/main/ui/workspace/tokens/core.cljs b/frontend/src/app/main/ui/workspace/tokens/core.cljs index dc86af1284..29d58d0e97 100644 --- a/frontend/src/app/main/ui/workspace/tokens/core.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/core.cljs @@ -9,13 +9,18 @@ [app.common.data :as d :refer [ordered-map]] [app.common.types.shape.radius :as ctsr] [app.common.types.token :as ctt] + [app.libs.file-builder :as fb] [app.main.data.tokens :as dt] [app.main.data.workspace :as udw] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.transforms :as dwt] + [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.workspace.tokens.style-dictionary :as sd] + [app.util.dom :as dom] + [app.util.webapi :as wapi] + [cuerdas.core :as str] [promesa.core :as p])) ;; Helpers --------------------------------------------------------------------- @@ -128,6 +133,33 @@ (st/emit! (dwsl/update-layout [shape-id] layout-update))))) +;; JSON export functions ------------------------------------------------------- + +(defn encode-tokens + [data] + (-> data + (clj->js) + (js/JSON.stringify nil 2))) + +(defn export-tokens-file [tokens-json] + (let [file-name "tokens.json" + file-content (encode-tokens tokens-json) + blob (wapi/create-blob (clj->js file-content) "application/json")] + (dom/trigger-download file-name blob))) + +(defn transform-tokens-into-json-format [tokens] + (let [global (reduce + (fn [acc [_ {:keys [name value type]}]] + (assoc acc name {:value value + :type (str/camel type)})) + (sorted-map) tokens)] + {:global global})) + +(defn download-tokens-as-json [] + (let [all-tokens (deref refs/workspace-tokens) + transformed-tokens-json (transform-tokens-into-json-format all-tokens)] + (export-tokens-file transformed-tokens-json))) + ;; Token types ----------------------------------------------------------------- (def token-types diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index d3350b3d50..3ab3519e01 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -25,6 +25,9 @@ (def lens:token-type-open-status (l/derived (l/in [:workspace-tokens :open-status]) st/state)) +(def ^:private download-icon + (i/icon-xref :download (stl/css :download-icon))) + (mf/defc token-pill {::mf/wrap-props false} [{:keys [on-click token highlighted? on-context-menu]}] @@ -163,4 +166,8 @@ ::mf/wrap-props false} [_props] [:div {:class (stl/css :sidebar-tab-wrapper)} - [:& tokens-explorer]]) + [:& tokens-explorer] + [:button {:class (stl/css :download-json-button) + :on-click wtc/download-tokens-as-json} + download-icon + "Export JSON"]]) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.scss b/frontend/src/app/main/ui/workspace/tokens/sidebar.scss index 64f11a3ce0..67ff95ee03 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.scss +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.scss @@ -49,3 +49,22 @@ // Align better with the label translate: 0px -1px; } + +.download-json-button { + @extend .button-secondary; + position: absolute; + bottom: $s-12; + right: $s-12; + display: flex; + align-items: center; + padding: $s-6 $s-8; + text-transform: uppercase; + gap: $s-8; + + .download-icon { + @extend .button-icon; + stroke: var(--icon-foreground); + width: 20px; + height: 20px; + } +}