mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 14:00:37 +00:00
✨ Add scale options panel to the right sidebar
This commit is contained in:
parent
c345c7cbaa
commit
9957cba277
3
frontend/resources/images/icons/scale.svg
Normal file
3
frontend/resources/images/icons/scale.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M5.88 10.12L10.12 5.88M5.88 8L5.88 10.12L8 10.12M8 5.88L10.12 5.88L10.12 8M3.4 8.35L3.4 12.6L7.65 12.6M8.35 3.4L12.6 3.4L12.6 7.65"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 262 B |
@ -1688,6 +1688,7 @@
|
||||
(dm/export dwt/update-positions)
|
||||
(dm/export dwt/flip-horizontal-selected)
|
||||
(dm/export dwt/flip-vertical-selected)
|
||||
(dm/export dwt/scale-selected)
|
||||
(dm/export dwly/set-opacity)
|
||||
|
||||
;; Common
|
||||
|
||||
@ -57,6 +57,14 @@
|
||||
(.preventDefault event)
|
||||
(st/emit! (toggle-layout-flag :display-guides)))))
|
||||
|
||||
(defn- escape
|
||||
"Leave the scale content mode when it is active, keeping the
|
||||
selection; otherwise clear the current drawing and selection."
|
||||
[]
|
||||
(if (contains? (deref refs/workspace-layout) :scale-text)
|
||||
(st/emit! :interrupt (dw/remove-layout-flag :scale-text))
|
||||
(st/emit! :interrupt (dwdc/clear-drawing) (dw/deselect-all true))))
|
||||
|
||||
(defn- emit-when-no-readonly
|
||||
[& events]
|
||||
(let [can-edit? (:can-edit (deref refs/permissions))
|
||||
@ -178,7 +186,7 @@
|
||||
:command "escape"
|
||||
:subsections [:edit]
|
||||
:section [:workspace]
|
||||
:fn #(st/emit! :interrupt (dwdc/clear-drawing) (dw/deselect-all true))}
|
||||
:fn escape}
|
||||
|
||||
:find {:tooltip (ds/meta "F") :command (ds/c-mod "f") :subsections [:edit]
|
||||
:label (fn [] (tr "shortcuts.find"))
|
||||
|
||||
@ -1593,6 +1593,59 @@
|
||||
(rx/of (dwm/apply-wasm-modifiers modifiers {:ignore-snap-pixel true}))
|
||||
(rx/of (dwm/apply-modifiers {:modifiers modifiers :ignore-snap-pixel true}))))))))
|
||||
|
||||
;; -- Scale ---------------------------------------------------------
|
||||
|
||||
(defn- anchor->point
|
||||
"Return the point of `rect` that matches the `anchor`, a
|
||||
`[horizontal vertical]` pair where horizontal is one of `:left`,
|
||||
`:center` or `:right` and vertical one of `:top`, `:center` or
|
||||
`:bottom`."
|
||||
[rect [h v]]
|
||||
(let [{:keys [x y width height]} rect]
|
||||
(gpt/point (case h :left x :right (+ x width) (+ x (/ width 2)))
|
||||
(case v :top y :bottom (+ y height) (+ y (/ height 2))))))
|
||||
|
||||
(defn scale-selected
|
||||
"Scale the selected shapes and their content (strokes, texts,
|
||||
shadows...) by `factor`, keeping the `anchor` point of the selection
|
||||
bounds in place. Behaves like a resize in the scale content mode."
|
||||
[factor anchor]
|
||||
(assert (and (number? factor) (pos? factor)) "expected a positive factor")
|
||||
(ptk/reify ::scale-selected
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
shapes (->> (dsh/lookup-selected state {:omit-blocked? true})
|
||||
(map (d/getf objects))
|
||||
(remove ctk/is-variant-container?))]
|
||||
(if (or (empty? shapes) (mth/close? factor 1))
|
||||
(rx/empty)
|
||||
(let [ids (map :id shapes)
|
||||
origin (anchor->point (gsh/shapes->rect shapes) anchor)
|
||||
scalev (gpt/point factor factor)
|
||||
|
||||
get-modifier
|
||||
(fn [shape]
|
||||
(let [grow-type (get shape :grow-type)
|
||||
new-grow-type (when (cfh/text-shape? shape)
|
||||
(dwm/next-grow-type grow-type scalev))]
|
||||
(cond-> (ctm/resize-modifiers scalev origin)
|
||||
:always
|
||||
(ctm/scale-content factor)
|
||||
|
||||
(and (some? new-grow-type) (not= new-grow-type grow-type))
|
||||
(ctm/change-property :grow-type new-grow-type))))
|
||||
|
||||
modif-tree (dwm/build-modif-tree ids objects get-modifier)]
|
||||
|
||||
(if (features/active-feature? state "render-wasm/v1")
|
||||
(rx/of (dwm/apply-wasm-modifiers modif-tree
|
||||
:ignore-constraints true
|
||||
:ignore-snap-pixel true))
|
||||
(rx/of (dwm/apply-modifiers {:modifiers modif-tree
|
||||
:ignore-constraints true
|
||||
:ignore-snap-pixel true})))))))))
|
||||
|
||||
(defn fit-layout-modifiers
|
||||
[objects frame]
|
||||
;; Set temporaly the auto flag and calculate a reflow to resize and position
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
[app.main.constants :refer [max-input-length]]
|
||||
[app.main.ui.ds.controls.select :refer [handle-focus-change]]
|
||||
[app.main.ui.ds.controls.shared.options-dropdown :refer [options-dropdown* schema:option]]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list] :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.globals :as globals]
|
||||
[app.util.keyboard :as kbd]
|
||||
@ -23,6 +23,9 @@
|
||||
[rumext.v2.util :as mfu])
|
||||
(:import goog.events.EventType))
|
||||
|
||||
(def ^:private schema:icon
|
||||
[:and :string [:fn #(contains? icon-list %)]])
|
||||
|
||||
(def ^:private schema:combobox
|
||||
[:map
|
||||
[:id {:optional true} :string]
|
||||
@ -30,6 +33,7 @@
|
||||
[:class {:optional true} :string]
|
||||
[:max-length {:optional true} :int]
|
||||
[:placeholder {:optional true} :string]
|
||||
[:icon {:optional true} [:maybe schema:icon]]
|
||||
[:disabled {:optional true} :boolean]
|
||||
[:default-selected {:optional true} :string]
|
||||
[:select-only {:optional true} :boolean]
|
||||
@ -39,7 +43,7 @@
|
||||
|
||||
(mf/defc combobox*
|
||||
{::mf/schema schema:combobox}
|
||||
[{:keys [id options class placeholder disabled has-error default-selected select-only max-length empty-to-end on-change] :rest props}]
|
||||
[{:keys [id options class placeholder icon disabled has-error default-selected select-only max-length empty-to-end on-change] :rest props}]
|
||||
(let [;; NOTE: we use mfu/bean here for transparently handle
|
||||
;; options provide as clojure data structures or javascript
|
||||
;; plain objects and lists.
|
||||
@ -239,8 +243,9 @@
|
||||
(d/seek #(= selected-id (get % :id)) options)))
|
||||
|
||||
icon
|
||||
(when selected-option
|
||||
(get selected-option :icon))
|
||||
(or (when selected-option
|
||||
(get selected-option :icon))
|
||||
icon)
|
||||
|
||||
avatar
|
||||
(when selected-option
|
||||
|
||||
@ -53,6 +53,18 @@ These are available in the `app.main.ds.foundations.assets.icon` namespace.
|
||||
]}]
|
||||
```
|
||||
|
||||
The `combobox*` itself also accepts an optional `icon`. It shows at the start of
|
||||
the input when the selected option has no icon of its own, for example when
|
||||
the user types a value that matches no option.
|
||||
|
||||
```clj
|
||||
[:> combobox*
|
||||
{:icon i/scale
|
||||
:default-selected "1"
|
||||
:options [{ :label "1x" :id "1" }
|
||||
{ :label "2x" :id "2" }]}]
|
||||
```
|
||||
|
||||
|
||||
### Avatars
|
||||
|
||||
|
||||
@ -72,6 +72,12 @@ export const WithIcons = {
|
||||
},
|
||||
};
|
||||
|
||||
export const WithIcon = {
|
||||
args: {
|
||||
icon: "scale",
|
||||
},
|
||||
};
|
||||
|
||||
export const EmptyToEnd = {
|
||||
args: {
|
||||
emptyToEnd: true,
|
||||
|
||||
@ -235,6 +235,7 @@
|
||||
(def ^:icon-id rotation "rotation")
|
||||
(def ^:icon-id row "row")
|
||||
(def ^:icon-id row-reverse "row-reverse")
|
||||
(def ^:icon-id scale "scale")
|
||||
(def ^:icon-id search "search")
|
||||
(def ^:icon-id separate-nodes "separate-nodes")
|
||||
(def ^:icon-id settings "settings")
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
|
||||
[app.main.ui.workspace.sidebar.layers :refer [layers-toolbox*]]
|
||||
[app.main.ui.workspace.sidebar.options :refer [options-toolbox*]]
|
||||
[app.main.ui.workspace.sidebar.scale :refer [scale-sidebar*]]
|
||||
[app.main.ui.workspace.sidebar.shortcuts :refer [shortcuts-container*]]
|
||||
[app.main.ui.workspace.sidebar.sitemap :refer [sitemap*]]
|
||||
[app.main.ui.workspace.sidebar.versions :refer [versions-toolbox*]]
|
||||
@ -286,6 +287,7 @@
|
||||
[{:keys [layout section file-id page-id drawing-tool active-tokens] :as props}]
|
||||
(let [is-comments? (= drawing-tool :comments)
|
||||
is-history? (contains? layout :document-history)
|
||||
is-scale? (contains? layout :scale-text)
|
||||
is-inspect? (= section :inspect)
|
||||
is-debug? (= section :debug)
|
||||
|
||||
@ -295,6 +297,7 @@
|
||||
can-be-expanded?
|
||||
(and (not is-comments?)
|
||||
(not is-history?)
|
||||
(not is-scale?)
|
||||
is-inspect?
|
||||
(= current-section :code))
|
||||
|
||||
@ -355,6 +358,9 @@
|
||||
is-history?
|
||||
[:> history-content* {}]
|
||||
|
||||
is-scale?
|
||||
[:> scale-sidebar* {}]
|
||||
|
||||
:else
|
||||
(let [props (mf/spread-props props
|
||||
{:on-change-section on-change-section
|
||||
|
||||
228
frontend/src/app/main/ui/workspace/sidebar/scale.cljs
Normal file
228
frontend/src/app/main/ui/workspace/sidebar/scale.cljs
Normal file
@ -0,0 +1,228 @@
|
||||
;; 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/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
(ns app.main.ui.workspace.sidebar.scale
|
||||
"Right sidebar panel of the scale content mode (K shortcut)."
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.math :as mth]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.ds.controls.combobox :refer [combobox*]]
|
||||
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
|
||||
[app.main.ui.ds.controls.utilities.label :refer [label*]]
|
||||
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||
[app.main.ui.ds.product.panel-title :refer [panel-title*]]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def ^:private scale-presets
|
||||
[0.5 0.75 1 1.5 2 3 4])
|
||||
|
||||
(def ^:private anchors
|
||||
[[:left :top] [:center :top] [:right :top]
|
||||
[:left :center] [:center :center] [:right :center]
|
||||
[:left :bottom] [:center :bottom] [:right :bottom]])
|
||||
|
||||
(def ^:private indexed-anchors
|
||||
(d/enumerate anchors))
|
||||
|
||||
(def ^:private default-anchor
|
||||
[:center :center])
|
||||
|
||||
(defn- factor->id
|
||||
[factor]
|
||||
(str (mth/precision factor 2)))
|
||||
|
||||
(defn- parse-factor
|
||||
"Parse a scale typed by the user, like `2`, `1.5x` or `0,5x`"
|
||||
[value]
|
||||
(let [factor (-> (str value)
|
||||
(str/trim)
|
||||
(str/rtrim "xX")
|
||||
(str/replace "," ".")
|
||||
(d/parse-double))]
|
||||
(when (and (some? factor) (pos? factor))
|
||||
factor)))
|
||||
|
||||
(defn- anchor-label
|
||||
[anchor]
|
||||
(case anchor
|
||||
[:left :top] (tr "workspace.scale.anchor.top-left")
|
||||
[:center :top] (tr "workspace.scale.anchor.top-center")
|
||||
[:right :top] (tr "workspace.scale.anchor.top-right")
|
||||
[:left :center] (tr "workspace.scale.anchor.center-left")
|
||||
[:center :center] (tr "workspace.scale.anchor.center-center")
|
||||
[:right :center] (tr "workspace.scale.anchor.center-right")
|
||||
[:left :bottom] (tr "workspace.scale.anchor.bottom-left")
|
||||
[:center :bottom] (tr "workspace.scale.anchor.bottom-center")
|
||||
[:right :bottom] (tr "workspace.scale.anchor.bottom-right")))
|
||||
|
||||
(mf/defc anchor-point-selector*
|
||||
{::mf/private true}
|
||||
[{:keys [value disabled on-change aria-labelledby]}]
|
||||
(let [on-click
|
||||
(mf/use-fn
|
||||
(mf/deps on-change)
|
||||
(fn [event]
|
||||
(let [index (-> (dom/get-current-target event)
|
||||
(dom/get-data "index")
|
||||
(d/parse-integer))]
|
||||
(on-change (nth anchors index)))))]
|
||||
|
||||
[:div {:class (stl/css :anchor-grid)
|
||||
:role "radiogroup"
|
||||
:aria-labelledby aria-labelledby}
|
||||
(for [[index anchor] indexed-anchors]
|
||||
(let [selected? (= anchor value)]
|
||||
[:button {:key index
|
||||
:type "button"
|
||||
:role "radio"
|
||||
:class (stl/css-case :anchor-point true
|
||||
:center-area (= anchor default-anchor)
|
||||
:selected selected?)
|
||||
:aria-checked selected?
|
||||
:aria-label (anchor-label anchor)
|
||||
:disabled disabled
|
||||
:data-index index
|
||||
:on-click on-click}
|
||||
[:span {:class (stl/css :anchor-mark)}]]))]))
|
||||
|
||||
(mf/defc scale-sidebar*
|
||||
[]
|
||||
(let [selected (mf/deref refs/selected-shapes)
|
||||
shapes-ref (mf/with-memo [selected]
|
||||
(refs/objects-by-id selected))
|
||||
shapes (mf/deref shapes-ref)
|
||||
|
||||
rect (mf/with-memo [shapes]
|
||||
(when (seq shapes)
|
||||
(gsh/shapes->rect shapes)))
|
||||
|
||||
width (get rect :width)
|
||||
height (get rect :height)
|
||||
size (when rect (max width height))
|
||||
disabled (or (nil? size) (mth/almost-zero? size))
|
||||
|
||||
;; The scale factor is relative to the size of the selection
|
||||
;; when it was selected, so it is only reset when the
|
||||
;; selection changes.
|
||||
base-size (mf/with-memo [selected]
|
||||
size)
|
||||
|
||||
factor (if (and (not disabled) (some? base-size) (pos? base-size))
|
||||
(/ size base-size)
|
||||
1)
|
||||
|
||||
factor-id (factor->id factor)
|
||||
|
||||
anchor* (mf/use-state default-anchor)
|
||||
anchor (deref anchor*)
|
||||
|
||||
width-id (mf/use-id)
|
||||
height-id (mf/use-id)
|
||||
scale-id (mf/use-id)
|
||||
anchor-id (mf/use-id)
|
||||
|
||||
scale-options
|
||||
(mf/with-memo []
|
||||
(mapv (fn [factor]
|
||||
{:id (factor->id factor)
|
||||
:label (str (factor->id factor) "x")})
|
||||
scale-presets))
|
||||
|
||||
default-selected
|
||||
(if (some #(= factor-id (:id %)) scale-options)
|
||||
factor-id
|
||||
(str factor-id "x"))
|
||||
|
||||
scale-to
|
||||
(mf/use-fn
|
||||
(mf/deps size anchor)
|
||||
(fn [new-size]
|
||||
(when (and (some? size) (pos? size) (pos? new-size))
|
||||
(st/emit! (dw/scale-selected (/ new-size size) anchor)))))
|
||||
|
||||
on-width-change
|
||||
(mf/use-fn
|
||||
(mf/deps scale-to width size)
|
||||
(fn [value]
|
||||
(when (and (number? value) (pos? width))
|
||||
(scale-to (* size (/ value width))))))
|
||||
|
||||
on-height-change
|
||||
(mf/use-fn
|
||||
(mf/deps scale-to height size)
|
||||
(fn [value]
|
||||
(when (and (number? value) (pos? height))
|
||||
(scale-to (* size (/ value height))))))
|
||||
|
||||
on-scale-change
|
||||
(mf/use-fn
|
||||
(mf/deps scale-to base-size factor-id)
|
||||
(fn [value]
|
||||
;; The combobox also reports its value on blur, skip it when
|
||||
;; it is the same rounded factor we are already showing.
|
||||
(when-let [factor (parse-factor value)]
|
||||
(when (not= factor-id (factor->id factor))
|
||||
(scale-to (* base-size factor))))))
|
||||
|
||||
on-anchor-change
|
||||
(mf/use-fn
|
||||
#(reset! anchor* %))
|
||||
|
||||
on-close
|
||||
(mf/use-fn
|
||||
#(st/emit! (dw/remove-layout-flag :scale-text)))]
|
||||
|
||||
[:div {:class (stl/css :scale-sidebar)}
|
||||
[:> panel-title* {:class (stl/css :scale-title)
|
||||
:text (tr "workspace.scale.title")
|
||||
:on-close on-close}]
|
||||
|
||||
[:div {:class (stl/css :scale-content)}
|
||||
[:div {:class (stl/css :field)}
|
||||
[:> label* {:for width-id} (tr "workspace.options.width")]
|
||||
[:> numeric-input* {:id width-id
|
||||
:icon i/character-w
|
||||
:min 0.01
|
||||
:disabled disabled
|
||||
:placeholder "--"
|
||||
:value width
|
||||
:on-change on-width-change}]]
|
||||
|
||||
[:div {:class (stl/css :field)}
|
||||
[:> label* {:for height-id} (tr "workspace.options.height")]
|
||||
[:> numeric-input* {:id height-id
|
||||
:icon i/character-h
|
||||
:min 0.01
|
||||
:disabled disabled
|
||||
:placeholder "--"
|
||||
:value height
|
||||
:on-change on-height-change}]]
|
||||
|
||||
[:div {:class (stl/css :field)}
|
||||
[:> label* {:for scale-id} (tr "workspace.scale.scale")]
|
||||
[:> combobox* {:id scale-id
|
||||
:icon i/scale
|
||||
:disabled disabled
|
||||
:options scale-options
|
||||
:default-selected default-selected
|
||||
:on-change on-scale-change}]]
|
||||
|
||||
[:div {:class (stl/css :field)}
|
||||
[:span {:id anchor-id
|
||||
:class (stl/css :anchor-title)}
|
||||
(tr "workspace.scale.anchor-point")]
|
||||
[:> anchor-point-selector* {:value anchor
|
||||
:disabled disabled
|
||||
:aria-labelledby anchor-id
|
||||
:on-change on-anchor-change}]]]]))
|
||||
99
frontend/src/app/main/ui/workspace/sidebar/scale.scss
Normal file
99
frontend/src/app/main/ui/workspace/sidebar/scale.scss
Normal file
@ -0,0 +1,99 @@
|
||||
// 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/.
|
||||
//
|
||||
// Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
@use "ds/_borders.scss" as *;
|
||||
@use "ds/_sizes.scss" as *;
|
||||
@use "ds/_utils.scss" as *;
|
||||
@use "ds/typography.scss" as t;
|
||||
|
||||
.scale-sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--panel-background-color);
|
||||
}
|
||||
|
||||
.scale-title {
|
||||
margin: var(--sp-s) var(--sp-s) 0;
|
||||
}
|
||||
|
||||
.scale-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--sp-l) var(--sp-s);
|
||||
padding: var(--sp-l) var(--sp-m);
|
||||
}
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--sp-xs);
|
||||
min-inline-size: 0;
|
||||
}
|
||||
|
||||
.anchor-title {
|
||||
@include t.use-typography("body-small");
|
||||
|
||||
color: var(--color-foreground-primary);
|
||||
}
|
||||
|
||||
.anchor-grid {
|
||||
--anchor-side-size: #{$sz-24};
|
||||
--anchor-center-size: #{px2rem(60)};
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: var(--anchor-side-size) var(--anchor-center-size) var(--anchor-side-size);
|
||||
grid-template-rows: var(--anchor-side-size) var(--anchor-center-size) var(--anchor-side-size);
|
||||
inline-size: fit-content;
|
||||
block-size: fit-content;
|
||||
border-radius: $br-8;
|
||||
background-color: var(--color-background-tertiary);
|
||||
}
|
||||
|
||||
// The unselected marks are 2/3 of the selected one, ring included
|
||||
$anchor-selected-size: px2rem(10);
|
||||
|
||||
.anchor-point {
|
||||
--anchor-mark-size: calc((#{$anchor-selected-size} + 2 * #{$b-2}) * 2 / 3);
|
||||
--anchor-mark-color: var(--color-foreground-secondary);
|
||||
--anchor-mark-outline-color: transparent;
|
||||
|
||||
all: unset;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
--anchor-mark-color: var(--color-foreground-primary);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: $b-1 solid var(--color-accent-primary);
|
||||
border-radius: $br-4;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
--anchor-mark-size: #{$anchor-selected-size};
|
||||
--anchor-mark-color: var(--color-accent-primary);
|
||||
--anchor-mark-outline-color: var(--color-accent-primary-muted);
|
||||
}
|
||||
}
|
||||
|
||||
.center-area {
|
||||
border-radius: $br-8;
|
||||
background-color: var(--color-background-primary);
|
||||
}
|
||||
|
||||
.anchor-mark {
|
||||
inline-size: var(--anchor-mark-size);
|
||||
block-size: var(--anchor-mark-size);
|
||||
border-radius: $br-4;
|
||||
background-color: var(--anchor-mark-color);
|
||||
outline: $b-2 solid var(--anchor-mark-outline-color);
|
||||
}
|
||||
@ -8340,6 +8340,54 @@ msgstr "'%s' PLUGIN IS INSTALLED FOR YOUR USER!"
|
||||
msgid "workspace.plugins.try-out.try"
|
||||
msgstr "TRY PLUGIN"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor-point"
|
||||
msgstr "Anchor point"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.bottom-center"
|
||||
msgstr "Bottom center"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.bottom-left"
|
||||
msgstr "Bottom left"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.bottom-right"
|
||||
msgstr "Bottom right"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.center-center"
|
||||
msgstr "Center"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.center-left"
|
||||
msgstr "Center left"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.center-right"
|
||||
msgstr "Center right"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.top-center"
|
||||
msgstr "Top center"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.top-left"
|
||||
msgstr "Top left"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.top-right"
|
||||
msgstr "Top right"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.scale"
|
||||
msgstr "Scale"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.title"
|
||||
msgstr "Scale"
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs:659
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Add flex layout"
|
||||
|
||||
@ -8431,6 +8431,54 @@ msgstr "¡LA EXTENSIÓN '%s' HA SIDO INSTALADA PARA TU USUARIO!"
|
||||
msgid "workspace.plugins.try-out.try"
|
||||
msgstr "PROBAR PLUGIN"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor-point"
|
||||
msgstr "Punto de anclaje"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.bottom-center"
|
||||
msgstr "Abajo en el centro"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.bottom-left"
|
||||
msgstr "Abajo a la izquierda"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.bottom-right"
|
||||
msgstr "Abajo a la derecha"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.center-center"
|
||||
msgstr "Centro"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.center-left"
|
||||
msgstr "Centro a la izquierda"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.center-right"
|
||||
msgstr "Centro a la derecha"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.top-center"
|
||||
msgstr "Arriba en el centro"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.top-left"
|
||||
msgstr "Arriba a la izquierda"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.anchor.top-right"
|
||||
msgstr "Arriba a la derecha"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.scale"
|
||||
msgstr "Escala"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/scale.cljs
|
||||
msgid "workspace.scale.title"
|
||||
msgstr "Escalado"
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs:659
|
||||
msgid "workspace.shape.menu.add-flex"
|
||||
msgstr "Añadir flex layout"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user