mirror of
https://github.com/penpot/penpot.git
synced 2025-03-12 07:41:43 -05:00
✨ Handoff for imported SVGS
This commit is contained in:
parent
6f07b4ea80
commit
4da3270d34
13 changed files with 187 additions and 67 deletions
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
(ns app.common.data
|
(ns app.common.data
|
||||||
"Data manipulation and query helper functions."
|
"Data manipulation and query helper functions."
|
||||||
(:refer-clojure :exclude [concat read-string hash-map merge])
|
(:refer-clojure :exclude [concat read-string hash-map merge name])
|
||||||
#?(:cljs
|
#?(:cljs
|
||||||
(:require-macros [app.common.data]))
|
(:require-macros [app.common.data]))
|
||||||
(:require
|
(:require
|
||||||
|
@ -359,7 +359,7 @@
|
||||||
;; Code for ClojureScript
|
;; Code for ClojureScript
|
||||||
(let [mdata (aapi/resolve &env v)
|
(let [mdata (aapi/resolve &env v)
|
||||||
arglists (second (get-in mdata [:meta :arglists]))
|
arglists (second (get-in mdata [:meta :arglists]))
|
||||||
sym (symbol (name v))
|
sym (symbol (core/name v))
|
||||||
andsym (symbol "&")
|
andsym (symbol "&")
|
||||||
procarg #(if (= % andsym) % (gensym "param"))]
|
procarg #(if (= % andsym) % (gensym "param"))]
|
||||||
(if (pos? (count arglists))
|
(if (pos? (count arglists))
|
||||||
|
@ -391,3 +391,16 @@
|
||||||
|
|
||||||
(defn any-key? [element & rest]
|
(defn any-key? [element & rest]
|
||||||
(some #(contains? element %) rest))
|
(some #(contains? element %) rest))
|
||||||
|
|
||||||
|
(defn name
|
||||||
|
"Improved version of name that won't fail if the input is not a keyword"
|
||||||
|
[maybe-keyword]
|
||||||
|
(cond
|
||||||
|
(keyword? maybe-keyword)
|
||||||
|
(core/name maybe-keyword)
|
||||||
|
|
||||||
|
(nil? maybe-keyword) nil
|
||||||
|
|
||||||
|
:else
|
||||||
|
(str maybe-keyword)))
|
||||||
|
|
||||||
|
|
|
@ -5512,5 +5512,38 @@
|
||||||
"en": "Imported SVG Attributes",
|
"en": "Imported SVG Attributes",
|
||||||
"es": "Atributos del SVG Importado"
|
"es": "Atributos del SVG Importado"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"handoff.attributes.stroke.alignment.inner" : {
|
||||||
|
"translations" : {
|
||||||
|
"en" : "Inside",
|
||||||
|
"es" : "Interior",
|
||||||
|
"fr" : "Intérieur",
|
||||||
|
"ru" : "Внутрь",
|
||||||
|
"zh_cn" : "内部"
|
||||||
|
},
|
||||||
|
"permanent": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"handoff.attributes.stroke.alignment.outer" : {
|
||||||
|
"translations" : {
|
||||||
|
"en" : "Outside",
|
||||||
|
"es" : "Exterior",
|
||||||
|
"fr" : "Extérieur",
|
||||||
|
"ru" : "Наружу",
|
||||||
|
"zh_cn" : "外部"
|
||||||
|
},
|
||||||
|
"permanent": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"handoff.attributes.stroke.alignment.center" : {
|
||||||
|
"translations" : {
|
||||||
|
"en" : "Center",
|
||||||
|
"es" : "Centro",
|
||||||
|
"fr" : "Centre",
|
||||||
|
"ru" : "Центр",
|
||||||
|
"zh_cn" : "居中"
|
||||||
|
},
|
||||||
|
"permanent": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,10 @@
|
||||||
|
|
||||||
.attributes-label,
|
.attributes-label,
|
||||||
.attributes-value {
|
.attributes-value {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
.copy-button {
|
.copy-button {
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
"Given a tag returns its layer name"
|
"Given a tag returns its layer name"
|
||||||
[tag]
|
[tag]
|
||||||
(str "svg-" (cond (string? tag) tag
|
(str "svg-" (cond (string? tag) tag
|
||||||
(keyword? tag) (name tag)
|
(keyword? tag) (d/name tag)
|
||||||
(nil? tag) "node"
|
(nil? tag) "node"
|
||||||
:else (str tag))))
|
:else (str tag))))
|
||||||
|
|
||||||
|
|
|
@ -19,16 +19,17 @@
|
||||||
[app.main.ui.handoff.attributes.shadow :refer [shadow-panel]]
|
[app.main.ui.handoff.attributes.shadow :refer [shadow-panel]]
|
||||||
[app.main.ui.handoff.attributes.blur :refer [blur-panel]]
|
[app.main.ui.handoff.attributes.blur :refer [blur-panel]]
|
||||||
[app.main.ui.handoff.attributes.image :refer [image-panel]]
|
[app.main.ui.handoff.attributes.image :refer [image-panel]]
|
||||||
[app.main.ui.handoff.attributes.text :refer [text-panel]]))
|
[app.main.ui.handoff.attributes.text :refer [text-panel]]
|
||||||
|
[app.main.ui.handoff.attributes.svg :refer [svg-panel]]))
|
||||||
|
|
||||||
(def type->options
|
(def type->options
|
||||||
{:multiple [:fill :stroke :image :text :shadow :blur]
|
{:multiple [:fill :stroke :image :text :shadow :blur]
|
||||||
:frame [:layout :fill]
|
:frame [:layout :fill]
|
||||||
:group [:layout]
|
:group [:layout :svg]
|
||||||
:rect [:layout :fill :stroke :shadow :blur]
|
:rect [:layout :fill :stroke :shadow :blur :svg]
|
||||||
:circle [:layout :fill :stroke :shadow :blur]
|
:circle [:layout :fill :stroke :shadow :blur :svg]
|
||||||
:path [:layout :fill :stroke :shadow :blur]
|
:path [:layout :fill :stroke :shadow :blur :svg]
|
||||||
:image [:image :layout :shadow :blur]
|
:image [:image :layout :shadow :blur :svg]
|
||||||
:text [:layout :text :shadow :blur]})
|
:text [:layout :text :shadow :blur]})
|
||||||
|
|
||||||
(mf/defc attributes
|
(mf/defc attributes
|
||||||
|
@ -46,7 +47,8 @@
|
||||||
:shadow shadow-panel
|
:shadow shadow-panel
|
||||||
:blur blur-panel
|
:blur blur-panel
|
||||||
:image image-panel
|
:image image-panel
|
||||||
:text text-panel)
|
:text text-panel
|
||||||
|
:svg svg-panel)
|
||||||
{:shapes shapes
|
{:shapes shapes
|
||||||
:frame frame
|
:frame frame
|
||||||
:locale locale}])
|
:locale locale}])
|
||||||
|
|
|
@ -37,28 +37,30 @@
|
||||||
|
|
||||||
(mf/defc layout-block
|
(mf/defc layout-block
|
||||||
[{:keys [shape locale]}]
|
[{:keys [shape locale]}]
|
||||||
|
(let [selrect (:selrect shape)
|
||||||
|
{:keys [width height x y]} selrect]
|
||||||
[:*
|
[:*
|
||||||
[:div.attributes-unit-row
|
[:div.attributes-unit-row
|
||||||
[:div.attributes-label (t locale "handoff.attributes.layout.width")]
|
[:div.attributes-label (t locale "handoff.attributes.layout.width")]
|
||||||
[:div.attributes-value (mth/precision (:width shape) 2) "px"]
|
[:div.attributes-value (mth/precision width 2) "px"]
|
||||||
[:& copy-button {:data (copy-data shape :width)}]]
|
[:& copy-button {:data (copy-data selrect :width)}]]
|
||||||
|
|
||||||
[:div.attributes-unit-row
|
[:div.attributes-unit-row
|
||||||
[:div.attributes-label (t locale "handoff.attributes.layout.height")]
|
[:div.attributes-label (t locale "handoff.attributes.layout.height")]
|
||||||
[:div.attributes-value (mth/precision (:height shape) 2) "px"]
|
[:div.attributes-value (mth/precision height 2) "px"]
|
||||||
[:& copy-button {:data (copy-data shape :height)}]]
|
[:& copy-button {:data (copy-data selrect :height)}]]
|
||||||
|
|
||||||
(when (not= (:x shape) 0)
|
(when (not= (:x shape) 0)
|
||||||
[:div.attributes-unit-row
|
[:div.attributes-unit-row
|
||||||
[:div.attributes-label (t locale "handoff.attributes.layout.left")]
|
[:div.attributes-label (t locale "handoff.attributes.layout.left")]
|
||||||
[:div.attributes-value (mth/precision (:x shape) 2) "px"]
|
[:div.attributes-value (mth/precision x 2) "px"]
|
||||||
[:& copy-button {:data (copy-data shape :x)}]])
|
[:& copy-button {:data (copy-data selrect :x)}]])
|
||||||
|
|
||||||
(when (not= (:y shape) 0)
|
(when (not= (:y shape) 0)
|
||||||
[:div.attributes-unit-row
|
[:div.attributes-unit-row
|
||||||
[:div.attributes-label (t locale "handoff.attributes.layout.top")]
|
[:div.attributes-label (t locale "handoff.attributes.layout.top")]
|
||||||
[:div.attributes-value (mth/precision (:y shape) 2) "px"]
|
[:div.attributes-value (mth/precision y 2) "px"]
|
||||||
[:& copy-button {:data (copy-data shape :y)}]])
|
[:& copy-button {:data (copy-data selrect :y)}]])
|
||||||
|
|
||||||
(when (and (:rx shape) (not= (:rx shape) 0))
|
(when (and (:rx shape) (not= (:rx shape) 0))
|
||||||
[:div.attributes-unit-row
|
[:div.attributes-unit-row
|
||||||
|
@ -83,7 +85,7 @@
|
||||||
[:div.attributes-unit-row
|
[:div.attributes-unit-row
|
||||||
[:div.attributes-label (t locale "handoff.attributes.layout.rotation")]
|
[:div.attributes-label (t locale "handoff.attributes.layout.rotation")]
|
||||||
[:div.attributes-value (mth/precision (:rotation shape) 2) "deg"]
|
[:div.attributes-value (mth/precision (:rotation shape) 2) "deg"]
|
||||||
[:& copy-button {:data (copy-data shape :rotation)}]])])
|
[:& copy-button {:data (copy-data shape :rotation)}]])]))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc layout-panel
|
(mf/defc layout-panel
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
[app.common.data :as d]
|
||||||
[app.util.i18n :refer [t]]
|
[app.util.i18n :refer [t]]
|
||||||
[app.util.code-gen :as cg]
|
[app.util.code-gen :as cg]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
@ -40,7 +41,7 @@
|
||||||
copy-data (shadow-copy-data shadow)]
|
copy-data (shadow-copy-data shadow)]
|
||||||
[:div.attributes-shadow-block
|
[:div.attributes-shadow-block
|
||||||
[:div.attributes-shadow-row
|
[:div.attributes-shadow-row
|
||||||
[:div.attributes-label (->> shadow :style name (str "handoff.attributes.shadow.style.") (t locale))]
|
[:div.attributes-label (->> shadow :style d/name (str "handoff.attributes.shadow.style.") (t locale))]
|
||||||
[:div.attributes-shadow
|
[:div.attributes-shadow
|
||||||
[:div.attributes-label (t locale "handoff.attributes.shadow.shorthand.offset-x")]
|
[:div.attributes-label (t locale "handoff.attributes.shadow.shorthand.offset-x")]
|
||||||
[:div.attributes-value (str (:offset-x shadow))]]
|
[:div.attributes-value (str (:offset-x shadow))]]
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.math :as mth]
|
||||||
[app.util.i18n :refer [t]]
|
[app.util.i18n :refer [t]]
|
||||||
[app.util.color :as uc]
|
[app.util.color :as uc]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
|
@ -27,13 +29,15 @@
|
||||||
|
|
||||||
(defn format-stroke [shape]
|
(defn format-stroke [shape]
|
||||||
(let [width (:stroke-width shape)
|
(let [width (:stroke-width shape)
|
||||||
style (name (:stroke-style shape))
|
style (d/name (:stroke-style shape))
|
||||||
|
style (if (= style "svg") "solid" style)
|
||||||
color (-> shape shape->color uc/color->background)]
|
color (-> shape shape->color uc/color->background)]
|
||||||
(str/format "%spx %s %s" width style color)))
|
(str/format "%spx %s %s" width style color)))
|
||||||
|
|
||||||
(defn has-stroke? [shape]
|
(defn has-stroke? [{:keys [stroke-style]}]
|
||||||
(and (:stroke-style shape)
|
(and stroke-style
|
||||||
(not= (:stroke-style shape) :none)))
|
(and (not= stroke-style :none)
|
||||||
|
(not= stroke-style :svg))))
|
||||||
|
|
||||||
(defn copy-stroke-data [shape]
|
(defn copy-stroke-data [shape]
|
||||||
(cg/generate-css-props
|
(cg/generate-css-props
|
||||||
|
@ -59,12 +63,15 @@
|
||||||
:copy-data (copy-color-data shape)
|
:copy-data (copy-color-data shape)
|
||||||
:on-change-format #(reset! color-format %)}]
|
:on-change-format #(reset! color-format %)}]
|
||||||
|
|
||||||
|
(let [{:keys [stroke-style stroke-alignment]} shape
|
||||||
|
stroke-style (if (= stroke-style :svg) :solid stroke-style)
|
||||||
|
stroke-alignment (or stroke-alignment :center)]
|
||||||
[:div.attributes-stroke-row
|
[:div.attributes-stroke-row
|
||||||
[:div.attributes-label (t locale "handoff.attributes.stroke.width")]
|
[:div.attributes-label (t locale "handoff.attributes.stroke.width")]
|
||||||
[:div.attributes-value (:stroke-width shape) "px"]
|
[:div.attributes-value (mth/precision (:stroke-width shape) 2) "px"]
|
||||||
[:div.attributes-value (->> shape :stroke-style name (str "handoff.attributes.stroke.style.") (t locale))]
|
[:div.attributes-value (->> stroke-style d/name (str "handoff.attributes.stroke.style.") (t locale))]
|
||||||
[:div.attributes-label (->> shape :stroke-alignment name (str "handoff.attributes.stroke.alignment.") (t locale))]
|
[:div.attributes-label (->> stroke-alignment d/name (str "handoff.attributes.stroke.alignment.") (t locale))]
|
||||||
[:& copy-button {:data (copy-stroke-data shape)}]]]))
|
[:& copy-button {:data (copy-stroke-data shape)}]])]))
|
||||||
|
|
||||||
(mf/defc stroke-panel
|
(mf/defc stroke-panel
|
||||||
[{:keys [shapes locale]}]
|
[{:keys [shapes locale]}]
|
||||||
|
|
57
frontend/src/app/main/ui/handoff/attributes/svg.cljs
Normal file
57
frontend/src/app/main/ui/handoff/attributes/svg.cljs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
;; 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.handoff.attributes.svg
|
||||||
|
(:require
|
||||||
|
[rumext.alpha :as mf]
|
||||||
|
[app.common.data :as d]
|
||||||
|
[cuerdas.core :as str]
|
||||||
|
[app.util.i18n :refer [tr]]
|
||||||
|
#_[app.common.math :as mth]
|
||||||
|
#_[app.main.ui.icons :as i]
|
||||||
|
#_[app.util.code-gen :as cg]
|
||||||
|
[app.main.ui.components.copy-button :refer [copy-button]]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn map->css [attr]
|
||||||
|
(->> attr
|
||||||
|
(map (fn [[attr-key attr-value]] (str (d/name attr-key) ":" attr-value)))
|
||||||
|
(str/join "; ")))
|
||||||
|
|
||||||
|
(mf/defc svg-attr [{:keys [attr value]}]
|
||||||
|
(if (map? value)
|
||||||
|
[:*
|
||||||
|
[:div.attributes-block-title
|
||||||
|
[:div.attributes-block-title-text (d/name attr)]
|
||||||
|
[:& copy-button {:data (map->css value)}]]
|
||||||
|
|
||||||
|
(for [[attr-key attr-value] value]
|
||||||
|
[:& svg-attr {:attr attr-key :value attr-value}])]
|
||||||
|
|
||||||
|
[:div.attributes-unit-row
|
||||||
|
[:div.attributes-label (d/name attr)]
|
||||||
|
[:div.attributes-value (str value)]
|
||||||
|
[:& copy-button {:data (d/name value)}]]))
|
||||||
|
|
||||||
|
(mf/defc svg-block
|
||||||
|
[{:keys [shape]}]
|
||||||
|
[:*
|
||||||
|
(for [[attr-key attr-value] (:svg-attrs shape)]
|
||||||
|
[:& svg-attr {:attr attr-key :value attr-value}])] )
|
||||||
|
|
||||||
|
|
||||||
|
(mf/defc svg-panel
|
||||||
|
[{:keys [shapes]}]
|
||||||
|
|
||||||
|
(let [shape (first shapes)]
|
||||||
|
(when (and (:svg-attrs shape) (not (empty? (:svg-attrs shape))))
|
||||||
|
[:div.attributes-block
|
||||||
|
[:div.attributes-block-title
|
||||||
|
[:div.attributes-block-title-text (tr "workspace.sidebar.options.svg-attrs.title")]]
|
||||||
|
[:& svg-block {:shape shape}]])))
|
|
@ -114,7 +114,7 @@
|
||||||
[:input.input-text {:on-change (partial on-suffix-change index)
|
[:input.input-text {:on-change (partial on-suffix-change index)
|
||||||
:value (:suffix export)}]
|
:value (:suffix export)}]
|
||||||
[:select.input-select {:on-change (partial on-type-change index)
|
[:select.input-select {:on-change (partial on-type-change index)
|
||||||
:value (name (:type export))}
|
:value (d/name (:type export))}
|
||||||
[:option {:value "png"} "PNG"]
|
[:option {:value "png"} "PNG"]
|
||||||
[:option {:value "jpeg"} "JPEG"]
|
[:option {:value "jpeg"} "JPEG"]
|
||||||
[:option {:value "svg"} "SVG"]]
|
[:option {:value "svg"} "SVG"]]
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[app.util.i18n :refer [t] :as i18n]
|
[app.util.i18n :refer [t] :as i18n]
|
||||||
|
[app.common.data :as d]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.icons :as i]
|
[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]]
|
||||||
|
@ -49,7 +50,7 @@
|
||||||
[:*
|
[:*
|
||||||
[:span.tool-window-bar-icon
|
[:span.tool-window-bar-icon
|
||||||
[:& element-icon {:shape (-> shapes first)}]]
|
[:& element-icon {:shape (-> shapes first)}]]
|
||||||
[:span.tool-window-bar-title (->> selected-type name (str "handoff.tabs.code.selected.") (t locale))]])
|
[:span.tool-window-bar-title (->> selected-type d/name (str "handoff.tabs.code.selected.") (t locale))]])
|
||||||
]
|
]
|
||||||
[:div.tool-window-content
|
[:div.tool-window-content
|
||||||
[:& tab-container {:on-change-tab #(do
|
[:& tab-container {:on-change-tab #(do
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
(fn []
|
(fn []
|
||||||
(on-delete attr)))
|
(on-delete attr)))
|
||||||
|
|
||||||
label (->> attr last name)]
|
label (->> attr last d/name)]
|
||||||
[:div.element-set-content
|
[:div.element-set-content
|
||||||
(if (string? value)
|
(if (string? value)
|
||||||
[:div.row-flex.row-flex-removable
|
[:div.row-flex.row-flex-removable
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
[:*
|
[:*
|
||||||
[:div.element-set-title
|
[:div.element-set-title
|
||||||
{:style {:border-bottom "1px solid #444" :margin-bottom "0.5rem"}}
|
{:style {:border-bottom "1px solid #444" :margin-bottom "0.5rem"}}
|
||||||
[:span (str (name (last attr)))]]
|
[:span (str (d/name (last attr)))]]
|
||||||
|
|
||||||
(for [[key value] value]
|
(for [[key value] value]
|
||||||
[:& attribute-value {:key key
|
[:& attribute-value {:key key
|
||||||
|
|
|
@ -63,7 +63,7 @@
|
||||||
"Transforms attributes to their react equivalent"
|
"Transforms attributes to their react equivalent"
|
||||||
[attrs]
|
[attrs]
|
||||||
(letfn [(transform-key [key]
|
(letfn [(transform-key [key]
|
||||||
(-> (name key)
|
(-> (d/name key)
|
||||||
(str/replace ":" "-")
|
(str/replace ":" "-")
|
||||||
(str/camel)
|
(str/camel)
|
||||||
(keyword)))
|
(keyword)))
|
||||||
|
|
Loading…
Add table
Reference in a new issue