0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-28 07:31:25 -05:00

Improvements in the handoff

This commit is contained in:
alonso.torres 2020-10-30 14:02:35 +01:00 committed by Hirunatan
parent 7a80297d31
commit 833a53f131
17 changed files with 345 additions and 226 deletions

View file

@ -1,3 +1,5 @@
$width-settings-bar: 16rem;
.handoff-layout {
display: grid;
grid-template-rows: 40px auto;
@ -28,6 +30,42 @@
}
}
.handoff-layout .settings-bar.settings-bar-left {
left: 0;
.handoff-layout {
.viewer-preview {
flex-wrap: nowrap;
}
.settings-bar {
transition: width 0.2s;
&.expanded {
width: $width-settings-bar * 3;
}
&.settings-bar-right,
&.settings-bar-left {
position: relative;
left: unset;
right: unset;
.settings-bar-inside {
padding-top: 0.5rem;
}
}
}
.handoff-svg-wrapper {
flex: 1;
overflow: hidden;
flex-direction: column;
justify-content: flex-start;
}
.handoff-svg-container {
display: grid;
width: 100%;
height: calc(100% - 35px);
overflow: auto;
align-items: center;
justify-content: safe center;
margin: 0 auto;
}
}

View file

@ -15,13 +15,12 @@
justify-content: center;
}
.attributes-copy-button {
.expand-button,
.copy-button {
visibility: hidden;
opacity: 0;
transition: opacity 0.3s;
position: absolute;
right: 0;
top: 0;
background: none;
border: none;
padding: 0;
@ -39,6 +38,19 @@
}
}
.expand-button {
right: 24px;
top: -1px;
svg {
transform: rotate(45deg);
}
}
.copy-button {
right: 0;
top: 0;
}
.attributes-block {
user-select: text;
@ -68,7 +80,7 @@
padding: 0.5rem;
font-size: $fs14;
.attributes-copy-button {
.copy-button {
padding: 0.5rem;
margin-top: 0.25rem;
}
@ -84,7 +96,7 @@
.attributes-value {
width: 50%;
}
.attributes-copy-button {
.copy-button {
padding: 1rem 0.5rem;
margin-top: 0.25rem;
}
@ -111,7 +123,7 @@
border-radius: $br-small;
border: 1px solid $color-gray-60;
}
.attributes-copy-button {
.copy-button {
padding: 1rem 0.5rem;
margin-top: 0.25rem;
}
@ -162,7 +174,7 @@
white-space: pre-wrap;
}
.attributes-copy-button {
.copy-button {
padding: 0.5rem;
margin-top: 0.25rem;
}
@ -249,9 +261,12 @@
.attributes-stroke-row,
.attributes-typography-row,
.attributes-content-row {
&:hover .attributes-copy-button {
visibility: visible;
opacity: 1;
&:hover {
.expand-button,
.copy-button {
visibility: visible;
opacity: 1;
}
}
}
@ -274,9 +289,12 @@
flex-direction: row;
margin: 0.5rem;
&:hover .attributes-copy-button {
visibility: visible;
opacity: 1;
&:hover {
.expand-button,
.copy-button {
visibility: visible;
opacity: 1;
}
}
.code-selection {
@ -294,14 +312,15 @@
background-position: 90% 48%;
background-size: 8px;
}
.attributes-copy-button {
.expand-button,
.copy-button {
margin-top: 8px;
}
}
.code-row-display {
margin: 0.5rem;
font-size: $fs12;
font-size: $fs14;
.code-display {
border-radius: 4px;

View file

@ -16,6 +16,11 @@ $width-settings-bar: 16rem;
position: fixed;
right: 0;
width: $width-settings-bar;
&.expanded {
width: $width-settings-bar * 3;
}
z-index: 10;
overflow-y: auto;

View file

@ -0,0 +1,23 @@
;; 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.components.code-block
(:require
["highlight.js" :as hljs]
[rumext.alpha :as mf]))
(mf/defc code-block [{:keys [code type]}]
(let [block-ref (mf/use-ref)]
(mf/use-effect
(mf/deps code type block-ref)
(fn []
(hljs/highlightBlock (mf/ref-val block-ref))))
[:pre.code-display {:class type
:ref block-ref} code]))

View file

@ -0,0 +1,35 @@
;; 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.components.copy-button
(:require
[beicon.core :as rx]
[rumext.alpha :as mf]
[app.util.webapi :as wapi]
[app.util.timers :as timers]
[app.main.ui.icons :as i]))
(mf/defc copy-button [{:keys [data]}]
(let [just-copied (mf/use-state false)]
(mf/use-effect
(mf/deps @just-copied)
(fn []
(when @just-copied
(let [sub (timers/schedule 1000 #(reset! just-copied false))]
;; On umounto we dispose the timer
#(rx/-dispose sub)))))
[:button.copy-button
{:on-click #(when-not @just-copied
(do
(reset! just-copied true)
(wapi/write-to-clipboard data)))}
(if @just-copied
i/tick
i/copy)]))

View file

@ -63,9 +63,10 @@
[:*
[:& left-sidebar {:frame frame}]
[:div.handoff-svg-wrapper {:on-click (handle-select-frame frame)}
[:& render-frame-svg {:frame-id (:id frame)
:zoom (:zoom local)
:objects objects}]]
[:div.handoff-svg-container
[:& render-frame-svg {:frame-id (:id frame)
:zoom (:zoom local)
:objects objects}]]]
[:& right-sidebar {:frame frame}]])]))
(mf/defc handoff-content

View file

@ -13,29 +13,30 @@
[cuerdas.core :as str]
[app.util.i18n :refer [t]]
[app.main.ui.icons :as i]
[app.main.ui.viewer.handoff.attributes.common :refer [copy-cb]]))
[app.util.code-gen :as cg]
[app.main.ui.components.copy-button :refer [copy-button]]))
(defn has-blur? [shape]
(:blur shape))
(defn copy-blur [shape]
(copy-cb shape
:blur
:to-prop "filter"
:format #(str/fmt "blur(%spx)" (:value %))))
(defn copy-data [shape]
(cg/generate-css-props
shape
:blur
{:to-prop "filter"
:format #(str/fmt "blur(%spx)" (:value %))}))
(mf/defc blur-panel [{:keys [shapes locale]}]
(let [shapes (->> shapes (filter has-blur?))
handle-copy (when (= (count shapes) 1) (copy-blur (first shapes)))]
(let [shapes (->> shapes (filter has-blur?))]
(when (seq shapes)
[:div.attributes-block
[:div.attributes-block-title
[:div.attributes-block-title-text (t locale "handoff.attributes.blur")]
(when handle-copy
[:button.attributes-copy-button {:on-click handle-copy} i/copy])]
(when (= (count shapes) 1)
[:& copy-button {:data (copy-data (first shapes))}])]
(for [shape shapes]
[: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 (copy-blur shape)} i/copy]])])))
[:& copy-button {:data (copy-data shape)}]])])))

