mirror of
https://github.com/penpot/penpot.git
synced 2025-05-06 07:35:53 +02:00
✨ Information panels
This commit is contained in:
parent
04f620ec00
commit
1e48221d7b
10 changed files with 713 additions and 18 deletions
|
@ -3360,5 +3360,73 @@
|
||||||
"ru" : "Кликни чтобы закончить фигуру",
|
"ru" : "Кликни чтобы закончить фигуру",
|
||||||
"es" : "Pulsar para cerrar la ruta"
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,3 +14,213 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -93,12 +93,13 @@
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [objects (:objects page)
|
(let [objects (:objects page)
|
||||||
frames (extract-frames objects)]
|
frames (extract-frames objects)]
|
||||||
(assoc state :viewer-data {:project project
|
(-> state
|
||||||
:objects objects
|
(assoc :viewer-data {:project project
|
||||||
:file file
|
:objects objects
|
||||||
:page page
|
:file file
|
||||||
:frames frames
|
:page page
|
||||||
:share-token share-token})))))
|
:frames frames
|
||||||
|
:share-token share-token}))))))
|
||||||
|
|
||||||
(def create-share-link
|
(def create-share-link
|
||||||
(ptk/reify ::create-share-link
|
(ptk/reify ::create-share-link
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
(let [color (if (string? color) {:color color :opacity 1} color)
|
(let [color (if (string? color) {:color color :opacity 1} color)
|
||||||
{:keys [name color opacity gradient]} color
|
{:keys [name color opacity gradient]} color
|
||||||
color-str (or name color (gradient-type->string (:type gradient)))]
|
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 %))
|
[:span.color-text {:on-click #(when on-click (on-click %))
|
||||||
:on-double-click #(when on-double-click (on-double-click %))
|
:on-double-click #(when on-double-click (on-double-click %))
|
||||||
:title name } color-str])))
|
:title name } color-str])))
|
||||||
|
|
|
@ -43,6 +43,12 @@
|
||||||
frames (:frames data [])
|
frames (:frames data [])
|
||||||
objects (:objects data)
|
objects (:objects data)
|
||||||
frame (get frames index)]
|
frame (get frames index)]
|
||||||
|
|
||||||
|
(mf/use-effect
|
||||||
|
(mf/deps index)
|
||||||
|
(fn []
|
||||||
|
(st/emit! (dv/select-shape (:id frame)))))
|
||||||
|
|
||||||
[:section.viewer-preview
|
[:section.viewer-preview
|
||||||
(cond
|
(cond
|
||||||
(empty? frames)
|
(empty? frames)
|
||||||
|
@ -60,7 +66,7 @@
|
||||||
[:& render-frame-svg {:frame-id (:id frame)
|
[:& render-frame-svg {:frame-id (:id frame)
|
||||||
:zoom (:zoom local)
|
:zoom (:zoom local)
|
||||||
:objects objects}]]
|
:objects objects}]]
|
||||||
[:& attributes-sidebar]])]))
|
[:& attributes-sidebar {:frame frame}]])]))
|
||||||
|
|
||||||
(mf/defc handoff-content
|
(mf/defc handoff-content
|
||||||
[{:keys [data local index] :as props}]
|
[{:keys [data local index] :as props}]
|
||||||
|
|
248
frontend/src/app/main/ui/viewer/handoff/attrib_panel.cljs
Normal file
248
frontend/src/app/main/ui/viewer/handoff/attrib_panel.cljs
Normal file
|
@ -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}])]))
|
110
frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs
Normal file
110
frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs
Normal file
|
@ -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"]]
|
||||||
|
|
||||||
|
])
|
|
@ -10,16 +10,48 @@
|
||||||
(ns app.main.ui.viewer.handoff.attributes-sidebar
|
(ns app.main.ui.viewer.handoff.attributes-sidebar
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
|
[okulary.core :as l]
|
||||||
|
[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]]
|
||||||
|
[app.main.ui.viewer.handoff.attrib-panel :refer [attrib-panel]]))
|
||||||
|
|
||||||
(mf/defc info-panel []
|
(defn make-selected-shapes-iref
|
||||||
[:div.element-options])
|
[]
|
||||||
|
(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 []
|
(mf/defc code-panel []
|
||||||
[:div.element-options])
|
[:div.element-options])
|
||||||
|
|
||||||
(mf/defc attributes-sidebar []
|
(mf/defc attributes-sidebar [{:keys [frame]}]
|
||||||
(let [section (mf/use-state :info #_:code)]
|
(let [section (mf/use-state :info #_:code)]
|
||||||
[:aside.settings-bar.settings-bar-right
|
[:aside.settings-bar.settings-bar-right
|
||||||
[:div.settings-bar-inside
|
[:div.settings-bar-inside
|
||||||
|
@ -31,8 +63,7 @@
|
||||||
[:& tab-container {:on-change-tab #(reset! section %)
|
[:& tab-container {:on-change-tab #(reset! section %)
|
||||||
:selected @section}
|
:selected @section}
|
||||||
[:& tab-element {:id :info :title "Info"}
|
[:& tab-element {:id :info :title "Info"}
|
||||||
[:& info-panel]]
|
[:& info-panel {:frame frame}]]
|
||||||
|
|
||||||
[:& tab-element {:id :code :title "Code"}
|
[:& tab-element {:id :code :title "Code"}
|
||||||
[:& code-panel]]]]]]]))
|
[:& code-panel]]]]]]]))
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
(let [hover (get-in state [:viewer-local :hover])
|
(let [hover (get-in state [:viewer-local :hover])
|
||||||
objects (get-in state [:viewer-data :page :objects])
|
objects (get-in state [:viewer-data :page :objects])
|
||||||
resolve-shape #(get objects %)]
|
resolve-shape #(get objects %)]
|
||||||
(map resolve-shape hover)))]
|
(mapv resolve-shape hover)))]
|
||||||
#(l/derived hover->shapes st/state)))
|
#(l/derived hover->shapes st/state)))
|
||||||
|
|
||||||
(mf/defc selection-feedback [{:keys [frame]}]
|
(mf/defc selection-feedback [{:keys [frame]}]
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
(ns app.util.text)
|
(ns app.util.text
|
||||||
|
(:require
|
||||||
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
(defonce default-text-attrs
|
(defonce default-text-attrs
|
||||||
{:font-id "sourcesanspro"
|
{:font-id "sourcesanspro"
|
||||||
|
@ -11,7 +13,9 @@
|
||||||
:letter-spacing "0"
|
:letter-spacing "0"
|
||||||
:text-transform "none"
|
:text-transform "none"
|
||||||
:text-align "left"
|
:text-align "left"
|
||||||
:text-decoration "none"})
|
:text-decoration "none"
|
||||||
|
:fill-color "#000000"
|
||||||
|
:fill-opacity 1})
|
||||||
|
|
||||||
(def typography-fields
|
(def typography-fields
|
||||||
[:font-id
|
[:font-id
|
||||||
|
@ -38,3 +42,20 @@
|
||||||
[map-fn node]
|
[map-fn node]
|
||||||
(cond-> (map-fn node)
|
(cond-> (map-fn node)
|
||||||
(:children node) (update :children (fn [children] (mapv #(map-node map-fn %) children)))))
|
(: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)))
|
||||||
|
|
Loading…
Add table
Reference in a new issue