diff --git a/backend/src/app/services/queries/viewer.clj b/backend/src/app/services/queries/viewer.clj index ffcff177a..bfd5b9aae 100644 --- a/backend/src/app/services/queries/viewer.clj +++ b/backend/src/app/services/queries/viewer.clj @@ -49,9 +49,12 @@ project (retrieve-project conn (:project-id file)) page (get-in file [:data :pages-index page-id]) - bundle {:file (dissoc file :data) + file-library (select-keys (:data file) [:colors :media :typographies]) + bundle {:file (-> (dissoc file :data) + (merge file-library)) :page (get-in file [:data :pages-index page-id]) - :project project}] + :project project} + ] (if (string? share-token) (do (check-shared-token! conn file-id page-id share-token) diff --git a/frontend/resources/styles/main/partials/handoff.scss b/frontend/resources/styles/main/partials/handoff.scss index ca741a3d2..3f407617f 100644 --- a/frontend/resources/styles/main/partials/handoff.scss +++ b/frontend/resources/styles/main/partials/handoff.scss @@ -104,9 +104,32 @@ .attributes-color-row { display: flex; + flex-direction: column; padding: 1rem 0; position: relative; - align-items: center; + + .attributes-color-id { + display: flex; + align-items: center; + + & > * { + margin: 0 0.5rem; + } + margin-bottom: 0.5rem; + } + + .attributes-color-value { + display: flex; + align-items: center; + + & > * { + margin: 0 0.5rem; + } + + & :last-child { + margin-right: 0; + } + } .color-text { width: 3rem; @@ -123,19 +146,15 @@ border-radius: $br-small; border: 1px solid $color-gray-60; } + + .hide-color .color-bullet { + visibility: hidden; + } .copy-button { padding: 1rem 0.5rem; margin-top: 0.25rem; } - & > * { - margin: 0 0.5rem; - } - - & :last-child { - margin-right: 0; - } - select { font-size: $fs12; margin: 0; @@ -226,6 +245,22 @@ justify-content: space-between; } + .attributes-typography-name-row { + position: relative; + margin-top: 0.5rem; + border: 1px solid $color-black; + border-radius: 4px; + margin: 0.5rem; + display: flex; + flex-direction: row; + align-items: center; + + .copy-button { + padding: 0.5rem; + margin-top: 0.25rem; + } + } + .attributes-typography-row { position: relative; margin: 0.5rem; @@ -234,6 +269,7 @@ .typography-sample { font-size: $fs16; } + } .download-button { @@ -260,7 +296,8 @@ .attributes-shadow-row, .attributes-stroke-row, .attributes-typography-row, - .attributes-content-row { + .attributes-content-row, + .attributes-typography-name-row { &:hover { .expand-button, .copy-button { @@ -343,6 +380,6 @@ } } -.element-options :first-child { +.element-options > :first-child { border-top: none; } diff --git a/frontend/src/app/main/data/viewer.cljs b/frontend/src/app/main/data/viewer.cljs index 8a09cf13c..67c1310ab 100644 --- a/frontend/src/app/main/data/viewer.cljs +++ b/frontend/src/app/main/data/viewer.cljs @@ -72,8 +72,10 @@ (let [params (cond-> {:page-id page-id :file-id file-id} (string? token) (assoc :share-token token))] - (->> (rp/query :viewer-bundle params) - (rx/map bundle-fetched) + (->> (rx/zip (rp/query :viewer-bundle params) + (rp/query :file-libraries {:file-id file-id})) + (rx/first) + (rx/map #(apply bundle-fetched %)) #_(rx/catch (fn [error-data] (rx/of (rt/nav :not-found))))))))) @@ -87,7 +89,7 @@ (vec)))) (defn bundle-fetched - [{:keys [project file page share-token] :as bundle}] + [{:keys [project file page share-token] :as bundle} libraries] (us/verify ::bundle bundle) (ptk/reify ::file-fetched ptk/UpdateEvent @@ -95,7 +97,8 @@ (let [objects (:objects page) frames (extract-frames objects)] (-> state - (assoc :viewer-data {:project project + (assoc :viewer-libraries (into {} (map #(vector (:id %) %) libraries)) + :viewer-data {:project project :objects objects :file file :page page diff --git a/frontend/src/app/main/ui/components/copy_button.cljs b/frontend/src/app/main/ui/components/copy_button.cljs index c23f57537..2f8e9d610 100644 --- a/frontend/src/app/main/ui/components/copy_button.cljs +++ b/frontend/src/app/main/ui/components/copy_button.cljs @@ -22,7 +22,7 @@ (fn [] (when @just-copied (let [sub (timers/schedule 1000 #(reset! just-copied false))] - ;; On umounto we dispose the timer + ;; On unmount we dispose the timer #(rx/-dispose sub))))) [:button.copy-button diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/common.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/common.cljs index fc50006b0..8fe89b976 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/common.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/common.cljs @@ -11,43 +11,69 @@ (:require [rumext.alpha :as mf] [cuerdas.core :as str] + [okulary.core :as l] + [app.common.math :as mth] [app.util.dom :as dom] [app.util.i18n :refer [t] :as i18n] [app.util.color :as uc] - [app.common.math :as mth] - [app.main.ui.icons :as i] [app.util.code-gen :as cg] [app.util.webapi :as wapi] + [app.main.ui.icons :as i] + [app.main.store :as st] [app.main.ui.components.copy-button :refer [copy-button]] [app.main.ui.components.color-bullet :refer [color-bullet color-name]])) + +(def file-colors-ref + (l/derived (l/in [:viewer-data :file :colors]) st/state)) + +(defn make-colors-library-ref [file-id] + (let [get-library + (fn [state] + (get-in state [:viewer-libraries file-id :data :colors]))] + #(l/derived get-library st/state))) + (mf/defc color-row [{:keys [color format copy-data on-change-format]}] - (let [locale (mf/deref i18n/locale)] + (let [locale (mf/deref i18n/locale) + + colors-library-ref (mf/use-memo + (mf/deps (:file-id color)) + (make-colors-library-ref (:file-id color))) + colors-library (mf/deref colors-library-ref) + + file-colors (mf/deref file-colors-ref) + + color-library-name (get-in (or colors-library file-colors) [(:id color) :name])] [:div.attributes-color-row - [:& color-bullet {:color color}] + (when color-library-name + [:div.attributes-color-id + [:& color-bullet {:color color}] + [:div color-library-name]]) - (if (:gradient color) - [:& color-name {:color color}] - (case format - :rgba (let [[r g b a] (->> (uc/hex->rgba (:color color) (:opacity color)) (map #(mth/precision % 2)))] - [:div (str/fmt "%s, %s, %s, %s" r g b a)]) - :hsla (let [[h s l a] (->> (uc/hex->hsla (:color color) (:opacity color)) (map #(mth/precision % 2)))] - [:div (str/fmt "%s, %s, %s, %s" h s l a)]) - [:* - [:& color-name {:color color}] - (when-not (:gradient color) [:div (str (* 100 (:opacity color)) "%")])])) + [:div.attributes-color-value {:class (when color-library-name "hide-color")} + [:& color-bullet {:color color}] - (when-not (and on-change-format (:gradient color)) - [:select {:on-change #(-> (dom/get-target-val %) keyword on-change-format)} - [:option {:value "hex"} - (t locale "handoff.attributes.color.hex")] + (if (:gradient color) + [:& color-name {:color color}] + (case format + :rgba (let [[r g b a] (->> (uc/hex->rgba (:color color) (:opacity color)) (map #(mth/precision % 2)))] + [:div (str/fmt "%s, %s, %s, %s" r g b a)]) + :hsla (let [[h s l a] (->> (uc/hex->hsla (:color color) (:opacity color)) (map #(mth/precision % 2)))] + [:div (str/fmt "%s, %s, %s, %s" h s l a)]) + [:* + [:& color-name {:color color}] + (when-not (:gradient color) [:div (str (* 100 (:opacity color)) "%")])])) - [:option {:value "rgba"} - (t locale "handoff.attributes.color.rgba")] + (when-not (and on-change-format (:gradient color)) + [:select {:on-change #(-> (dom/get-target-val %) keyword on-change-format)} + [:option {:value "hex"} + (t locale "handoff.attributes.color.hex")] - [:option {:value "hsla"} - (t locale "handoff.attributes.color.hsla")]]) + [:option {:value "rgba"} + (t locale "handoff.attributes.color.rgba")] + [:option {:value "hsla"} + (t locale "handoff.attributes.color.hsla")]])] (when copy-data [:& copy-button {:data copy-data}])])) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/fill.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/fill.cljs index e433d557f..8afb6d5ba 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/fill.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/fill.cljs @@ -23,8 +23,8 @@ {:color (:fill-color shape) :opacity (:fill-opacity shape) :gradient (:fill-color-gradient shape) - :id (:fill-ref-id shape) - :file-id (:fill-ref-file-id shape)}) + :id (:fill-color-ref-id shape) + :file-id (:fill-color-ref-file shape)}) (defn has-color? [shape] (and diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/stroke.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/stroke.cljs index de9f7da64..fe26f8be5 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/stroke.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/stroke.cljs @@ -22,8 +22,8 @@ {:color (:stroke-color shape) :opacity (:stroke-opacity shape) :gradient (:stroke-color-gradient shape) - :id (:stroke-ref-id shape) - :file-id (:stroke-ref-file-id shape)}) + :id (:stroke-color-ref-id shape) + :file-id (:stroke-color-ref-file shape)}) (defn format-stroke [shape] (let [width (:stroke-width shape) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/text.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/text.cljs index 583c22280..9c1090f41 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/text.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/text.cljs @@ -11,6 +11,7 @@ (:require [rumext.alpha :as mf] [cuerdas.core :as str] + [okulary.core :as l] [app.util.data :as d] [app.util.i18n :refer [t]] [app.util.color :as uc] @@ -20,11 +21,22 @@ [app.util.webapi :as wapi] [app.main.ui.viewer.handoff.attributes.common :refer [color-row]] [app.util.code-gen :as cg] + [app.main.store :as st] [app.main.ui.components.copy-button :refer [copy-button]])) (defn has-text? [shape] (:content shape)) +(def file-typographies-ref + (l/derived (l/in [:viewer-data :file :typographies]) st/state)) + +(defn make-typographies-library-ref [file-id] + (let [get-library + (fn [state] + (get-in state [:viewer-libraries file-id :data :typographies]))] + #(l/derived get-library st/state))) + + (def properties [:fill-color :fill-color-gradient :font-family @@ -39,21 +51,21 @@ {:color (:fill-color shape) :opacity (:fill-opacity shape) :gradient (:fill-color-gradient shape) - :id (:fill-ref-id shape) - :file-id (:fill-ref-file-id shape)}) + :id (:fill-color-ref-id shape) + :file-id (:fill-color-ref-file shape)}) (def params {:to-prop {:fill-color "color" :fill-color-gradient "color"} - :format {:font-family #(str "'" % "'") - :font-style #(str "'" % "'") - :font-size #(str % "px") - :line-height #(str % "px") - :letter-spacing #(str % "px") - :text-decoration name - :text-transform name - :fill-color #(-> %2 shape->color uc/color->background) - :fill-color-gradient #(-> %2 shape->color uc/color->background)}}) + :format {:font-family #(str "'" % "'") + :font-style #(str "'" % "'") + :font-size #(str % "px") + :line-height #(str % "px") + :letter-spacing #(str % "px") + :text-decoration name + :text-transform name + :fill-color #(-> %2 shape->color uc/color->background) + :fill-color-gradient #(-> %2 shape->color uc/color->background)}}) (defn copy-style-data ([style] @@ -62,16 +74,37 @@ (cg/generate-css-props style properties params))) (mf/defc typography-block [{:keys [shape locale text style full-style]}] - (let [color-format (mf/use-state :hex) - color (shape->color style)] + (let [typography-library-ref (mf/use-memo + (mf/deps (:typography-ref-file style)) + (make-typographies-library-ref (:typography-ref-file style))) + typography-library (mf/deref typography-library-ref) + + file-typographies (mf/deref file-typographies-ref) + + color-format (mf/use-state :hex) + color (shape->color style) + + typography (get (or typography-library file-typographies) (:typography-ref-id style))] + [:div.attributes-text-block - [:div.attributes-typography-row - [:div.typography-sample - {:style {:font-family (:font-family full-style) - :font-weight (:font-weight full-style) - :font-style (:font-style full-style)}} - (t locale "workspace.assets.typography.sample")] - [:& copy-button {:data (copy-style-data style)}]] + (if (:typography-ref-id style) + [:div.attributes-typography-name-row + [:div.typography-entry + [:div.typography-sample + {:style {:font-family (:font-family typography) + :font-weight (:font-weight typography) + :font-style (:font-style typography)}} + (t locale "workspace.assets.typography.sample")]] + [:div.typography-entry-name (:name typography)] + [:& copy-button {:data (copy-style-data typography)}]] + + [:div.attributes-typography-row + [:div.typography-sample + {:style {:font-family (:font-family full-style) + :font-weight (:font-weight full-style) + :font-style (:font-style full-style)}} + (t locale "workspace.assets.typography.sample")] + [:& copy-button {:data (copy-style-data style)}]]) [:div.attributes-content-row [:pre.attributes-content (str/trim text)] @@ -129,7 +162,6 @@ (mf/defc text-block [{:keys [shape locale]}] (let [font (ut/search-text-attrs (:content shape) (keys ut/default-text-attrs)) - style-text-blocks (->> (keys ut/default-text-attrs) (ut/parse-style-text-blocks (:content shape)) (remove (fn [[style text]] (str/empty? (str/trim text)))) diff --git a/frontend/src/app/util/text.cljs b/frontend/src/app/util/text.cljs index e5226b04d..4e1ad7136 100644 --- a/frontend/src/app/util/text.cljs +++ b/frontend/src/app/util/text.cljs @@ -3,7 +3,9 @@ [cuerdas.core :as str])) (defonce default-text-attrs - {:font-id "sourcesanspro" + {:typography-ref-file nil + :typography-ref-id nil + :font-id "sourcesanspro" :font-family "sourcesanspro" :font-variant-id "regular" :font-size "14"