View file

@ -18,14 +18,10 @@
[app.main.ui.icons :as i]
[app.util.code-gen :as cg]
[app.util.webapi :as wapi]
[app.main.ui.components.copy-button :refer [copy-button]]
[app.main.ui.components.color-bullet :refer [color-bullet color-name]]))
(defn copy-cb [values properties & {:keys [to-prop format] :as params}]
(fn [event]
(let [result (cg/generate-css-props values properties params)]
(wapi/write-to-clipboard result))))
(mf/defc color-row [{:keys [color format on-copy on-change-format]}]
(mf/defc color-row [{:keys [color format copy-data on-change-format]}]
(let [locale (mf/deref i18n/locale)]
[:div.attributes-color-row
[:& color-bullet {:color color}]
@ -52,6 +48,6 @@
[:option {:value "hsla"}
(t locale "handoff.attributes.color.hsla")]])
(when on-copy
[:button.attributes-copy-button {:on-click on-copy} i/copy])]))
(when copy-data
[:& copy-button {:data copy-data}])]))

View file

@ -13,7 +13,9 @@
[app.util.i18n :refer [t]]
[app.util.color :as uc]
[app.main.ui.icons :as i]
[app.main.ui.viewer.handoff.attributes.common :refer [copy-cb color-row]]))
[app.util.code-gen :as cg]
[app.main.ui.components.copy-button :refer [copy-button]]
[app.main.ui.viewer.handoff.attributes.common :refer [color-row]]))
(def fill-attributes [:fill-color :fill-color-gradient])
@ -30,36 +32,31 @@
(or (:fill-color shape)
(:fill-color-gradient shape))))
(defn copy-data [shape]
(cg/generate-css-props
shape
fill-attributes
{:to-prop "background"
:format #(uc/color->background (shape->color shape))}))
(mf/defc fill-block [{:keys [shape locale]}]
(let [color-format (mf/use-state :hex)
color (shape->color shape)
handle-copy (copy-cb shape
fill-attributes
:to-prop "background"
:format #(uc/color->background color))]
color (shape->color shape)]
[:& color-row {:color color
:format @color-format
:on-change-format #(reset! color-format %)
:on-copy handle-copy}]))
:copy-data (copy-data shape)}]))
(mf/defc fill-panel
[{:keys [shapes locale]}]
(let [shapes (->> shapes (filter has-color?))
handle-copy (when (= (count shapes) 1)
(copy-cb (first shapes)
fill-attributes
:to-prop "background"
:format #(-> shapes first shape->color uc/color->background)))]
(let [shapes (->> shapes (filter has-color?))]
(when (seq shapes)
[:div.attributes-block
[:div.attributes-block-title
[:div.attributes-block-title-text (t locale "handoff.attributes.fill")]
(when handle-copy
[:button.attributes-copy-button
{:on-click handle-copy}
i/copy])]
(when (= (count shapes) 1)
[:& copy-button {:data (copy-data (first shapes))}])]
(for [shape shapes]
[:& fill-block {:key (str "fill-block-" (:id shape))

View file

@ -14,7 +14,8 @@
[app.config :as cfg]
[app.util.i18n :refer [t]]
[app.main.ui.icons :as i]
[app.main.ui.viewer.handoff.attributes.common :refer [copy-cb]]))
[app.util.code-gen :as cg]
[app.main.ui.components.copy-button :refer [copy-button]]))
(defn has-image? [shape]
(and (= (:type shape) :image)))
@ -30,12 +31,12 @@
[:div.attributes-unit-row
[: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]]
[:& copy-button {:data (cg/generate-css-props shape :width)}]]
[:div.attributes-unit-row
[: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]]
[:& copy-button {:data (cg/generate-css-props shape :height)}]]
(let [filename (last (str/split (-> shape :metadata :path) "/"))]
[:a.download-button {:target "_blank"

View file

@ -14,13 +14,22 @@
[app.util.i18n :refer [t]]
[app.common.math :as mth]
[app.main.ui.icons :as i]
[app.main.ui.viewer.handoff.attributes.common :refer [copy-cb]]))
[app.util.code-gen :as cg]
[app.main.ui.components.copy-button :refer [copy-button]]))
(defn copy-layout [shape]
(copy-cb shape
[:width :height :x :y :radius :rx]
:to-prop {:x "left" :y "top" :rotation "transform" :rx "border-radius"}
:format {:rotation #(str/fmt "rotate(%sdeg)" %)}))
(def properties [:width :height :x :y :radius :rx])
(def params
{:to-prop {:x "left"
:y "top"
:rotation "transform"
:rx "border-radius"}
:format {:rotation #(str/fmt "rotate(%sdeg)" %)}})
(defn copy-data
([shape]
(apply copy-data shape properties))
([shape & properties]
(cg/generate-css-props shape properties params)))
(mf/defc layout-block
[{:keys [shape locale]}]
@ -28,65 +37,46 @@
[: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
{:on-click (copy-cb shape :width)}
i/copy]]
[:& copy-button {:data (copy-data shape :width)}]]
[: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
{:on-click (copy-cb shape :height)}
i/copy]]
[:& copy-button {:data (copy-data shape :height)}]]
(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
{:on-click (copy-cb shape :x :to-prop "left")}
i/copy]])
[:& copy-button {:data (copy-data shape :x)}]])
(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
{:on-click (copy-cb shape :y :to-prop "top")}
i/copy]])
[:& copy-button {:data (copy-data shape :y)}]])
(when (and (:rx shape) (not= (:rx shape) 0))
[:div.attributes-unit-row
[:div.attributes-label (t locale "handoff.attributes.layout.radius")]
[:div.attributes-value (mth/precision (:rx shape) 2) "px"]
[:button.attributes-copy-button
{:on-click (copy-cb shape :rx :to-prop "border-radius")}
i/copy]])
[:& copy-button {:data (copy-data shape :rx)}]])
(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
{:on-click (copy-cb shape
:rotation
:to-prop "transform"
:format #(str/fmt "rotate(%sdeg)" %))}
i/copy]])])
[:& copy-button {:data (copy-data shape :rotation)}]])])
(mf/defc layout-panel
[{:keys [shapes locale]}]
(let [handle-copy (when (= (count shapes) 1)
(copy-layout (first shapes)))]
[:div.attributes-block
[:div.attributes-block-title
[:div.attributes-block-title-text (t locale "handoff.attributes.layout")]
(when handle-copy
[:button.attributes-copy-button
{:on-click handle-copy}
i/copy])]
[:div.attributes-block
[:div.attributes-block-title
[:div.attributes-block-title-text (t locale "handoff.attributes.layout")]
(when (= (count shapes) 1)
[:& copy-button {:data (copy-data (first shapes))}])]
(for [shape shapes]
[:& layout-block {:shape shape
:locale locale}])]))
(for [shape shapes]
[:& layout-block {:shape shape
:locale locale}])])

