Compare commits

..

1 Commits

Author SHA1 Message Date
Pablo Alba
0bb74ed722 🐛 Fix viewer can update library (#8231) 2026-01-28 20:48:52 +01:00
9 changed files with 348 additions and 249 deletions

View File

@@ -31,6 +31,7 @@
- Fix unhandled exception on open-new-window helper [Github #7787](https://github.com/penpot/penpot/issues/7787) - Fix unhandled exception on open-new-window helper [Github #7787](https://github.com/penpot/penpot/issues/7787)
- Fix exception on uploading large fonts [Github #8135](https://github.com/penpot/penpot/pull/8135) - Fix exception on uploading large fonts [Github #8135](https://github.com/penpot/penpot/pull/8135)
- Fix boolean operators in menu for boards [Taiga #13174](https://tree.taiga.io/project/penpot/issue/13174) - Fix boolean operators in menu for boards [Taiga #13174](https://tree.taiga.io/project/penpot/issue/13174)
- Fix viewer can update library [Taiga #13186](https://tree.taiga.io/project/penpot/issue/13186)
## 2.13.0 (Unreleased) ## 2.13.0 (Unreleased)

View File

@@ -1205,6 +1205,7 @@
file (dsh/lookup-file state file-id) file (dsh/lookup-file state file-id)
file-data (get file :data) file-data (get file :data)
ignore-until (get file :ignore-sync-until) ignore-until (get file :ignore-sync-until)
permissions (:permissions state)
libraries-need-sync libraries-need-sync
(->> (vals (get state :files)) (->> (vals (get state :files))
@@ -1224,7 +1225,8 @@
do-dismiss do-dismiss
#(st/emit! ignore-sync (ntf/hide))] #(st/emit! ignore-sync (ntf/hide))]
(when (seq libraries-need-sync) (when (and (:can-edit permissions)
(seq libraries-need-sync))
(rx/of (ntf/dialog (rx/of (ntf/dialog
:content (tr "workspace.updates.there-are-updates") :content (tr "workspace.updates.there-are-updates")
:controls :inline-actions :controls :inline-actions

View File

@@ -3,15 +3,17 @@
(:require (:require
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.types.shape.radius :as ctsr] [app.common.types.shape.radius :as ctsr]
[app.common.types.token :as tk]
[app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.tokens.application :as dwta] [app.main.data.workspace.tokens.application :as dwta]
[app.main.features :as features] [app.main.features :as features]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.numeric-input :as deprecated-input] [app.main.ui.components.numeric-input :as deprecated-input]
[app.main.ui.context :as muc]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.main.ui.hooks :as hooks] [app.main.ui.hooks :as hooks]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[potok.v2.core :as ptk] [potok.v2.core :as ptk]
@@ -44,6 +46,63 @@
(identical? (get old-values :r4) (identical? (get old-values :r4)
(get new-values :r4))))) (get new-values :r4)))))
(mf/defc numeric-input-wrapper*
{::mf/private true}
[{:keys [values name applied-tokens align on-detach radius] :rest props}]
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
tokens (mf/with-memo [tokens name]
(delay
(-> (deref tokens)
(select-keys (get tk/tokens-by-input name))
(not-empty))))
on-detach-attr
(mf/use-fn
(mf/deps on-detach name)
#(on-detach % name))
r1-value (get applied-tokens :r1)
all-token-equal? (and (seq applied-tokens) (all-equal? applied-tokens))
all-values-equal? (all-equal? values)
applied-token (cond
(not (seq applied-tokens))
nil
(and (= radius :all) (or (not all-values-equal?) (not all-token-equal?)))
:multiple
(and all-token-equal? all-values-equal? (= radius :all))
r1-value
:else
(get applied-tokens radius))
placeholder (if (= radius :all)
(cond
(or (not all-values-equal?)
(not all-token-equal?))
(tr "settings.multiple")
:else
"--")
(cond
(or (= :multiple (:applied-tokens values))
(= :multiple (get values name)))
(tr "settings.multiple")
:else
"--"))
props (mf/spread-props props
{:placeholder placeholder
:applied-token applied-token
:tokens (if (delay? tokens) @tokens tokens)
:align align
:on-detach on-detach-attr
:value values})]
[:> numeric-input* props]))
(mf/defc border-radius-menu* (mf/defc border-radius-menu*
{::mf/wrap [#(mf/memo' % check-border-radius-menu-props)]} {::mf/wrap [#(mf/memo' % check-border-radius-menu-props)]}
[{:keys [class ids values applied-tokens]}] [{:keys [class ids values applied-tokens]}]
@@ -51,7 +110,6 @@
(features/use-feature "tokens/numeric-input") (features/use-feature "tokens/numeric-input")
all-values-equal? (all-equal? values) all-values-equal? (all-equal? values)
all-token-equal? (and (seq applied-tokens) (all-equal? applied-tokens))
radius-expanded* (mf/use-state false) radius-expanded* (mf/use-state false)
radius-expanded (deref radius-expanded*) radius-expanded (deref radius-expanded*)
@@ -177,27 +235,14 @@
:on-detach on-detach-all :on-detach on-detach-all
:icon i/corner-radius :icon i/corner-radius
:min 0 :min 0
:attr :border-radius :name :border-radius
:nillable true :nillable true
:property (tr "workspace.options.radius") :property (tr "workspace.options.radius")
:class (stl/css :radius-wrapper) :class (stl/css :radius-wrapper)
:applied-token (cond :applied-tokens applied-tokens
(not (seq applied-tokens)) :radius :all
nil
(or (not all-values-equal?) (not all-token-equal?))
:multiple
:else
(get applied-tokens :r1))
:align :right :align :right
:placeholder (cond :values (if all-values-equal?
(or (not all-values-equal?)
(not all-token-equal?))
(tr "settings.multiple")
:else
"--")
:value (if all-values-equal?
(if (nil? (:r1 values)) (if (nil? (:r1 values))
0 0
(:r1 values)) (:r1 values))
@@ -231,76 +276,56 @@
{:on-change on-radius-r1-change {:on-change on-radius-r1-change
:on-detach on-detach-r1 :on-detach on-detach-r1
:min 0 :min 0
:attr :border-radius :name :border-radius
:property (tr "workspace.options.radius-top-left") :property (tr "workspace.options.radius-top-left")
:applied-token (get applied-tokens :r1) :applied-tokens applied-tokens
:radius :r1
:align :right :align :right
:placeholder (cond
(or (= :multiple (get applied-tokens :r1))
(= :multiple (get values :r1)))
(tr "settings.multiple")
:else
"--")
:class (stl/css :radius-wrapper :dropdown-offset) :class (stl/css :radius-wrapper :dropdown-offset)
:inner-class (stl/css :no-icon-input) :inner-class (stl/css :no-icon-input)
:value (:r1 values)}] :values (:r1 values)}]
[:> numeric-input-wrapper* [:> numeric-input-wrapper*
{:on-change on-radius-r2-change {:on-change on-radius-r2-change
:on-detach on-detach-r2 :on-detach on-detach-r2
:min 0 :min 0
:attr :border-radius :name :border-radius
:nillable true :nillable true
:property (tr "workspace.options.radius-top-right") :property (tr "workspace.options.radius-top-right")
:applied-token (get applied-tokens :r2) :applied-tokens applied-tokens
:align :right :align :right
:class (stl/css :radius-wrapper) :class (stl/css :radius-wrapper)
:inner-class (stl/css :no-icon-input) :inner-class (stl/css :no-icon-input)
:placeholder (cond :radius :r2
(or (= :multiple (get applied-tokens :r2)) :values (:r2 values)}]
(= :multiple (get values :r2)))
(tr "settings.multiple")
:else
"--")
:value (:r2 values)}]
[:> numeric-input-wrapper* [:> numeric-input-wrapper*
{:on-change on-radius-r4-change {:on-change on-radius-r4-change
:on-detach on-detach-r4 :on-detach on-detach-r4
:min 0 :min 0
:attr :border-radius :name :border-radius
:nillable true :nillable true
:property (tr "workspace.options.radius-bottom-left") :property (tr "workspace.options.radius-bottom-left")
:applied-token (get applied-tokens :r4) :applied-tokens applied-tokens
:class (stl/css :radius-wrapper :dropdown-offset) :class (stl/css :radius-wrapper :dropdown-offset)
:inner-class (stl/css :no-icon-input) :inner-class (stl/css :no-icon-input)
:placeholder (cond :radius :r4
(or (= :multiple (get applied-tokens :r4))
(= :multiple (get values :r4)))
(tr "settings.multiple")
:else
"--")
:align :right :align :right
:value (:r4 values)}] :values (:r4 values)}]
[:> numeric-input-wrapper* [:> numeric-input-wrapper*
{:on-change on-radius-r3-change {:on-change on-radius-r3-change
:on-detach on-detach-r3 :on-detach on-detach-r3
:min 0 :min 0
:attr :border-radius :name :border-radius
:nillable true :nillable true
:property (tr "workspace.options.radius-bottom-right") :property (tr "workspace.options.radius-bottom-right")
:applied-token (get applied-tokens :r3) :applied-tokens applied-tokens
:placeholder (cond :radius :r3
(or (= :multiple (get applied-tokens :r3))
(= :multiple (get values :r3)))
(tr "settings.multiple")
:else
"--")
:align :right :align :right
:class (stl/css :radius-wrapper) :class (stl/css :radius-wrapper)
:inner-class (stl/css :no-icon-input) :inner-class (stl/css :no-icon-input)
:value (:r3 values)}]] :values (:r3 values)}]]
[:div {:class (stl/css :radius-4)} [:div {:class (stl/css :radius-4)}
[:div {:class (stl/css :small-input)} [:div {:class (stl/css :small-input)}

View File

@@ -1,35 +0,0 @@
(ns app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens
(:require
[app.common.types.token :as tk]
[app.main.ui.context :as muc]
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
[app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf]))
(mf/defc numeric-input-wrapper*
[{:keys [value attr applied-token align on-detach placeholder input-type] :rest props}]
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
tokens (mf/with-memo [tokens input-type]
(delay
(-> (deref tokens)
(select-keys (get tk/tokens-by-input (or input-type attr)))
(not-empty))))
on-detach-attr
(mf/use-fn
(mf/deps on-detach attr)
#(on-detach % attr))
props (mf/spread-props props
{:placeholder (or placeholder
(if (= :multiple value)
(tr "settings.multiple")
"--"))
:applied-token applied-token
:tokens (if (delay? tokens) @tokens tokens)
:align align
:on-detach on-detach-attr
:name attr
:value value})]
[:> numeric-input* props]))

View File

@@ -9,6 +9,7 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.types.token :as tk]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.shapes :as dwsh]
[app.main.data.workspace.tokens.application :as dwta] [app.main.data.workspace.tokens.application :as dwta]
@@ -16,9 +17,10 @@
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.numeric-input :as deprecated-input] [app.main.ui.components.numeric-input :as deprecated-input]
[app.main.ui.components.select :refer [select]] [app.main.ui.components.select :refer [select]]
[app.main.ui.context :as muc]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
[app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.render-wasm.api :as wasm.api] [app.render-wasm.api :as wasm.api]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
@@ -60,6 +62,36 @@
(identical? (get old-values :hidden) (identical? (get old-values :hidden)
(get new-values :hidden))))) (get new-values :hidden)))))
(mf/defc numeric-input-wrapper*
{::mf/private true}
[{:keys [values name applied-tokens align on-detach] :rest props}]
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
tokens (mf/with-memo [tokens name]
(delay
(-> (deref tokens)
(select-keys (get tk/tokens-by-input name))
(not-empty))))
on-detach-attr (mf/use-fn
(mf/deps on-detach name)
#(on-detach % name))
applied-token (get applied-tokens name)
opacity-value (or (get values name) 1)
props (mf/spread-props props
{:placeholder (if (or (= :multiple (:applied-tokens values))
(= :multiple opacity-value))
(tr "settings.multiple")
"--")
:applied-token applied-token
:tokens (if (delay? tokens) @tokens tokens)
:align align
:on-detach on-detach-attr
:name name
:value (* 100 opacity-value)})]
[:> numeric-input* props]))
(mf/defc layer-menu* (mf/defc layer-menu*
{::mf/wrap [#(mf/memo' % check-layer-menu-props)]} {::mf/wrap [#(mf/memo' % check-layer-menu-props)]}
[{:keys [ids values applied-tokens]}] [{:keys [ids values applied-tokens]}]
@@ -218,24 +250,22 @@
:on-pointer-enter-option handle-blend-mode-enter :on-pointer-enter-option handle-blend-mode-enter
:on-pointer-leave-option handle-blend-mode-leave}]] :on-pointer-leave-option handle-blend-mode-leave}]]
(if token-numeric-inputs (if token-numeric-inputs
[:> numeric-input-wrapper* [:> numeric-input-wrapper*
{:on-change on-opacity-change {:on-change on-opacity-change
:on-detach on-detach-token :on-detach on-detach-token
:icon i/percentage :icon i/percentage
:min 0 :min 0
:max 100 :max 100
:attr :opacity :name :opacity
:property (tr "workspace.options.opacity") :property (tr "workspace.options.opacity")
:applied-token (get applied-tokens :opacity) :applied-tokens applied-tokens
:placeholder (if (or (= :multiple (get applied-tokens :opacity))
(= :multiple (or (get values name) 1)))
(tr "settings.multiple")
"--")
:align :right :align :right
:class (stl/css :numeric-input-wrapper) :class (stl/css :numeric-input-wrapper)
:value (* 100 :values values}]
(or (get values name) 1))}]
[:div {:class (stl/css :input) [:div {:class (stl/css :input)
:title (tr "workspace.options.opacity")} :title (tr "workspace.options.opacity")}

View File

@@ -11,6 +11,7 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.common.types.token :as tk]
[app.config :as cf] [app.config :as cf]
[app.main.data.event :as-alias ev] [app.main.data.event :as-alias ev]
[app.main.data.workspace :as udw] [app.main.data.workspace :as udw]
@@ -24,14 +25,15 @@
[app.main.ui.components.numeric-input :as deprecated-input] [app.main.ui.components.numeric-input :as deprecated-input]
[app.main.ui.components.select :refer [select]] [app.main.ui.components.select :refer [select]]
[app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.components.title-bar :refer [title-bar*]]
[app.main.ui.context :as muc]
[app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
[app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]]
[app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.formats :as fmt] [app.main.ui.formats :as fmt]
[app.main.ui.hooks :as h] [app.main.ui.hooks :as h]
[app.main.ui.icons :as deprecated-icon] [app.main.ui.icons :as deprecated-icon]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[app.util.keyboard :as kbd] [app.util.keyboard :as kbd]
@@ -46,6 +48,44 @@
:column i/column :column i/column
:column-reverse i/column-reverse)) :column-reverse i/column-reverse))
(mf/defc numeric-input-wrapper*
{::mf/private true}
[{:keys [values name applied-tokens align on-detach] :rest props}]
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
input-type (cond
(some #{:p2 :p4} [name])
:horizontal-padding
(some #{:p1 :p3} [name])
:vertical-padding
:else
name)
tokens (mf/with-memo [tokens input-type]
(delay
(-> (deref tokens)
(select-keys (get tk/tokens-by-input input-type))
(not-empty))))
on-detach-attr
(mf/use-fn
(mf/deps on-detach name)
#(on-detach % name))
props (mf/spread-props props
{:placeholder (if (or (= :multiple (:applied-tokens values))
(= :multiple (get values name))
(nil? (get values name)))
(tr "settings.multiple")
"--")
:class (stl/css :numeric-input-layout)
:applied-token (get applied-tokens name)
:tokens tokens
:align align
:on-detach on-detach-attr
:value (get values name)})]
[:> numeric-input* props]))
;; FLEX COMPONENTS ;; FLEX COMPONENTS
(def layout-container-flex-attrs (def layout-container-flex-attrs
@@ -375,17 +415,11 @@
:on-focus on-focus-p1 :on-focus on-focus-p1
:icon i/padding-top-bottom :icon i/padding-top-bottom
:min 0 :min 0
:attr :p1 :name :p1
:input-type :vertical-padding
:property (tr "workspace.layout-grid.editor.padding.vertical") :property (tr "workspace.layout-grid.editor.padding.vertical")
:nillable true :nillable true
:placeholder (if (or (= :multiple applied-to-p1) :applied-tokens {:p1 applied-to-p1}
(= :multiple p1) :values {:p1 p1}}]
(nil? p1))
(tr "settings.multiple")
"--")
:applied-token applied-to-p1
:value p1}]
[:div {:class (stl/css :padding-simple) [:div {:class (stl/css :padding-simple)
:title (tr "workspace.layout-grid.editor.padding.vertical")} :title (tr "workspace.layout-grid.editor.padding.vertical")}
@@ -410,18 +444,12 @@
:on-focus on-focus-p2 :on-focus on-focus-p2
:icon i/padding-left-right :icon i/padding-left-right
:min 0 :min 0
:attr :p2 :name :p2
:input-type :horizontal-padding
:align :right :align :right
:property (tr "workspace.layout-grid.editor.padding.horizontal") :property (tr "workspace.layout-grid.editor.padding.horizontal")
:nillable true :nillable true
:applied-token applied-to-p2 :applied-tokens {:p2 applied-to-p2}
:placeholder (if (or (= :multiple applied-to-p2) :values {:p2 p2}}]
(= :multiple p2)
(nil? p2))
(tr "settings.multiple")
"--")
:value p2}]
[:div {:class (stl/css :padding-simple) [:div {:class (stl/css :padding-simple)
:title (tr "workspace.layout-grid.editor.padding.horizontal")} :title (tr "workspace.layout-grid.editor.padding.horizontal")}
@@ -448,11 +476,6 @@
p3 (:p3 value) p3 (:p3 value)
p4 (:p4 value) p4 (:p4 value)
applied-to-p1 (:p1 applied-tokens)
applied-to-p2 (:p2 applied-tokens)
applied-to-p3 (:p3 applied-tokens)
applied-to-p4 (:p4 applied-tokens)
on-change' on-change'
(mf/use-fn (mf/use-fn
(mf/deps on-change ids) (mf/deps on-change ids)
@@ -512,15 +535,10 @@
:on-focus on-focus-p1 :on-focus on-focus-p1
:icon i/padding-top :icon i/padding-top
:min 0 :min 0
:attr :p1 :name :p1
:input-type :vertical-padding
:property (tr "workspace.layout-grid.editor.padding.top") :property (tr "workspace.layout-grid.editor.padding.top")
:placeholder (if (or (= :multiple applied-to-p1) :applied-tokens applied-tokens
(= :multiple p1)) :values value}]
(tr "settings.multiple")
"--")
:applied-token applied-to-p1
:value p1}]
[:div {:class (stl/css :padding-multiple) [:div {:class (stl/css :padding-multiple)
:title (tr "workspace.layout-grid.editor.padding.top")} :title (tr "workspace.layout-grid.editor.padding.top")}
@@ -545,16 +563,11 @@
:on-focus on-focus-p2 :on-focus on-focus-p2
:icon i/padding-right :icon i/padding-right
:min 0 :min 0
:attr :p2 :name :p2
:input-type :horizontal-padding
:align :right :align :right
:property (tr "workspace.layout-grid.editor.padding.right") :property (tr "workspace.layout-grid.editor.padding.right")
:placeholder (if (or (= :multiple applied-to-p2) :applied-tokens applied-tokens
(= :multiple p2)) :values value}]
(tr "settings.multiple")
"--")
:applied-token applied-to-p2
:value p2}]
[:div {:class (stl/css :padding-multiple) [:div {:class (stl/css :padding-multiple)
:title (tr "workspace.layout-grid.editor.padding.right")} :title (tr "workspace.layout-grid.editor.padding.right")}
@@ -579,15 +592,10 @@
:on-focus on-focus-p3 :on-focus on-focus-p3
:icon i/padding-bottom :icon i/padding-bottom
:min 0 :min 0
:attr :p3 :name :p3
:input-type :vertical-padding
:property (tr "workspace.layout-grid.editor.padding.bottom") :property (tr "workspace.layout-grid.editor.padding.bottom")
:placeholder (if (or (= :multiple applied-to-p3) :applied-tokens applied-tokens
(= :multiple p3)) :values value}]
(tr "settings.multiple")
"--")
:applied-token applied-to-p3
:value p3}]
[:div {:class (stl/css :padding-multiple) [:div {:class (stl/css :padding-multiple)
:title (tr "workspace.layout-grid.editor.padding.bottom")} :title (tr "workspace.layout-grid.editor.padding.bottom")}
@@ -613,15 +621,10 @@
:icon i/padding-left :icon i/padding-left
:min 0 :min 0
:align :right :align :right
:attr :p4 :name :p4
:input-type :horizontal-padding
:property (tr "workspace.layout-grid.editor.padding.left") :property (tr "workspace.layout-grid.editor.padding.left")
:placeholder (if (or (= :multiple applied-to-p4) :applied-tokens applied-tokens
(= :multiple p4)) :values value}]
(tr "settings.multiple")
"--")
:applied-token applied-to-p4
:value p4}]
[:div {:class (stl/css :padding-multiple) [:div {:class (stl/css :padding-multiple)
:title (tr "workspace.layout-grid.editor.padding.left")} :title (tr "workspace.layout-grid.editor.padding.left")}
@@ -754,16 +757,11 @@
:icon i/gap-vertical :icon i/gap-vertical
:nillable true :nillable true
:min 0 :min 0
:attr :row-gap :name :row-gap
:applied-tokens applied-tokens
:property "Row gap" :property "Row gap"
:values {:row-gap (:row-gap value)} :values {:row-gap (:row-gap value)}
:disabled row-gap-disabled? :disabled row-gap-disabled?}]
:placeholder (if (or (= :multiple (:row-gap applied-tokens))
(= :multiple (:row-gap value)))
(tr "settings.multiple")
"--")
:applied-token (:row-gap applied-tokens)
:value (:row-gap value)}]
[:div {:class (stl/css-case [:div {:class (stl/css-case
:row-gap true :row-gap true
@@ -793,15 +791,11 @@
:icon i/gap-horizontal :icon i/gap-horizontal
:nillable true :nillable true
:min 0 :min 0
:attr :column-gap :name :column-gap
:align :right :align :right
:applied-tokens applied-tokens
:property "Column gap" :property "Column gap"
:placeholder (if (or (= :multiple (:column-gap applied-tokens)) :values {:column-gap (:column-gap value)}
(= :multiple (:column-gap value)))
(tr "settings.multiple")
"--")
:applied-token (:column-gap applied-tokens)
:value (:column-gap value)
:disabled col-gap-disabled?}] :disabled col-gap-disabled?}]
[:div {:class (stl/css-case [:div {:class (stl/css-case

View File

@@ -10,6 +10,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.schema :as sm] [app.common.schema :as sm]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.common.types.token :as tk]
[app.main.data.workspace :as udw] [app.main.data.workspace :as udw]
[app.main.data.workspace.shape-layout :as dwsl] [app.main.data.workspace.shape-layout :as dwsl]
[app.main.data.workspace.tokens.application :as dwta] [app.main.data.workspace.tokens.application :as dwta]
@@ -18,16 +19,62 @@
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.numeric-input :as deprecated-input] [app.main.ui.components.numeric-input :as deprecated-input]
[app.main.ui.components.title-bar :refer [title-bar*]] [app.main.ui.components.title-bar :refer [title-bar*]]
[app.main.ui.context :as muc]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
[app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]]
[app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.icons :as deprecated-icon] [app.main.ui.icons :as deprecated-icon]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.main.ui.workspace.sidebar.options.menus.layout-container :refer [get-layout-flex-icon]] [app.main.ui.workspace.sidebar.options.menus.layout-container :refer [get-layout-flex-icon]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc numeric-input-wrapper*
{::mf/private true}
[{:keys [values name applied-tokens align on-detach placeholder] :rest props}]
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
input-type (cond
(some #{:m2 :m4} [name])
:horizontal-margin
(some #{:m1 :m3} [name])
:vertical-margin
(= name :layout-item-max-w)
:max-width
(= name :layout-item-max-h)
:max-height
(= name :layout-item-min-w)
:min-width
(= name :layout-item-min-h)
:min-height
:else
name)
tokens (mf/with-memo [tokens input-type]
(delay
(-> (deref tokens)
(select-keys (get tk/tokens-by-input input-type))
(not-empty))))
on-detach-attr
(mf/use-fn
(mf/deps on-detach name)
#(on-detach % name))
props (mf/spread-props props
{:placeholder (or placeholder "--")
:applied-token (get applied-tokens name)
:tokens tokens
:align align
:on-detach on-detach-attr
:value (get values name)})]
[:> numeric-input* props]))
(def layout-item-attrs (def layout-item-attrs
[:layout-item-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0} [:layout-item-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0}
:layout-item-margin-type ;; :simple :multiple :layout-item-margin-type ;; :simple :multiple
@@ -151,12 +198,11 @@
:placeholder m1-placeholder :placeholder m1-placeholder
:icon i/margin-top-bottom :icon i/margin-top-bottom
:min 0 :min 0
:attr :m1 :name :m1
:input-type :vertical-margin
:property "Vertical margin " :property "Vertical margin "
:nillable true :nillable true
:applied-token token-applied-m1 :applied-tokens {:m1 token-applied-m1}
:value m1}] :values {:m1 m1}}]
[:div {:class (stl/css :vertical-margin) [:div {:class (stl/css :vertical-margin)
:title "Vertical margin"} :title "Vertical margin"}
@@ -181,13 +227,12 @@
:icon i/margin-left-right :icon i/margin-left-right
:class (stl/css :horizontal-margin-wrapper) :class (stl/css :horizontal-margin-wrapper)
:min 0 :min 0
:attr :m2 :name :m2
:align :right :align :right
:input-type :horizontal-margin
:property "Horizontal margin" :property "Horizontal margin"
:nillable true :nillable true
:applied-token token-applied-m2 :applied-tokens {:m2 token-applied-m2}
:value m2}] :values {:m2 m2}}]
[:div {:class (stl/css :horizontal-margin) [:div {:class (stl/css :horizontal-margin)
:title "Horizontal margin"} :title "Horizontal margin"}
@@ -279,12 +324,11 @@
:icon i/margin-top :icon i/margin-top
:class (stl/css :top-margin-wrapper) :class (stl/css :top-margin-wrapper)
:min 0 :min 0
:attr :m1 :name :m1
:input-type :vertical-margin
:property "Top margin" :property "Top margin"
:nillable true :nillable true
:applied-token applied-token-to-m1 :applied-tokens {:m1 applied-token-to-m1}
:value m1}] :values {:m1 m1}}]
[:div {:class (stl/css :top-margin) [:div {:class (stl/css :top-margin)
:title "Top margin"} :title "Top margin"}
@@ -307,13 +351,12 @@
:icon i/margin-right :icon i/margin-right
:class (stl/css :right-margin-wrapper) :class (stl/css :right-margin-wrapper)
:min 0 :min 0
:attr :m2 :name :m2
:align :right :align :right
:input-type :horizontal-margin
:property "Right margin" :property "Right margin"
:nillable true :nillable true
:applied-token applied-token-to-m2 :applied-tokens {:m2 applied-token-to-m2}
:value m2}] :values {:m2 m2}}]
[:div {:class (stl/css :right-margin) [:div {:class (stl/css :right-margin)
:title "Right margin"} :title "Right margin"}
@@ -337,13 +380,12 @@
:icon i/margin-bottom :icon i/margin-bottom
:class (stl/css :bottom-margin-wrapper) :class (stl/css :bottom-margin-wrapper)
:min 0 :min 0
:attr :m3 :name :m3
:align :right :align :right
:input-type :vertical-margin
:property "Bottom margin" :property "Bottom margin"
:nillable true :nillable true
:applied-token applied-token-to-m3 :applied-tokens {:m3 applied-token-to-m3}
:value m3}] :values {:m3 m3}}]
[:div {:class (stl/css :bottom-margin) [:div {:class (stl/css :bottom-margin)
:title "Bottom margin"} :title "Bottom margin"}
@@ -367,12 +409,11 @@
:icon i/margin-left :icon i/margin-left
:class (stl/css :left-margin-wrapper) :class (stl/css :left-margin-wrapper)
:min 0 :min 0
:attr :m4 :name :m4
:property "Left margin" :property "Left margin"
:input-type :horizontal-margin
:nillable true :nillable true
:applied-token applied-token-to-m4 :applied-tokens {:m4 applied-token-to-m4}
:value m4}] :values {:m4 m4}}]
[:div {:class (stl/css :left-margin) [:div {:class (stl/css :left-margin)
:title "Left margin"} :title "Left margin"}
@@ -588,14 +629,13 @@
:on-detach on-detach-token :on-detach on-detach-token
:class (stl/css :min-w-wrapper) :class (stl/css :min-w-wrapper)
:min 0 :min 0
:attr :layout-item-min-w :name :layout-item-min-w
:property (tr "workspace.options.layout-item.layout-item-min-w") :property (tr "workspace.options.layout-item.layout-item-min-w")
:text-icon "MIN W" :text-icon "MIN W"
:input-type :min-width
:nillable true :nillable true
:applied-token applied-token-to-min-w :applied-tokens {:layout-item-min-w applied-token-to-min-w}
:tooltip-class (stl/css :tooltip-wrapper) :tooltip-class (stl/css :tooltip-wrapper)
:value min-w}] :values {:layout-item-min-w min-w}}]
[:div {:class (stl/css :layout-item-min-w) [:div {:class (stl/css :layout-item-min-w)
:title (tr "workspace.options.layout-item.layout-item-min-w")} :title (tr "workspace.options.layout-item.layout-item-min-w")}
@@ -620,14 +660,13 @@
:text-icon "MAX W" :text-icon "MAX W"
:class (stl/css :max-w-wrapper) :class (stl/css :max-w-wrapper)
:min 0 :min 0
:name :layout-item-max-w
:align :right :align :right
:input-type :max-width
:attr :layout-item-max-w
:property (tr "workspace.options.layout-item.layout-item-max-w") :property (tr "workspace.options.layout-item.layout-item-max-w")
:nillable true :nillable true
:tooltip-class (stl/css :tooltip-wrapper) :tooltip-class (stl/css :tooltip-wrapper)
:applied-token applied-token-to-max-w :applied-tokens {:layout-item-max-w applied-token-to-max-w}
:value max-w}] :values {:layout-item-max-w max-w}}]
[:div {:class (stl/css :layout-item-max-w) [:div {:class (stl/css :layout-item-max-w)
:title (tr "workspace.options.layout-item.layout-item-max-w")} :title (tr "workspace.options.layout-item.layout-item-max-w")}
@@ -651,16 +690,14 @@
{:on-change on-layout-item-min-h-change {:on-change on-layout-item-min-h-change
:on-detach on-detach-token :on-detach on-detach-token
:text-icon "MIN H" :text-icon "MIN H"
:input-type :max-height
:class (stl/css :min-h-wrapper) :class (stl/css :min-h-wrapper)
:min 0 :min 0
:attr :layout-item-min-h :name :layout-item-min-h
:property (tr "workspace.options.layout-item.layout-item-min-h") :property (tr "workspace.options.layout-item.layout-item-min-h")
:nillable true :nillable true
:tooltip-class (stl/css :tooltip-wrapper) :tooltip-class (stl/css :tooltip-wrapper)
:applied-tokens {:layout-item-min-h applied-token-to-min-h}
:applied-token applied-token-to-min-h :values {:layout-item-min-h min-h}}]
:value min-h}]
[:div {:class (stl/css :layout-item-min-h) [:div {:class (stl/css :layout-item-min-h)
:title (tr "workspace.options.layout-item.layout-item-min-h")} :title (tr "workspace.options.layout-item.layout-item-min-h")}
@@ -684,14 +721,13 @@
:class (stl/css :max-h-wrapper) :class (stl/css :max-h-wrapper)
:min 0 :min 0
:text-icon "MAX H" :text-icon "MAX H"
:name :layout-item-max-h
:align :right :align :right
:input-type :max-height
:attr :layout-item-max-h
:property (tr "workspace.options.layout-item.layout-item-max-h") :property (tr "workspace.options.layout-item.layout-item-max-h")
:nillable true :nillable true
:tooltip-class (stl/css :tooltip-wrapper) :tooltip-class (stl/css :tooltip-wrapper)
:applied-token applied-token-to-max-h :applied-tokens {:layout-item-max-h applied-token-to-max-h}
:value max-h}] :values {:layout-item-max-h max-h}}]
[:div {:class (stl/css :layout-item-max-h) [:div {:class (stl/css :layout-item-max-h)
:title (tr "workspace.options.layout-item.layout-item-max-h")} :title (tr "workspace.options.layout-item.layout-item-max-h")}

View File

@@ -13,6 +13,7 @@
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.logic.shapes :as cls] [app.common.logic.shapes :as cls]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.common.types.token :as tk]
[app.main.constants :refer [size-presets]] [app.main.constants :refer [size-presets]]
[app.main.data.workspace :as udw] [app.main.data.workspace :as udw]
[app.main.data.workspace.interactions :as dwi] [app.main.data.workspace.interactions :as dwi]
@@ -25,12 +26,13 @@
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.components.numeric-input :as deprecated-input] [app.main.ui.components.numeric-input :as deprecated-input]
[app.main.ui.context :as muc]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
[app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]] [app.main.ui.ds.controls.radio-buttons :refer [radio-buttons*]]
[app.main.ui.ds.foundations.assets.icon :as i] [app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.icons :as deprecated-icon] [app.main.ui.icons :as deprecated-icon]
[app.main.ui.workspace.sidebar.options.menus.border-radius :refer [border-radius-menu*]] [app.main.ui.workspace.sidebar.options.menus.border-radius :refer [border-radius-menu*]]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[clojure.set :as set] [clojure.set :as set]
@@ -89,6 +91,32 @@
shape)] shape)]
(select-keys shape measure-attrs))) (select-keys shape measure-attrs)))
(mf/defc numeric-input-wrapper*
{::mf/private true}
[{:keys [values name applied-tokens align on-detach] :rest props}]
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
tokens (mf/with-memo [tokens name]
(delay
(-> (deref tokens)
(select-keys (get tk/tokens-by-input name))
(not-empty))))
on-detach-attr
(mf/use-fn
(mf/deps on-detach name)
#(on-detach % name))
props (mf/spread-props props
{:placeholder (if (or (= :multiple (:applied-tokens values))
(= :multiple (get values name)))
(tr "settings.multiple") "--")
:class (stl/css :numeric-input-measures)
:applied-token (get applied-tokens name)
:tokens (if (delay? tokens) @tokens tokens)
:align align
:on-detach on-detach-attr
:value (get values name)})]
[:> numeric-input* props]))
(def ^:private xf:map-type (map :type)) (def ^:private xf:map-type (map :type))
(def ^:private xf:mapcat-type-to-options (mapcat type->options)) (def ^:private xf:mapcat-type-to-options (mapcat type->options))
@@ -416,13 +444,10 @@
:on-detach on-detach-token :on-detach on-detach-token
:icon i/character-w :icon i/character-w
:min 0.01 :min 0.01
:attr :width :name :width
:property (tr "workspace.options.width") :property (tr "workspace.options.width")
:applied-token (get applied-tokens :width) :applied-tokens applied-tokens
:placeholder (if (or (= :multiple (get applied-tokens :width)) :values values}]
(= :multiple (get values :width)))
(tr "settings.multiple") "--")
:value (get values :width)}]
[:> numeric-input-wrapper* [:> numeric-input-wrapper*
{:disabled disabled-height-sizing? {:disabled disabled-height-sizing?
@@ -430,11 +455,11 @@
:on-detach on-detach-token :on-detach on-detach-token
:min 0.01 :min 0.01
:icon i/character-h :icon i/character-h
:attr :height :name :height
:align :right :align :right
:property (tr "workspace.options.height") :property (tr "workspace.options.height")
:applied-token (get applied-tokens :height) :applied-tokens applied-tokens
:value (get values :height)}]] :values values}]]
[:* [:*
[:div {:class (stl/css-case :width true [:div {:class (stl/css-case :width true
@@ -478,26 +503,20 @@
:on-change on-pos-x-change :on-change on-pos-x-change
:on-detach on-detach-token :on-detach on-detach-token
:icon i/character-x :icon i/character-x
:attr :x :name :x
:property (tr "workspace.options.x") :property (tr "workspace.options.x")
:applied-token (get applied-tokens :x) :applied-tokens applied-tokens
:placeholder (if (or (= :multiple (get applied-tokens :x)) :values values}]
(= :multiple (get values :x)))
(tr "settings.multiple") "--")
:value (get values :x)}]
[:> numeric-input-wrapper* [:> numeric-input-wrapper*
{:disabled disabled-position? {:disabled disabled-position?
:on-change on-pos-y-change :on-change on-pos-y-change
:on-detach on-detach-token :on-detach on-detach-token
:icon i/character-y :icon i/character-y
:attr :y :name :y
:align :right :align :right
:property (tr "workspace.options.y") :property (tr "workspace.options.y")
:applied-token (get applied-tokens :y) :applied-tokens applied-tokens
:placeholder (if (or (= :multiple (get applied-tokens :y)) :values values}]]
(= :multiple (get values :y)))
(tr "settings.multiple") "--")
:value (get values :y)}]]
[:* [:*
[:div {:class (stl/css-case :x-position true [:div {:class (stl/css-case :x-position true
@@ -532,13 +551,10 @@
:icon i/rotation :icon i/rotation
:min -359 :min -359
:max 359 :max 359
:attr :rotation :name :rotation
:property (tr "workspace.options.rotation") :property (tr "workspace.options.rotation")
:applied-token (get applied-tokens :rotation) :applied-tokens applied-tokens
:placeholder (if (or (= :multiple (get applied-tokens :rotation)) :values values}]
(= :multiple (get values :rotation)))
(tr "settings.multiple") "--")
:value (get values :rotation)}]
[:div {:class (stl/css :rotation) [:div {:class (stl/css :rotation)
:title (tr "workspace.options.rotation")} :title (tr "workspace.options.rotation")}

View File

@@ -9,20 +9,50 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.types.color :as ctc] [app.common.types.color :as ctc]
[app.common.types.token :as tk]
[app.main.data.workspace.tokens.application :as dwta] [app.main.data.workspace.tokens.application :as dwta]
[app.main.features :as features] [app.main.features :as features]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.numeric-input :as deprecated-input] [app.main.ui.components.numeric-input :as deprecated-input]
[app.main.ui.components.reorder-handler :refer [reorder-handler*]] [app.main.ui.components.reorder-handler :refer [reorder-handler*]]
[app.main.ui.components.select :refer [select]] [app.main.ui.components.select :refer [select]]
[app.main.ui.context :as muc]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.controls.numeric-input :refer [numeric-input*]]
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i] [app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
[app.main.ui.hooks :as h] [app.main.ui.hooks :as h]
[app.main.ui.workspace.sidebar.options.menus.input-wrapper-tokens :refer [numeric-input-wrapper*]]
[app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row*]]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc numeric-input-wrapper*
{::mf/private true}
[{:keys [values name applied-tokens align on-detach] :rest props}]
(let [tokens (mf/use-ctx muc/active-tokens-by-type)
tokens (mf/with-memo [tokens name]
(delay
(-> (deref tokens)
(select-keys (get tk/tokens-by-input name))
(not-empty))))
on-detach-attr (mf/use-fn
(mf/deps on-detach name)
#(on-detach % name))
applied-token (get applied-tokens name)
props (mf/spread-props props
{:placeholder (if (= :multiple values)
(tr "settings.multiple")
"--")
:applied-token applied-token
:tokens (if (delay? tokens) @tokens tokens)
:align align
:on-detach on-detach-attr
:name name
:value values})]
[:> numeric-input* props]))
(mf/defc stroke-row* (mf/defc stroke-row*
[{:keys [index [{:keys [index
stroke stroke
@@ -220,11 +250,11 @@
:min 0 :min 0
:on-focus on-focus :on-focus on-focus
:on-blur on-blur :on-blur on-blur
:attr :stroke-width :name :stroke-width
:class (stl/css :numeric-input-wrapper) :class (stl/css :numeric-input-wrapper)
:property (tr "workspace.options.stroke-width") :property (tr "workspace.options.stroke-width")
:applied-token (get applied-tokens :stroke-width) :applied-tokens applied-tokens
:value stroke-width}] :values stroke-width}]
[:div {:class (stl/css :stroke-width-input) [:div {:class (stl/css :stroke-width-input)
:title (tr "workspace.options.stroke-width")} :title (tr "workspace.options.stroke-width")}