mirror of
https://github.com/penpot/penpot.git
synced 2025-03-11 23:31:21 -05:00
✨ Adds copy properties.
This commit is contained in:
parent
1e48221d7b
commit
d6573c2bcc
9 changed files with 454 additions and 166 deletions
|
@ -3366,6 +3366,16 @@
|
|||
"handoff.tabs.info": "Info",
|
||||
"handoff.tabs.code": "Code",
|
||||
|
||||
"handoff.tabs.code.selected.frame": "Artboard",
|
||||
"handoff.tabs.code.selected.group": "Group",
|
||||
"handoff.tabs.code.selected.rect": "Rectangle",
|
||||
"handoff.tabs.code.selected.circle": "Circle",
|
||||
"handoff.tabs.code.selected.path": "Path",
|
||||
"handoff.tabs.code.selected.curve": "Curve",
|
||||
"handoff.tabs.code.selected.image": "Image",
|
||||
"handoff.tabs.code.selected.text": "Text",
|
||||
"handoff.tabs.code.selected.multiple": "%s Selected",
|
||||
|
||||
"handoff.attributes.color.hex": "HEX",
|
||||
"handoff.attributes.color.rgba": "RGBA",
|
||||
"handoff.attributes.color.hsla": "HSLA",
|
||||
|
|
|
@ -22,6 +22,14 @@
|
|||
padding-bottom: 0.5rem;
|
||||
font-size: $fs12;
|
||||
|
||||
.attributes-text-block {
|
||||
border-bottom: 1px solid $color-gray-60;
|
||||
}
|
||||
|
||||
& :last-child{
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.attributes-copy-button {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
@ -139,13 +147,18 @@
|
|||
|
||||
.attributes-content {
|
||||
overflow-y: auto;
|
||||
max-height: 10rem;
|
||||
max-height: 5rem;
|
||||
background: $color-gray-60;
|
||||
border-radius: 4px;
|
||||
padding: 1rem 0.5rem;
|
||||
color: $color-gray-10;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.attributes-copy-button {
|
||||
padding: 0.5rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.attributes-image-row {
|
||||
|
@ -194,6 +207,16 @@
|
|||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.attributes-typography-row {
|
||||
position: relative;
|
||||
margin: 0.5rem;
|
||||
padding-right: 2rem;
|
||||
|
||||
.typography-sample {
|
||||
font-size: $fs16;
|
||||
}
|
||||
}
|
||||
|
||||
.download-button {
|
||||
display: block;
|
||||
text-align: center;
|
||||
|
@ -216,7 +239,9 @@
|
|||
.attributes-unit-row,
|
||||
.attributes-color-row,
|
||||
.attributes-shadow-row,
|
||||
.attributes-stroke-row {
|
||||
.attributes-stroke-row,
|
||||
.attributes-typography-row,
|
||||
.attributes-content-row {
|
||||
&:hover .attributes-copy-button {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
|
|
|
@ -77,6 +77,13 @@
|
|||
(let [page-id (get @state :current-page-id)]
|
||||
(logjs "state" (get-in @state [:workspace-data :pages-index page-id :objects]))))
|
||||
|
||||
(defn ^:export dump-object [name]
|
||||
(let [page-id (get @state :current-page-id)]
|
||||
(let [objects (get-in @state [:workspace-data :pages-index page-id :objects])
|
||||
target (d/seek (fn [[id shape]] (= name (:name shape))) objects)]
|
||||
(->> target
|
||||
(logjs "state")))))
|
||||
|
||||
(defn ^:export dump-tree
|
||||
([] (dump-tree false))
|
||||
([show-touched]
|
||||
|
|
|
@ -12,150 +12,271 @@
|
|||
[rumext.alpha :as mf]
|
||||
[cuerdas.core :as str]
|
||||
[app.config :as cfg]
|
||||
[app.util.data :as d]
|
||||
[app.util.dom :as dom]
|
||||
[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.common.math :as mth]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.main.fonts :as fonts]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.webapi :as wapi]
|
||||
[app.main.ui.components.color-bullet :refer [color-bullet color-name]]))
|
||||
|
||||
(mf/defc color-row [{:keys [color]}]
|
||||
(defn copy-cb [values properties & {:keys [to-prop format] :or {to-prop {}}}]
|
||||
(fn [event]
|
||||
(let [
|
||||
;; We allow the :format and :to-prop to be a map for different properties
|
||||
;; or just a value for a single property. This code transform a single
|
||||
;; property to a uniform one
|
||||
properties (if-not (coll? properties) [properties] properties)
|
||||
|
||||
format (if (not (map? format))
|
||||
(into {} (map #(vector % format) properties))
|
||||
format)
|
||||
|
||||
to-prop (if (not (map? to-prop))
|
||||
(into {} (map #(vector % to-prop) properties))
|
||||
to-prop)
|
||||
|
||||
default-format (fn [value] (str (mth/precision value 2) "px"))
|
||||
format-property (fn [prop]
|
||||
(let [css-prop (or (prop to-prop) (name prop))]
|
||||
(str/fmt " %s: %s;" css-prop ((or (prop format) default-format) (prop values) values))))
|
||||
|
||||
text-props (->> properties
|
||||
(remove #(let [value (get values %)]
|
||||
(or (nil? value) (= value 0))))
|
||||
(map format-property)
|
||||
(str/join "\n"))
|
||||
|
||||
result (str/fmt "{\n%s\n}" text-props)]
|
||||
|
||||
(wapi/write-to-clipboard result))))
|
||||
|
||||
|
||||
(mf/defc color-row [{:keys [color format on-copy on-change-format]}]
|
||||
(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")]]
|
||||
(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)) "%")])]))
|
||||
|
||||
[:button.attributes-copy-button i/copy]]))
|
||||
(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 "rgba"}
|
||||
(t locale "handoff.attributes.color.rgba")]
|
||||
|
||||
[:option {:value "hsla"}
|
||||
(t locale "handoff.attributes.color.hsla")]])
|
||||
|
||||
(when on-copy
|
||||
[:button.attributes-copy-button {:on-click on-copy} 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]]
|
||||
[:button.attributes-copy-button
|
||||
{:on-click (copy-cb shape
|
||||
[:width :height :x :y :rotation]
|
||||
:to-prop {:x "left" :y "top" :rotation "transform"}
|
||||
:format {:rotation #(str/fmt "rotate(%sdeg)" %)})}
|
||||
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]]
|
||||
[:button.attributes-copy-button
|
||||
{:on-click (copy-cb shape :width)}
|
||||
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]]
|
||||
[:button.attributes-copy-button
|
||||
{:on-click (copy-cb shape :height)}
|
||||
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]])
|
||||
[:button.attributes-copy-button
|
||||
{:on-click (copy-cb shape :x :to-prop "left")}
|
||||
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]])
|
||||
[:button.attributes-copy-button
|
||||
{:on-click (copy-cb shape :y :to-prop "top")}
|
||||
i/copy]])
|
||||
|
||||
(when (not= (:rotation shape) 0)
|
||||
(when (not= (:rotation shape 0) 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]])])
|
||||
[:button.attributes-copy-button
|
||||
{:on-click (copy-cb shape
|
||||
:rotation
|
||||
:to-prop "transform"
|
||||
:format #(str/fmt "rotate(%sdeg)" %))}
|
||||
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)
|
||||
(let [color-format (mf/use-state :hex)
|
||||
color {: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)}
|
||||
|
||||
handle-copy (copy-cb shape
|
||||
[:fill-color :fill-color-gradient]
|
||||
:to-prop "background"
|
||||
:format #(uc/color->background color))]
|
||||
|
||||
(when (or (:color color) (:gradient color))
|
||||
[:div.attributes-block
|
||||
[:div.attributes-block-title
|
||||
[:div.attributes-block-title-text (t locale "handoff.attributes.fill")]
|
||||
[:button.attributes-copy-button i/copy]]
|
||||
[:button.attributes-copy-button
|
||||
{:on-click handle-copy}
|
||||
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}])])))
|
||||
[:& color-row {:color color
|
||||
:format @color-format
|
||||
:on-change-format #(reset! color-format %)
|
||||
:on-copy handle-copy}]])))
|
||||
|
||||
(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}]
|
||||
(let [color-format (mf/use-state :hex)
|
||||
color {:color (:stroke-color shape)
|
||||
:opacity (:stroke-opacity shape)
|
||||
:gradient (:stroke-color-gradient shape)
|
||||
:id (:stroke-color-ref-id shape)
|
||||
:file-id (:stroke-color-file-id shape)}
|
||||
|
||||
handle-copy-stroke (copy-cb shape
|
||||
:stroke-style
|
||||
:to-prop "border"
|
||||
:format #(let [width (:stroke-width %2)
|
||||
style (name (:stroke-style %2))
|
||||
color (uc/color->background color)]
|
||||
(str/format "%spx %s %s" width style color)))]
|
||||
|
||||
(when (and (:stroke-style shape) (not= (:stroke-style shape) :none))
|
||||
[:div.attributes-block
|
||||
[:div.attributes-block-title
|
||||
[:div.attributes-block-title-text (t locale "handoff.attributes.stroke")]
|
||||
[:button.attributes-copy-button i/copy]]
|
||||
[:button.attributes-copy-button
|
||||
{:on-click handle-copy-stroke} i/copy]]
|
||||
|
||||
[:& color-row {:color color}]
|
||||
[:& color-row {:color color
|
||||
:format @color-format
|
||||
:on-change-format #(reset! color-format %)
|
||||
:on-copy (copy-cb shape
|
||||
:stroke-color
|
||||
:to-prop "border-color"
|
||||
:format #(uc/color->background 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]]])))
|
||||
[:div.attributes-value (:stroke-width shape) "px"]
|
||||
[:div.attributes-value (->> shape :stroke-style name (str "handoff.attributes.stroke.style.") (t locale))]
|
||||
[:div.attributes-label (->> shape :stroke-alignment name (str "handoff.attributes.stroke.alignment.") (t locale))]
|
||||
[:button.attributes-copy-button
|
||||
{:on-click handle-copy-stroke} i/copy]]])))
|
||||
|
||||
(defn shadow->css [shadow]
|
||||
(let [{:keys [style offset-x offset-y blur spread]} shadow
|
||||
css-color (uc/color->background (:color shadow))]
|
||||
(str
|
||||
(if (= style :inner-shadow) "inset " "")
|
||||
(str/fmt "%spx %spx %spx %spx %s" offset-x offset-y blur spread css-color))))
|
||||
|
||||
(mf/defc shadow-block [{:keys [shape locale shadow]}]
|
||||
(let [color-format (mf/use-state :hex)]
|
||||
[:div.attributes-shadow-block
|
||||
[: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
|
||||
{:on-click (copy-cb shadow
|
||||
:style
|
||||
:to-prop "box-shadow"
|
||||
:format #(shadow->css shadow))}
|
||||
i/copy]]
|
||||
[:& color-row {:color (:color shadow)
|
||||
:format @color-format
|
||||
:on-change-format #(reset! color-format %)}]]))
|
||||
|
||||
(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]]
|
||||
[:button.attributes-copy-button
|
||||
{:on-click (copy-cb shape
|
||||
:shadow
|
||||
:to-prop "box-shadow"
|
||||
:format #(str/join ", " (map shadow->css (:shadow shape))))}
|
||||
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)}]]))]))
|
||||
[:& shadow-block {:shape shape
|
||||
:locale locale
|
||||
:shadow 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]]
|
||||
(let [handle-copy
|
||||
(copy-cb shape
|
||||
:blur
|
||||
:to-prop "filter"
|
||||
:format #(str/fmt "blur(%spx)" %))]
|
||||
(when (:blur shape)
|
||||
[:div.attributes-block
|
||||
[:div.attributes-block-title
|
||||
[:div.attributes-block-title-text (t locale "handoff.attributes.blur")]
|
||||
[:button.attributes-copy-button {:on-click handle-copy} 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]]]))
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.blur.value")]
|
||||
[:div.attributes-value (-> shape :blur :value) "px"]
|
||||
[:button.attributes-copy-button {:on-click handle-copy} i/copy]]])))
|
||||
|
||||
(mf/defc image-panel [{:keys [shape locale]}]
|
||||
[:div.attributes-block
|
||||
|
@ -163,70 +284,143 @@
|
|||
[: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-label (t locale "handoff.attributes.image.width")]
|
||||
[:div.attributes-value (-> shape :metadata :width) "px"]
|
||||
[:button.attributes-copy-button {:on-click (copy-cb shape :width)} i/copy]]
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.image.height")]
|
||||
[:div.attributes-value (-> shape :metadata :height) "px"]]
|
||||
[:div.attributes-label (t locale "handoff.attributes.image.height")]
|
||||
[:div.attributes-value (-> shape :metadata :height) "px"]
|
||||
[:button.attributes-copy-button {:on-click (copy-cb shape :height)} i/copy]]
|
||||
(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 text-block [{:keys [shape locale text style full-style]}]
|
||||
(let [color-format (mf/use-state :hex)
|
||||
color {:color (:fill-color style)
|
||||
:opacity (:fill-opacity style)
|
||||
:gradient (:fill-color-gradient style)
|
||||
:id (:fill-color-ref-id style)
|
||||
:file-id (:fill-color-ref-file-id style)}
|
||||
properties [:fill-color
|
||||
:fill-color-gradient
|
||||
:font-family
|
||||
:font-style
|
||||
:font-size
|
||||
:line-height
|
||||
:letter-spacing
|
||||
:text-decoration
|
||||
:text-transform]
|
||||
format {:font-family identity
|
||||
:font-style identity
|
||||
:font-size #(str % "px")
|
||||
:line-height #(str % "px")
|
||||
:letter-spacing #(str % "px")
|
||||
:text-decoration name
|
||||
:text-transform name
|
||||
:fill-color #(uc/color->background color)
|
||||
:fill-color-gradient #(uc/color->background color)}
|
||||
to-prop {:fill-color "color"
|
||||
:fill-color-gradient "color"}]
|
||||
[: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")]
|
||||
[:button.attributes-copy-button
|
||||
{:on-click (copy-cb style properties :to-prop to-prop :format format)} i/copy]]
|
||||
|
||||
[:div.attributes-content-row
|
||||
[:pre.attributes-content (str/trim text)]
|
||||
[:button.attributes-copy-button
|
||||
{:on-click #(wapi/write-to-clipboard (str/trim text))}
|
||||
i/copy]]
|
||||
|
||||
(when (or (:fill-color style) (:fill-color-gradient style))
|
||||
(let [color {:color (:fill-color style)
|
||||
:opacity (:fill-opacity style)
|
||||
:gradient (:fill-color-gradient style)
|
||||
:id (:fill-ref-id style)
|
||||
:file-id (:fill-ref-file-id style)}]
|
||||
[:& color-row {:format @color-format
|
||||
:on-change-format #(reset! color-format %)
|
||||
:color color
|
||||
:on-copy (copy-cb style [:fill-color :fill-color-gradient] :to-prop to-prop :format format)}]))
|
||||
|
||||
(when (:font-id style)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.typography.font-family")]
|
||||
[:div.attributes-value (-> style :font-id fonts/get-font-data :name)]
|
||||
[:button.attributes-copy-button {:on-click (copy-cb style :font-family :format identity)} i/copy]])
|
||||
|
||||
(when (:font-style style)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.typography.font-style")]
|
||||
[:div.attributes-value (str (:font-style style))]
|
||||
[:button.attributes-copy-button {:on-click (copy-cb style :font-style :format identity)} i/copy]])
|
||||
|
||||
(when (:font-size style)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.typography.font-size")]
|
||||
[:div.attributes-value (str (:font-size style)) "px"]
|
||||
[:button.attributes-copy-button {:on-click (copy-cb style :font-size :format #(str % "px"))} i/copy]])
|
||||
|
||||
(when (:line-height style)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.typography.line-height")]
|
||||
[:div.attributes-value (str (:line-height style)) "px"]
|
||||
[:button.attributes-copy-button {:on-click (copy-cb style :line-height :format #(str % "px"))} i/copy]])
|
||||
|
||||
(when (:letter-spacing style)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.typography.letter-spacing")]
|
||||
[:div.attributes-value (str (:letter-spacing style)) "px"]
|
||||
[:button.attributes-copy-button {:on-click (copy-cb style :letter-spacing :format #(str % "px"))} i/copy]])
|
||||
|
||||
(when (:text-decoration style)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.typography.text-decoration")]
|
||||
[:div.attributes-value (->> style :text-decoration (str "handoff.attributes.typography.text-decoration.") (t locale))]
|
||||
[:button.attributes-copy-button {:on-click (copy-cb style :text-decoration :format name)} i/copy]])
|
||||
|
||||
(when (:text-transform style)
|
||||
[:div.attributes-unit-row
|
||||
[:div.attributes-label (t locale "handoff.attributes.typography.text-transform")]
|
||||
[:div.attributes-value (->> style :text-transform (str "handoff.attributes.typography.text-transform.") (t locale))]
|
||||
[:button.attributes-copy-button {:on-click (copy-cb style :text-transform :format name)} i/copy]])]))
|
||||
|
||||
(mf/defc typography-panel [{: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))))
|
||||
(mapv (fn [[style text]] (vector (merge ut/default-text-attrs style) text))))
|
||||
|
||||
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-block-title-text (t locale "handoff.attributes.typography")]]
|
||||
|
||||
[: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]]
|
||||
(for [[idx [full-style text]] (map-indexed vector style-text-blocks)]
|
||||
(let [previus-style (first (nth style-text-blocks (dec idx) nil))
|
||||
style (d/remove-equal-values full-style previus-style)
|
||||
|
||||
[: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]]])
|
||||
;; If the color is set we need to add opacity otherwise the display will not work
|
||||
style (cond-> style
|
||||
(:fill-color style)
|
||||
(assoc :fill-opacity (:fill-opacity full-style)))]
|
||||
[:& text-block {:shape shape
|
||||
:locale locale
|
||||
:full-style full-style
|
||||
:style style
|
||||
:text text}]))]))
|
||||
|
||||
(mf/defc attrib-panel [{:keys [shape frame options]}]
|
||||
(let [locale (mf/deref locale)]
|
||||
|
@ -240,9 +434,7 @@
|
|||
:shadow shadow-panel
|
||||
:blur blur-panel
|
||||
:image image-panel
|
||||
:typography typography-panel
|
||||
:content content-panel
|
||||
)
|
||||
:typography typography-panel)
|
||||
{:shape (gsh/translate-to-frame shape frame)
|
||||
:frame frame
|
||||
:locale locale}])]))
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
|
||||
(mf/defc layout-panel [{:keys [shapes]}]
|
||||
(prn "???" shapes)
|
||||
[:*
|
||||
[:div.attributes-block
|
||||
[:div.attributes-block-title
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[okulary.core :as l]
|
||||
[app.util.i18n :refer [t] :as i18n]
|
||||
[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.viewer.handoff.attrib-panel :refer [attrib-panel]]))
|
||||
[app.main.ui.viewer.handoff.attrib-panel :refer [attrib-panel]]
|
||||
[app.main.ui.workspace.sidebar.layers :refer [element-icon]]))
|
||||
|
||||
(defn make-selected-shapes-iref
|
||||
[]
|
||||
|
@ -26,44 +28,54 @@
|
|||
(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 info-panel [{:keys [frame shapes]}]
|
||||
(if (> (count shapes) 1)
|
||||
;; TODO: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 :typography :shadow :blur])]
|
||||
[:& attrib-panel {:frame frame
|
||||
:shape shape
|
||||
:options options}]))))
|
||||
|
||||
(mf/defc code-panel []
|
||||
[:div.element-options])
|
||||
|
||||
(mf/defc attributes-sidebar [{:keys [frame]}]
|
||||
(let [section (mf/use-state :info #_:code)]
|
||||
(let [locale (mf/deref i18n/locale)
|
||||
section (mf/use-state :info #_:code)
|
||||
selected-ref (mf/use-memo (make-selected-shapes-iref))
|
||||
shapes (mf/deref selected-ref)]
|
||||
[:aside.settings-bar.settings-bar-right
|
||||
[:div.settings-bar-inside
|
||||
[:div.tool-window
|
||||
[:div.tool-window-bar.big
|
||||
[:span.tool-window-bar-icon i/text]
|
||||
[:span.tool-window-bar-title "Text"]]
|
||||
[:div.tool-window-content
|
||||
[:& tab-container {:on-change-tab #(reset! section %)
|
||||
:selected @section}
|
||||
[:& tab-element {:id :info :title "Info"}
|
||||
[:& info-panel {:frame frame}]]
|
||||
(when (seq shapes)
|
||||
[:div.tool-window
|
||||
[:div.tool-window-bar.big
|
||||
(if (> (count shapes) 1)
|
||||
[:*
|
||||
[:span.tool-window-bar-icon i/layers]
|
||||
[:span.tool-window-bar-title (t locale "handoff.tabs.code.selected.multiple" (count shapes))]]
|
||||
[:*
|
||||
[:span.tool-window-bar-icon
|
||||
[:& element-icon {:shape (-> shapes first)}]]
|
||||
[:span.tool-window-bar-title (->> shapes first :type name (str "handoff.tabs.code.selected.") (t locale))]])
|
||||
]
|
||||
[:div.tool-window-content
|
||||
[:& tab-container {:on-change-tab #(reset! section %)
|
||||
:selected @section}
|
||||
[:& tab-element {:id :info :title (t locale "handoff.tabs.info")}
|
||||
[:& info-panel {:frame frame
|
||||
:shapes shapes}]]
|
||||
|
||||
[:& tab-element {:id :code :title "Code"}
|
||||
[:& code-panel]]]]]]]))
|
||||
[:& tab-element {:id :code :title (t locale "handoff.tabs.code")}
|
||||
[:& code-panel]]]]])]]))
|
||||
|
|
|
@ -53,6 +53,11 @@
|
|||
(into [] (gcolor/hexToHsl hex))
|
||||
(catch :default e [0 0 0])))
|
||||
|
||||
(defn hex->hsla
|
||||
[^string data ^number opacity]
|
||||
(-> (hex->hsl data)
|
||||
(conj opacity)))
|
||||
|
||||
(defn hsl->rgb
|
||||
[[h s l]]
|
||||
(gcolor/hslToRgb h s l))
|
||||
|
|
|
@ -111,6 +111,14 @@
|
|||
not-found))
|
||||
not-found coll)))
|
||||
|
||||
(defn remove-equal-values [m1 m2]
|
||||
(if (and (map? m1) (map? m2) (not (nil? m1)) (not (nil? m2)))
|
||||
(->> m1
|
||||
(remove (fn [[k v]] (= (k m2) v)))
|
||||
(into {}))
|
||||
m1))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Numbers Parsing
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -50,6 +50,36 @@
|
|||
(str/join (if (= "paragraph-set" (:type node)) "\n" "") (map content->text (:children node)))
|
||||
(:text node ""))))
|
||||
|
||||
(defn parse-style-text-blocks
|
||||
[node attrs]
|
||||
(letfn
|
||||
[(rec-style-text-map [acc node style]
|
||||
(let [node-style (merge style (select-keys node attrs))
|
||||
head (or (-> acc first) [{} ""])
|
||||
[head-style head-text] head
|
||||
|
||||
new-acc
|
||||
(cond
|
||||
(:children node)
|
||||
(reduce #(rec-style-text-map %1 %2 node-style) acc (:children node))
|
||||
|
||||
(not= head-style node-style)
|
||||
(cons [node-style (:text node "")] acc)
|
||||
|
||||
:else
|
||||
(cons [node-style (str head-text "" (:text node))] (rest acc)))
|
||||
|
||||
;; We add an end-of-line when finish a paragraph
|
||||
new-acc
|
||||
(if (= (:type node) "paragraph")
|
||||
(let [[hs ht] (first new-acc)]
|
||||
(cons [hs (str ht "\n")] (rest new-acc)))
|
||||
new-acc)]
|
||||
new-acc))]
|
||||
|
||||
(-> (rec-style-text-map [] node {})
|
||||
reverse)))
|
||||
|
||||
(defn search-text-attrs
|
||||
[node attrs]
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue