From 1e48221d7b7a08643e9f59a41e1bbe7edd4d5f4e Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Thu, 22 Oct 2020 18:08:40 +0200 Subject: [PATCH] :sparkles: Information panels --- frontend/resources/locales.json | 70 ++++- .../styles/main/partials/handoff.scss | 210 +++++++++++++++ frontend/src/app/main/data/viewer.cljs | 13 +- .../app/main/ui/components/color_bullet.cljs | 2 +- frontend/src/app/main/ui/viewer/handoff.cljs | 8 +- .../main/ui/viewer/handoff/attrib_panel.cljs | 248 ++++++++++++++++++ .../ui/viewer/handoff/attributes/layout.cljs | 110 ++++++++ .../ui/viewer/handoff/attributes_sidebar.cljs | 43 ++- .../ui/viewer/handoff/selection_feedback.cljs | 2 +- frontend/src/app/util/text.cljs | 25 +- 10 files changed, 713 insertions(+), 18 deletions(-) create mode 100644 frontend/src/app/main/ui/viewer/handoff/attrib_panel.cljs create mode 100644 frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json index 43ccfefff..1fd5dbfc0 100644 --- a/frontend/resources/locales.json +++ b/frontend/resources/locales.json @@ -3360,5 +3360,73 @@ "ru" : "Кликни чтобы закончить фигуру", "es" : "Pulsar para cerrar la ruta" } - } + }, + + + "handoff.tabs.info": "Info", + "handoff.tabs.code": "Code", + + "handoff.attributes.color.hex": "HEX", + "handoff.attributes.color.rgba": "RGBA", + "handoff.attributes.color.hsla": "HSLA", + + "handoff.attributes.layout": "Layout", + + "handoff.attributes.layout.width": "Width", + "handoff.attributes.layout.height": "Height", + "handoff.attributes.layout.left": "Left", + "handoff.attributes.layout.top": "Top", + "handoff.attributes.layout.rotation": "Rotation", + + "handoff.attributes.fill": "Fill", + + "handoff.attributes.stroke": "Stroke", + "handoff.attributes.stroke.width": "Width", + + "handoff.attributes.stroke.style.solid": "Solid", + "handoff.attributes.stroke.style.dotted": "Dotted", + "handoff.attributes.stroke.style.dashed": "Dashed", + "handoff.attributes.stroke.style.mixed": "Mixed", + "handoff.attributes.stroke.style.none": "None", + + "handoff.attributes.stroke.alignment.center": "Center", + "handoff.attributes.stroke.alignment.inner": "Inner", + "handoff.attributes.stroke.alignment.outer": "Outer", + + "handoff.attributes.shadow": "Shadow", + + "handoff.attributes.shadow.shorthand.offset-x": "X", + "handoff.attributes.shadow.shorthand.offset-y": "Y", + "handoff.attributes.shadow.shorthand.blur": "B", + "handoff.attributes.shadow.shorthand.spread": "S", + + "handoff.attributes.shadow.style.inner-shadow": "Inner", + "handoff.attributes.shadow.style.drop-shadow": "Drop", + + "handoff.attributes.blur": "Blur", + "handoff.attributes.blur.value": "Value", + + "handoff.attributes.image.width": "Width", + "handoff.attributes.image.height": "Height", + "handoff.attributes.image.download": "Dowload source image", + + "handoff.attributes.typography": "Typography", + "handoff.attributes.typography.font-family": "Font Family", + "handoff.attributes.typography.font-style": "Font Style", + "handoff.attributes.typography.font-size": "Font Size", + "handoff.attributes.typography.line-height": "Line Height", + "handoff.attributes.typography.letter-spacing": "Letter Spacing", + "handoff.attributes.typography.text-decoration": "Text Decoration", + "handoff.attributes.typography.text-transform": "Text Transform", + + "handoff.attributes.content": "Content", + + "handoff.attributes.typography.text-decoration.none": "None", + "handoff.attributes.typography.text-decoration.underline": "Underline", + "handoff.attributes.typography.text-decoration.strikethrough": "Strikethrough", + + "handoff.attributes.typography.text-transform.none": "None", + "handoff.attributes.typography.text-transform.uppercase": "Upper Case", + "handoff.attributes.typography.text-transform.lowercase": "Lower Case", + "handoff.attributes.typography.text-transform.titlecase": "Title Case" } diff --git a/frontend/resources/styles/main/partials/handoff.scss b/frontend/resources/styles/main/partials/handoff.scss index 5e92c3ca3..5a1856093 100644 --- a/frontend/resources/styles/main/partials/handoff.scss +++ b/frontend/resources/styles/main/partials/handoff.scss @@ -14,3 +14,213 @@ align-items: center; justify-content: center; } + +.attributes-block { + user-select: text; + + border-bottom: 1px solid $color-gray-60; + padding-bottom: 0.5rem; + font-size: $fs12; + + .attributes-copy-button { + visibility: hidden; + opacity: 0; + transition: opacity 0.3s; + position: absolute; + right: 0; + top: 0; + background: none; + border: none; + padding: 0; + cursor: pointer; + + svg { + width: 16px; + height: 16px; + fill: $color-gray-20; + transition: fill 0.3s; + + &:hover { + fill: $color-primary; + } + } + } + + .attributes-label { + color: $color-gray-20; + } + + .attributes-value { + color: $color-white; + } + + .attributes-block-title { + position: relative; + color: $color-gray-10; + padding: 0.5rem; + font-size: $fs14; + + .attributes-copy-button { + padding: 0.5rem; + margin-top: 0.25rem; + } + } + + .attributes-unit-row { + position: relative; + display: flex; + flex-direction: row; + padding: 1rem 0.5rem; + + .attributes-label, + .attributes-value { + width: 50%; + } + .attributes-copy-button { + padding: 1rem 0.5rem; + margin-top: 0.25rem; + } + } + + .attributes-color-row { + display: flex; + padding: 1rem 0; + position: relative; + align-items: center; + + .attributes-color-display { + display: flex; + } + + .color-bullet { + width: 24px; + height: 24px; + } + .attributes-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; + background: none; + color: $color-gray-20; + border: none; + border-bottom: 1px solid $color-gray-30; + padding: 0 1rem 0.25rem 0.25rem; + margin-top: 2px; + background-image: url("/images/icons/arrow-down-white.svg"); + background-repeat: no-repeat; + background-position: 95% 48%; + background-size: 10px; + cursor: pointer; + + option { + padding: 1rem; + background-color: $color-gray-50; + border: none; + } + } + } + + .attributes-content-row { + position: relative; + margin: 0.5rem; + width: calc(100% - 1rem); + + .attributes-content { + overflow-y: auto; + max-height: 10rem; + background: $color-gray-60; + border-radius: 4px; + padding: 1rem 0.5rem; + color: $color-gray-10; + white-space: pre-wrap; + } + } + + .attributes-image-row { + position: relative; + display: flex; + padding: 0.25rem; + align-items: center; + justify-content: center; + margin: 0.5rem; + background: $color-gray-60; + border-radius: 4px; + + width: calc(100% - 1rem); + min-height: 5rem; + img { + max-height: 8rem; + width: auto; + } + } + + .attributes-shadow-row { + position: relative; + display: flex; + margin: 0.5rem; + padding-right: 2rem; + justify-content: space-between; + + & > :first-child { + color: $color-gray-10; + } + + .attributes-shadow { + display: flex; + + .attributes-label { + margin-right: 2px; + } + } + } + + .attributes-stroke-row { + position: relative; + display: flex; + margin: 0.5rem; + padding-right: 2rem; + justify-content: space-between; + } + + .download-button { + display: block; + text-align: center; + border: 1px solid $color-gray-60; + background-color: $color-gray-60; + padding: 0.5rem 1rem; + color: $color-gray-10; + width: calc(100% - 1rem); + border-radius: 4px; + margin: 0.5rem; + cursor: pointer; + + &:hover { + background-color: $color-primary; + color: $color-black; + } + } + + .attributes-block-title, + .attributes-unit-row, + .attributes-color-row, + .attributes-shadow-row, + .attributes-stroke-row { + &:hover .attributes-copy-button { + visibility: visible; + opacity: 1; + } + } + +} diff --git a/frontend/src/app/main/data/viewer.cljs b/frontend/src/app/main/data/viewer.cljs index c98b1d1b9..ef51b5068 100644 --- a/frontend/src/app/main/data/viewer.cljs +++ b/frontend/src/app/main/data/viewer.cljs @@ -93,12 +93,13 @@ (update [_ state] (let [objects (:objects page) frames (extract-frames objects)] - (assoc state :viewer-data {:project project - :objects objects - :file file - :page page - :frames frames - :share-token share-token}))))) + (-> state + (assoc :viewer-data {:project project + :objects objects + :file file + :page page + :frames frames + :share-token share-token})))))) (def create-share-link (ptk/reify ::create-share-link diff --git a/frontend/src/app/main/ui/components/color_bullet.cljs b/frontend/src/app/main/ui/components/color_bullet.cljs index 017eec05f..d4f774674 100644 --- a/frontend/src/app/main/ui/components/color_bullet.cljs +++ b/frontend/src/app/main/ui/components/color_bullet.cljs @@ -36,7 +36,7 @@ (let [color (if (string? color) {:color color :opacity 1} color) {:keys [name color opacity gradient]} color color-str (or name color (gradient-type->string (:type gradient)))] - (when (= size :big) + (when (or (not size) (= size :big)) [:span.color-text {:on-click #(when on-click (on-click %)) :on-double-click #(when on-double-click (on-double-click %)) :title name } color-str]))) diff --git a/frontend/src/app/main/ui/viewer/handoff.cljs b/frontend/src/app/main/ui/viewer/handoff.cljs index 70371fa4b..8875df8c9 100644 --- a/frontend/src/app/main/ui/viewer/handoff.cljs +++ b/frontend/src/app/main/ui/viewer/handoff.cljs @@ -43,6 +43,12 @@ frames (:frames data []) objects (:objects data) frame (get frames index)] + + (mf/use-effect + (mf/deps index) + (fn [] + (st/emit! (dv/select-shape (:id frame))))) + [:section.viewer-preview (cond (empty? frames) @@ -60,7 +66,7 @@ [:& render-frame-svg {:frame-id (:id frame) :zoom (:zoom local) :objects objects}]] - [:& attributes-sidebar]])])) + [:& attributes-sidebar {:frame frame}]])])) (mf/defc handoff-content [{:keys [data local index] :as props}] diff --git a/frontend/src/app/main/ui/viewer/handoff/attrib_panel.cljs b/frontend/src/app/main/ui/viewer/handoff/attrib_panel.cljs new file mode 100644 index 000000000..20aa9df7c --- /dev/null +++ b/frontend/src/app/main/ui/viewer/handoff/attrib_panel.cljs @@ -0,0 +1,248 @@ +;; 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/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns app.main.ui.viewer.handoff.attrib-panel + (:require + [rumext.alpha :as mf] + [cuerdas.core :as str] + [app.config :as cfg] + [app.util.i18n :refer [locale t]] + [app.common.geom.shapes :as gsh] + [app.common.math :as mth] + [app.main.ui.icons :as i] + [app.util.color :as uc] + [app.util.text :as ut] + [app.main.fonts :as fonts] + [app.main.ui.components.color-bullet :refer [color-bullet color-name]])) + +(mf/defc color-row [{:keys [color]}] + (let [locale (mf/deref locale)] + [:div.attributes-color-row + [:& color-bullet {:color color}] + + [:* + [:& color-name {:color color}] + (when-not (:gradient color) [:div (str (* 100 (:opacity color)) "%")])] + + [:select + [:option (t locale "handoff.attributes.color.hex")] + [:option (t locale "handoff.attributes.color.rgba")] + [:option (t locale "handoff.attributes.color.hsla")]] + + [:button.attributes-copy-button i/copy]])) + +(mf/defc layout-panel + [{:keys [shape locale]}] + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text (t locale "handoff.attributes.layout")] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.layout.width")] + [:div.attributes-value (mth/precision (:width shape) 2) "px"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.layout.height")] + [:div.attributes-value (mth/precision (:height shape) 2) "px"] + [:button.attributes-copy-button i/copy]] + + (when (not= (:x shape) 0) + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.layout.left")] + [:div.attributes-value (mth/precision (:x shape) 2) "px"] + [:button.attributes-copy-button i/copy]]) + + (when (not= (:y shape) 0) + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.layout.top")] + [:div.attributes-value (mth/precision (:y shape) 2) "px"] + [:button.attributes-copy-button i/copy]]) + + (when (not= (:rotation shape) 0) + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.layout.rotation")] + [:div.attributes-value (mth/precision (:rotation shape) 2) "deg"] + [:button.attributes-copy-button i/copy]])]) + +(mf/defc fill-panel + [{:keys [shape locale]}] + (let [{:keys [fill-color fill-opacity fill-color-gradient fill-ref-id fill-ref-file-id]} shape] + (when (or fill-color fill-color-gradient) + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text (t locale "handoff.attributes.fill")] + [:button.attributes-copy-button i/copy]] + + (let [color {:color fill-color + :opacity fill-opacity + :gradient fill-color-gradient + :id fill-ref-id + :file-id fill-ref-file-id}] + [:& color-row {:color color}])]))) + +(mf/defc stroke-panel + [{:keys [shape locale]}] + (when (and (:stroke-style shape) (not= (:stroke-style shape) :none)) + (let [{:keys [stroke-style stroke-alignment stroke-width + stroke-color stroke-opacity stroke-color-gradient + stroke-color-ref-id stroke-color-file-id]} shape + color {:color stroke-color + :opacity stroke-opacity + :gradient stroke-color-gradient + :id stroke-color-ref-id + :file-id stroke-color-file-id}] + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text (t locale "handoff.attributes.stroke")] + [:button.attributes-copy-button i/copy]] + + [:& color-row {:color color}] + + [:div.attributes-stroke-row + [:div.attributes-label (t locale "handoff.attributes.stroke.width")] + [:div.attributes-value (str stroke-width) "px"] + [:div.attributes-value (->> stroke-style name (str "handoff.attributes.stroke.style.") (t locale))] + [:div.attributes-label (->> stroke-alignment name (str "handoff.attributes.stroke.alignment.") (t locale))] + [:button.attributes-copy-button i/copy]]]))) + +(mf/defc shadow-panel [{:keys [shape locale]}] + (when (seq (:shadow shape)) + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text (t locale "handoff.attributes.shadow")] + [:button.attributes-copy-button i/copy]] + + (for [shadow (:shadow shape)] + (do + (prn "???" (:spread shadow)) + [:* + [:div.attributes-shadow-row + [:div.attributes-label (->> shadow :style name (str "handoff.attributes.shadow.style.") (t locale))] + [:div.attributes-shadow + [:div.attributes-label (t locale "handoff.attributes.shadow.shorthand.offset-x")] + [:div.attributes-value (str (:offset-x shadow))]] + + [:div.attributes-shadow + [:div.attributes-label (t locale "handoff.attributes.shadow.shorthand.offset-y")] + [:div.attributes-value (str (:offset-y shadow))]] + + [:div.attributes-shadow + [:div.attributes-label (t locale "handoff.attributes.shadow.shorthand.blur")] + [:div.attributes-value (str (:blur shadow))]] + + [:div.attributes-shadow + [:div.attributes-label (t locale "handoff.attributes.shadow.shorthand.spread")] + [:div.attributes-value (str (:spread shadow))]] + + [:button.attributes-copy-button i/copy]] + [:& color-row {:color (:color shadow)}]]))])) + +(mf/defc blur-panel [{:keys [shape locale]}] + (when (:blur shape) + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text (t locale "handoff.attributes.blur")] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.blur.value")] + [:div.attributes-value (-> shape :blur :value) "px"] + [:button.attributes-copy-button i/copy]]])) + +(mf/defc image-panel [{:keys [shape locale]}] + [:div.attributes-block + [:div.attributes-image-row + [:div.attributes-image + [:img {:src (cfg/resolve-media-path (-> shape :metadata :path))}]]] + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.image.width")] + [:div.attributes-value (-> shape :metadata :width) "px"]] + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.image.height")] + [:div.attributes-value (-> shape :metadata :height) "px"]] + (let [filename (last (str/split (-> shape :metadata :path) "/"))] + [:a.download-button {:target "_blank" + :download filename + :href (cfg/resolve-media-path (-> shape :metadata :path))} + (t locale "handoff.attributes.image.download")])]) + +(mf/defc typography-panel [{:keys [shape locale]}] + (let [font (ut/search-text-attrs (:content shape) + (keys ut/default-text-attrs)) + font (merge ut/default-text-attrs font)] + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text (t locale "handoff.attributes.typography")] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.typography.font-family")] + [:div.attributes-value (-> font :font-id fonts/get-font-data :name)] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.typography.font-style")] + [:div.attributes-value (str (:font-style font))] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.typography.font-size")] + [:div.attributes-value (str (:font-size font)) "px"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.typography.line-height")] + [:div.attributes-value (str (:line-height font)) "px"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.typography.letter-spacing")] + [:div.attributes-value (str (:letter-spacing font)) "px"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.typography.text-decoration")] + [:div.attributes-value (->> font :text-decoration (str "handoff.attributes.typography.text-decoration.") (t locale))] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label (t locale "handoff.attributes.typography.text-transform")] + [:div.attributes-value (->> font :text-transform (str "handoff.attributes.typography.text-transform.") (t locale))] + [:button.attributes-copy-button i/copy]]])) + +(mf/defc content-panel [{:keys [shape locale]}] + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text (t locale "handoff.attributes.content")] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-content-row + [:pre.attributes-content (ut/content->text (:content shape))] + [:button.attributes-copy-button i/copy]]]) + +(mf/defc attrib-panel [{:keys [shape frame options]}] + (let [locale (mf/deref locale)] + [:div.element-options + (for [option options] + [:> + (case option + :layout layout-panel + :fill fill-panel + :stroke stroke-panel + :shadow shadow-panel + :blur blur-panel + :image image-panel + :typography typography-panel + :content content-panel + ) + {:shape (gsh/translate-to-frame shape frame) + :frame frame + :locale locale}])])) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs new file mode 100644 index 000000000..2098f602b --- /dev/null +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs @@ -0,0 +1,110 @@ +;; 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/. +;; +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL + +(ns app.main.ui.viewer.handoff.attributes.layout + (:require + [rumext.alpha :as mf] + [app.main.ui.icons :as i] + [app.main.ui.components.color-bullet :refer [color-bullet color-name]])) + + +(mf/defc layout-panel [{:keys [shapes]}] + (prn "???" shapes) + [:* + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text "Layout"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label "Width"] + [:div.attributes-value "100px"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label "Height"] + [:div.attributes-value "100px"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label "Top"] + [:div.attributes-value "100px"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-unit-row + [:div.attributes-label "Left"] + [:div.attributes-value "100px"] + [:button.attributes-copy-button i/copy]]] + + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text "Fill"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-shadow-row + [:div.attributes-label "Drop"] + [:div.attributes-shadow + [:div.attributes-label "X"] + [:div.attributes-value "4"]] + + [:div.attributes-shadow + [:div.attributes-label "Y"] + [:div.attributes-value "4"]] + + [:div.attributes-shadow + [:div.attributes-label "B"] + [:div.attributes-value "0"]] + + [:div.attributes-shadow + [:div.attributes-label "B"] + [:div.attributes-value "0"]] + + [:button.attributes-copy-button i/copy]] + + [:div.attributes-color-row + [:& color-bullet {:color {:color "#000000" :opacity 0.5}}] + + [:* + [:div "#000000"] + [:div "100%"]] + + [:select + [:option "Hex"] + [:option "RGBA"] + [:option "HSLA"]] + + [:button.attributes-copy-button i/copy]] + + [:div.attributes-stroke-row + [:div.attributes-label "Width"] + [:div.attributes-value "1px"] + [:div.attributes-value "Solid"] + [:div.attributes-label "Center"] + [:button.attributes-copy-button i/copy]]] + + [:div.attributes-block + [:div.attributes-block-title + [:div.attributes-block-title-text "Content"] + [:button.attributes-copy-button i/copy]] + + [:div.attributes-content-row + [:div.attributes-content + "Hi, how are you"] + [:button.attributes-copy-button i/copy]]] + + [:div.attributes-block + [:div.attributes-image-row + [:div.attributes-image + #_[:img {:src "https://www.publico.es/tremending/wp-content/uploads/2019/05/Cxagv.jpg"}] + #_[:img {:src "https://i.blogs.es/3861b2/grumpy-cat/1366_2000.png"}] + [:img {:src "https://abs.twimg.com/favicons/twitter.ico"}] + ]] + [:button.download-button "Dowload source image"]] + + ]) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes_sidebar.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes_sidebar.cljs index dd93c613a..11ecb2797 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes_sidebar.cljs @@ -10,16 +10,48 @@ (ns app.main.ui.viewer.handoff.attributes-sidebar (:require [rumext.alpha :as mf] + [okulary.core :as l] + [app.main.store :as st] [app.main.ui.icons :as i] - [app.main.ui.components.tab-container :refer [tab-container tab-element]])) + [app.main.ui.components.tab-container :refer [tab-container tab-element]] + [app.main.ui.viewer.handoff.attrib-panel :refer [attrib-panel]])) -(mf/defc info-panel [] - [:div.element-options]) +(defn make-selected-shapes-iref + [] + (let [selected->shapes + (fn [state] + (let [selected (get-in state [:viewer-local :selected]) + objects (get-in state [:viewer-data :page :objects]) + resolve-shape #(get objects %)] + (mapv resolve-shape selected)))] + #(l/derived selected->shapes st/state))) + +(mf/defc info-panel [{:keys [frame]}] + (let [selected-ref (mf/use-memo (make-selected-shapes-iref)) + shapes (mf/deref selected-ref)] + (if (> (count shapes) 1) + ;; Multiple selection + nil + ;; Single shape + (when-let [shape (first shapes)] + (let [options + (case (:type shape) + :frame [:layout :fill] + :group [:layout] + :rect [:layout :fill :stroke :shadow :blur] + :circle [:layout :fill :stroke :shadow :blur] + :path [:layout :fill :stroke :shadow :blur] + :curve [:layout :fill :stroke :shadow :blur] + :image [:image :layout :shadow :blur] + :text [:layout :fill :typography :content :shadow :blur])] + [:& attrib-panel {:frame frame + :shape shape + :options options}]))))) (mf/defc code-panel [] [:div.element-options]) -(mf/defc attributes-sidebar [] +(mf/defc attributes-sidebar [{:keys [frame]}] (let [section (mf/use-state :info #_:code)] [:aside.settings-bar.settings-bar-right [:div.settings-bar-inside @@ -31,8 +63,7 @@ [:& tab-container {:on-change-tab #(reset! section %) :selected @section} [:& tab-element {:id :info :title "Info"} - [:& info-panel]] + [:& info-panel {:frame frame}]] [:& tab-element {:id :code :title "Code"} [:& code-panel]]]]]]])) - diff --git a/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs b/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs index a3725b8d2..44fdd6ffa 100644 --- a/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs @@ -46,7 +46,7 @@ (let [hover (get-in state [:viewer-local :hover]) objects (get-in state [:viewer-data :page :objects]) resolve-shape #(get objects %)] - (map resolve-shape hover)))] + (mapv resolve-shape hover)))] #(l/derived hover->shapes st/state))) (mf/defc selection-feedback [{:keys [frame]}] diff --git a/frontend/src/app/util/text.cljs b/frontend/src/app/util/text.cljs index 4adea0fb3..4ba1d4e96 100644 --- a/frontend/src/app/util/text.cljs +++ b/frontend/src/app/util/text.cljs @@ -1,4 +1,6 @@ -(ns app.util.text) +(ns app.util.text + (:require + [cuerdas.core :as str])) (defonce default-text-attrs {:font-id "sourcesanspro" @@ -11,7 +13,9 @@ :letter-spacing "0" :text-transform "none" :text-align "left" - :text-decoration "none"}) + :text-decoration "none" + :fill-color "#000000" + :fill-opacity 1}) (def typography-fields [:font-id @@ -38,3 +42,20 @@ [map-fn node] (cond-> (map-fn node) (:children node) (update :children (fn [children] (mapv #(map-node map-fn %) children))))) + +(defn content->text + [node] + (str + (if (:children node) + (str/join (if (= "paragraph-set" (:type node)) "\n" "") (map content->text (:children node))) + (:text node "")))) + +(defn search-text-attrs + [node attrs] + + (let [rec-fn + (fn rec-fn [current node] + (let [current (reduce rec-fn current (:children node []))] + (merge current + (select-keys node attrs))))] + (rec-fn {} node)))