View file

@ -14,13 +14,30 @@
[app.util.i18n :refer [t]]
[app.util.code-gen :as cg]
[app.main.ui.icons :as i]
[app.main.ui.viewer.handoff.attributes.common :refer [copy-cb color-row]]))
[app.util.code-gen :as cg]
[app.main.ui.components.copy-button :refer [copy-button]]
[app.main.ui.viewer.handoff.attributes.common :refer [color-row]]))
(defn has-shadow? [shape]
(:shadow shape))
(defn shape-copy-data [shape]
(cg/generate-css-props
shape
:shadow
{:to-prop "box-shadow"
:format #(str/join ", " (map cg/shadow->css (:shadow shape)))}))
(defn shadow-copy-data [shadow]
(cg/generate-css-props
shadow
:style
{:to-prop "box-shadow"
:format #(cg/shadow->css shadow)}))
(mf/defc shadow-block [{:keys [shape locale shadow]}]
(let [color-format (mf/use-state :hex)]
(let [color-format (mf/use-state :hex)
copy-data (shadow-copy-data shadow)]
[:div.attributes-shadow-block
[:div.attributes-shadow-row
[:div.attributes-label (->> shadow :style name (str "handoff.attributes.shadow.style.") (t locale))]
@ -40,29 +57,20 @@
[: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 #(cg/shadow->css shadow))}
i/copy]]
[:& copy-button {:data (shadow-copy-data shadow)}]]
[:& color-row {:color (:color shadow)
:format @color-format
:on-change-format #(reset! color-format %)}]]))
(mf/defc shadow-panel [{:keys [shapes locale]}]
(let [shapes (->> shapes (filter has-shadow?))
handle-copy-shadow (when (= (count shapes) 1)
(copy-cb (first shapes)
:shadow
:to-prop "box-shadow"
:format #(str/join ", " (map cg/shadow->css (:shadow (first shapes))))))]
(let [shapes (->> shapes (filter has-shadow?))]
(when (seq shapes)
[:div.attributes-block
[:div.attributes-block-title
[:div.attributes-block-title-text (t locale "handoff.attributes.shadow")]
(when handle-copy-shadow
[:button.attributes-copy-button {:on-click handle-copy-shadow} i/copy])]
(when (= (count shapes) 1)
[:& copy-button {:data (shape-copy-data (first shapes))}])]
[:div.attributes-shadow-blocks
(for [shape shapes]

View file

@ -14,7 +14,9 @@
[app.util.i18n :refer [t]]
[app.util.color :as uc]
[app.main.ui.icons :as i]
[app.main.ui.viewer.handoff.attributes.common :refer [copy-cb color-row]]))
[app.util.code-gen :as cg]
[app.main.ui.components.copy-button :refer [copy-button]]
[app.main.ui.viewer.handoff.attributes.common :refer [color-row]]))
(defn shape->color [shape]
{:color (:stroke-color shape)
@ -33,49 +35,46 @@
(and (:stroke-style shape)
(not= (:stroke-style shape) :none)))
(defn copy-stroke-data [shape]
(cg/generate-css-props
shape
:stroke-style
{:to-prop "border"
:format #(format-stroke shape)}))
(defn copy-color-data [shape]
(cg/generate-css-props
shape
:stroke-color
{:to-prop "border-color"
:format #(uc/color->background (shape->color shape))}))
(mf/defc stroke-block
[{:keys [shape locale]}]
(let [color-format (mf/use-state :hex)
color (shape->color shape)
handle-copy-stroke (copy-cb shape
:stroke-style
:to-prop "border"
:format #(format-stroke shape))
handle-copy-color (copy-cb shape
:stroke-color
:to-prop "border-color"
:format #(uc/color->background color))]
color (shape->color shape)]
[:*
[:& color-row {:color color
:format @color-format
:on-change-format #(reset! color-format %)
:on-copy handle-copy-color}]
:copy-data (copy-color-data shape)
:on-change-format #(reset! color-format %)}]
[:div.attributes-stroke-row
[:div.attributes-label (t locale "handoff.attributes.stroke.width")]
[: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]]]))
[:& copy-button {:data (copy-stroke-data shape)}]]]))
(mf/defc stroke-panel
[{:keys [shapes locale]}]
(let [shapes (->> shapes (filter has-stroke?))
handle-copy (when (= (count shapes) 1)
(copy-cb (first shapes)
:stroke-style
:to-prop "border"
:format #(format-stroke (first shapes))))]
(let [shapes (->> shapes (filter has-stroke?))]
(when (seq shapes)
[:div.attributes-block
[:div.attributes-block-title
[:div.attributes-block-title-text (t locale "handoff.attributes.stroke")]
(when handle-copy
[:button.attributes-copy-button
{:on-click handle-copy} i/copy])]
(when (= (count shapes) 1)
[:& copy-button {:data (copy-stroke-data (first shapes))}])]
(for [shape shapes]
[:& stroke-block {:key (str "stroke-color-" (:id shape))

View file

@ -18,7 +18,9 @@
[app.main.fonts :as fonts]
[app.main.ui.icons :as i]
[app.util.webapi :as wapi]
[app.main.ui.viewer.handoff.attributes.common :refer [copy-cb color-row]]))
[app.main.ui.viewer.handoff.attributes.common :refer [color-row]]
[app.util.code-gen :as cg]
[app.main.ui.components.copy-button :refer [copy-button]]))
(defn has-text? [shape]
(:content shape))
@ -40,22 +42,28 @@
:id (:fill-ref-id shape)
:file-id (:fill-ref-file-id shape)})
(defn format-style [color]
{: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 #(uc/color->background color)
:fill-color-gradient #(uc/color->background color)})
(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)}})
(defn copy-style-data
([style]
(cg/generate-css-props style properties params))
([style & properties]
(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)
to-prop {:fill-color "color"
:fill-color-gradient "color"}]
color (shape->color style)]
[:div.attributes-text-block
[:div.attributes-typography-row
[:div.typography-sample
@ -63,68 +71,59 @@
: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-style color))}
i/copy]]
[:& copy-button {:data (copy-style-data style)}]]
[: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]]
[:& copy-button {:data (str/trim text)}]]
(when (or (:fill-color style) (:fill-color-gradient style))
[:& color-row {:format @color-format
:on-change-format #(reset! color-format %)
:color (shape->color style)
:on-copy (copy-cb style
[:fill-color :fill-color-gradient]
:to-prop to-prop
:format (format-style color))}])
:copy-data (copy-style-data style :fill-color :fill-color-gradient)
:on-change-format #(reset! color-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]])
[:& copy-button {:data (copy-style-data style :font-family)}]])
(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]])
[:& copy-button {:data (copy-style-data style :font-style)}]])
(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]])
[:& copy-button {:data (copy-style-data style :font-size)}]])
(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]])
[:& copy-button {:data (copy-style-data style :line-height)}]])
(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]])
[:& copy-button {:data (copy-style-data style :letter-spacing)}]])
(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]])
[:& copy-button {:data (copy-style-data style :text-decoration)}]])
(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]])]))
[:& copy-button {:data (copy-style-data style :text-transform)}]])]))
(mf/defc text-block [{:keys [shape locale]}]

View file

@ -9,17 +9,16 @@
(ns app.main.ui.viewer.handoff.code
(:require
["highlight.js" :as hljs]
["js-beautify" :as beautify]
[cuerdas.core :as str]
[rumext.alpha :as mf]
[app.util.i18n :as i18n]
[app.util.color :as uc]
[app.util.dom :as dom]
[app.util.webapi :as wapi]
[app.util.code-gen :as cg]
[app.main.ui.icons :as i]
[app.common.geom.shapes :as gsh]))
[app.common.geom.shapes :as gsh]
[app.main.ui.components.copy-button :refer [copy-button]]
[app.main.ui.components.code-block :refer [code-block]]))
(defn generate-markup-code [type shapes]
(let [frame (dom/query js/document "#svg-frame")
@ -35,22 +34,15 @@
(remove nil?)
(str/join "\n\n"))))
(mf/defc code-block [{:keys [code type]}]
(defn format-code [code type]
(let [code (-> code
(str/replace "<defs></defs>" "")
(str/replace "><" ">\n<"))
code (cond-> code
(= type "svg") (beautify/html #js {"indent_size" 2}))
block-ref (mf/use-ref)]
(mf/use-effect
(mf/deps code type block-ref)
(fn []
(hljs/highlightBlock (mf/ref-val block-ref))))
[:pre.code-display {:class type
:ref block-ref} code]))
(str/replace "><" ">\n<"))]
(cond-> code
(= type "svg") (beautify/html #js {"indent_size" 2}))))
(mf/defc code
[{:keys [shapes frame]}]
[{:keys [shapes frame on-expand]}]
(let [style-type (mf/use-state "css")
markup-type (mf/use-state "svg")
@ -58,8 +50,11 @@
shapes (->> shapes
(map #(gsh/translate-to-frame % frame)))
style-code (cg/generate-style-code @style-type shapes)
markup-code (mf/use-memo (mf/deps shapes) #(generate-markup-code @markup-type shapes))]
style-code (-> (cg/generate-style-code @style-type shapes)
(format-code "css"))
markup-code (-> (mf/use-memo (mf/deps shapes) #(generate-markup-code @markup-type shapes))
(format-code "svg"))]
[:div.element-options
[:div.code-block
[:div.code-row-lang
@ -69,9 +64,11 @@
#_[:option {:value "less"} "Less"]
#_[:option {:value "stylus"} "Stylus"]]
[:button.attributes-copy-button
{:on-click #(wapi/write-to-clipboard style-code)}
i/copy]]
[:button.expand-button
{:on-click on-expand }
i/full-screen]
[:& copy-button { :data style-code }]]
[:div.code-row-display
[:& code-block {:type @style-type
@ -83,9 +80,11 @@
[:option "SVG"]
[:option "HTML"]]
[:button.attributes-copy-button
{:on-click #(wapi/write-to-clipboard markup-code)}
i/copy]]
[:button.expand-button
{:on-click on-expand}
i/full-screen]
[:& copy-button { :data markup-code }]]
[:div.code-row-display
[:& code-block {:type @markup-type

View file

@ -32,11 +32,12 @@
(mf/defc right-sidebar
[{:keys [frame]}]
(let [locale (mf/deref i18n/locale)
(let [expanded (mf/use-state false)
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
[:aside.settings-bar.settings-bar-right {:class (when @expanded "expanded")}
[:div.settings-bar-inside
(when (seq shapes)
[:div.tool-window
@ -51,7 +52,9 @@
[: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 %)
[:& tab-container {:on-change-tab #(do
(reset! expanded false)
(reset! section %))
:selected @section}
[:& tab-element {:id :info :title (t locale "handoff.tabs.info")}
[:& attributes {:frame frame
@ -59,4 +62,5 @@
[:& tab-element {:id :code :title (t locale "handoff.tabs.code")}
[:& code {:frame frame
:shapes shapes}]]]]])]]))
:shapes shapes
:on-expand #(swap! expanded not)}]]]]])]]))

View file

@ -77,34 +77,38 @@
:fill-color format-fill-color}})
(defn generate-css-props [values properties params]
(let [{:keys [to-prop format tab-size] :or {to-prop {} tab-size 0}} params
;; 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)
(defn generate-css-props
([values properties]
(generate-css-props values properties nil))
format (if (not (map? format))
(into {} (map #(vector % format) properties))
format)
([values properties params]
(let [{:keys [to-prop format tab-size] :or {to-prop {} tab-size 0}} params
;; 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)
to-prop (if (not (map? to-prop))
(into {} (map #(vector % to-prop) properties))
to-prop)
format (if (not (map? format))
(into {} (map #(vector % format) properties))
format)
default-format (fn [value] (str (mth/precision value 2) "px"))
format-property (fn [prop]
(let [css-prop (or (prop to-prop) (name prop))
format-fn (or (prop format) default-format)]
(str
(str/repeat " " tab-size)
(str/fmt "%s: %s;" css-prop (format-fn (prop values) values)))))]
to-prop (if (not (map? to-prop))
(into {} (map #(vector % to-prop) properties))
to-prop)
(->> properties
(remove #(let [value (get values %)]
(or (nil? value) (= value 0))))
(map format-property)
(str/join "\n"))))
default-format (fn [value] (str (mth/precision value 2) "px"))
format-property (fn [prop]
(let [css-prop (or (prop to-prop) (name prop))
format-fn (or (prop format) default-format)]
(str
(str/repeat " " tab-size)
(str/fmt "%s: %s;" css-prop (format-fn (prop values) values)))))]
(->> properties
(remove #(let [value (get values %)]
(or (nil? value) (= value 0))))
(map format-property)
(str/join "\n")))))
(defn shape->properties [shape]
(let [props (->> styles-data vals (mapcat :props))