mirror of
https://github.com/penpot/penpot.git
synced 2025-03-12 07:41:43 -05:00
♻️ Review create and edit modal
This commit is contained in:
parent
31b5f5cefa
commit
03ea5414be
12 changed files with 310 additions and 147 deletions
|
@ -279,7 +279,6 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it state _]
|
||||||
(let [data (get state :workspace-data)
|
(let [data (get state :workspace-data)
|
||||||
_ (prn "paso por aquí")
|
|
||||||
changes (-> (pcb/empty-changes it)
|
changes (-> (pcb/empty-changes it)
|
||||||
(pcb/with-library-data data)
|
(pcb/with-library-data data)
|
||||||
(pcb/delete-token set-name token-name))]
|
(pcb/delete-token set-name token-name))]
|
||||||
|
|
|
@ -130,3 +130,21 @@
|
||||||
box-shadow: inset 0 0 #{px2rem(10)} #{px2rem(2)} rgba(0, 0, 0, 0.2);
|
box-shadow: inset 0 0 #{px2rem(10)} #{px2rem(2)} rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%base-button-action {
|
||||||
|
--button-bg-color: transparent;
|
||||||
|
--button-fg-color: var(--color-foreground-secondary);
|
||||||
|
|
||||||
|
--button-hover-bg-color: transparent;
|
||||||
|
--button-hover-fg-color: var(--color-accent-primary);
|
||||||
|
|
||||||
|
--button-active-bg-color: var(--color-background-quaternary);
|
||||||
|
|
||||||
|
--button-disabled-bg-color: transparent;
|
||||||
|
--button-disabled-fg-color: var(--color-accent-primary-muted);
|
||||||
|
|
||||||
|
--button-focus-bg-color: transparent;
|
||||||
|
--button-focus-fg-color: var(--color-accent-primary);
|
||||||
|
--button-focus-inner-ring-color: transparent;
|
||||||
|
--button-focus-outer-ring-color: var(--color-accent-primary);
|
||||||
|
}
|
||||||
|
|
|
@ -12,9 +12,6 @@
|
||||||
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
|
[app.main.ui.ds.foundations.assets.icon :refer [icon* icon-list]]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
(def button-variants (set '("primary" "secondary" "ghost" "destructive")))
|
|
||||||
|
|
||||||
|
|
||||||
(def ^:private schema:icon-button
|
(def ^:private schema:icon-button
|
||||||
[:map
|
[:map
|
||||||
[:class {:optional true} :string]
|
[:class {:optional true} :string]
|
||||||
|
@ -22,7 +19,7 @@
|
||||||
[:and :string [:fn #(contains? icon-list %)]]]
|
[:and :string [:fn #(contains? icon-list %)]]]
|
||||||
[:aria-label :string]
|
[:aria-label :string]
|
||||||
[:variant {:optional true}
|
[:variant {:optional true}
|
||||||
[:maybe [:enum "primary" "secondary" "ghost" "destructive"]]]])
|
[:maybe [:enum "primary" "secondary" "ghost" "destructive" "action"]]]])
|
||||||
|
|
||||||
(mf/defc icon-button*
|
(mf/defc icon-button*
|
||||||
{::mf/props :obj
|
{::mf/props :obj
|
||||||
|
@ -33,6 +30,7 @@
|
||||||
:icon-button-primary (= variant "primary")
|
:icon-button-primary (= variant "primary")
|
||||||
:icon-button-secondary (= variant "secondary")
|
:icon-button-secondary (= variant "secondary")
|
||||||
:icon-button-ghost (= variant "ghost")
|
:icon-button-ghost (= variant "ghost")
|
||||||
|
:icon-button-action (= variant "action")
|
||||||
:icon-button-destructive (= variant "destructive")))
|
:icon-button-destructive (= variant "destructive")))
|
||||||
props (mf/spread-props props {:class class :title aria-label})]
|
props (mf/spread-props props {:class class :title aria-label})]
|
||||||
[:> "button" props [:> icon* {:id icon :aria-label aria-label}]]))
|
[:> "button" props [:> icon* {:id icon :aria-label aria-label}]]))
|
|
@ -31,3 +31,7 @@
|
||||||
.icon-button-destructive {
|
.icon-button-destructive {
|
||||||
@extend %base-button-destructive;
|
@extend %base-button-destructive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-button-action {
|
||||||
|
@extend %base-button-action;
|
||||||
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default {
|
||||||
},
|
},
|
||||||
disabled: { control: "boolean" },
|
disabled: { control: "boolean" },
|
||||||
variant: {
|
variant: {
|
||||||
options: ["primary", "secondary", "ghost", "destructive"],
|
options: ["primary", "secondary", "ghost", "destructive", "action"],
|
||||||
control: { type: "select" },
|
control: { type: "select" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -59,6 +59,12 @@ export const Ghost = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Action = {
|
||||||
|
args: {
|
||||||
|
variant: "action",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Destructive = {
|
export const Destructive = {
|
||||||
args: {
|
args: {
|
||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
|
|
|
@ -10,12 +10,16 @@
|
||||||
["lodash.debounce" :as debounce]
|
["lodash.debounce" :as debounce]
|
||||||
[app.common.colors :as c]
|
[app.common.colors :as c]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.types.tokens-lib :as ctob]
|
[app.common.types.tokens-lib :as ctob]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.tokens :as dt]
|
[app.main.data.tokens :as dt]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.color-bullet :refer [color-bullet]]
|
[app.main.ui.components.color-bullet :refer [color-bullet]]
|
||||||
|
[app.main.ui.ds.buttons.button :refer [button*]]
|
||||||
|
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||||
|
[app.main.ui.ds.foundations.typography.text :refer [text*]]
|
||||||
[app.main.ui.workspace.colorpicker :as colorpicker]
|
[app.main.ui.workspace.colorpicker :as colorpicker]
|
||||||
[app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector]]
|
[app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector]]
|
||||||
[app.main.ui.workspace.tokens.common :as tokens.common]
|
[app.main.ui.workspace.tokens.common :as tokens.common]
|
||||||
|
@ -25,6 +29,7 @@
|
||||||
[app.main.ui.workspace.tokens.token :as wtt]
|
[app.main.ui.workspace.tokens.token :as wtt]
|
||||||
[app.main.ui.workspace.tokens.update :as wtu]
|
[app.main.ui.workspace.tokens.update :as wtu]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
[app.util.i18n :refer [tr]]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[malli.core :as m]
|
[malli.core :as m]
|
||||||
[malli.error :as me]
|
[malli.error :as me]
|
||||||
|
@ -124,7 +129,7 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
[name-ref token tokens callback & {:keys [timeout] :or {timeout 160}}]
|
[name-ref token tokens callback & {:keys [timeout] :or {timeout 160}}]
|
||||||
(let [timeout-id-ref (mf/use-ref nil)
|
(let [timeout-id-ref (mf/use-ref nil)
|
||||||
debounced-resolver-callback
|
debounced-resolver-callback
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps token callback tokens)
|
(mf/deps token callback tokens)
|
||||||
(fn [value]
|
(fn [value]
|
||||||
(let [timeout-id (js/Symbol)
|
(let [timeout-id (js/Symbol)
|
||||||
|
@ -178,19 +183,22 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
[{:keys [result-or-errors]}]
|
[{:keys [result-or-errors]}]
|
||||||
(let [{:keys [errors]} result-or-errors
|
(let [{:keys [errors]} result-or-errors
|
||||||
empty-message? (or (nil? result-or-errors)
|
empty-message? (or (nil? result-or-errors)
|
||||||
(wte/has-error-code? :error/empty-input errors))]
|
(wte/has-error-code? :error/empty-input errors))
|
||||||
[:div {:class (stl/css-case :resolved-value true
|
message (cond
|
||||||
:resolved-value-placeholder empty-message?
|
empty-message? (dm/str (tr "workspace.token.resolved-value") "-")
|
||||||
:resolved-value-error (seq errors))}
|
|
||||||
(cond
|
|
||||||
empty-message? "Enter token value"
|
|
||||||
errors (->> (wte/humanize-errors errors)
|
errors (->> (wte/humanize-errors errors)
|
||||||
(str/join "\n"))
|
(str/join "\n"))
|
||||||
:else [:p result-or-errors])]))
|
:else (dm/str (tr "workspace.token.resolved-value") result-or-errors))]
|
||||||
|
[:> text* {:as "p"
|
||||||
|
:typography "body-small"
|
||||||
|
:class (stl/css-case :resolved-value true
|
||||||
|
:resolved-value-placeholder empty-message?
|
||||||
|
:resolved-value-error (seq errors))}
|
||||||
|
message]))
|
||||||
|
|
||||||
(mf/defc form
|
(mf/defc form
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [token token-type]}]
|
[{:keys [token token-type action selected-token-set-id]}]
|
||||||
(let [validate-name? (mf/use-state (not (:id token)))
|
(let [validate-name? (mf/use-state (not (:id token)))
|
||||||
token (or token {:type token-type})
|
token (or token {:type token-type})
|
||||||
color? (wtt/color-token? token)
|
color? (wtt/color-token? token)
|
||||||
|
@ -212,13 +220,16 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
;; Name
|
;; Name
|
||||||
name-ref (mf/use-var (:name token))
|
name-ref (mf/use-var (:name token))
|
||||||
name-errors (mf/use-state nil)
|
name-errors (mf/use-state nil)
|
||||||
validate-name (mf/use-callback
|
validate-name
|
||||||
|
(mf/use-fn
|
||||||
(mf/deps selected-set-tokens-tree)
|
(mf/deps selected-set-tokens-tree)
|
||||||
(fn [value]
|
(fn [value]
|
||||||
(let [schema (token-name-schema {:token token
|
(let [schema (token-name-schema {:token token
|
||||||
:tokens-tree selected-set-tokens-tree})]
|
:tokens-tree selected-set-tokens-tree})]
|
||||||
(m/explain schema (finalize-name value)))))
|
(m/explain schema (finalize-name value)))))
|
||||||
on-update-name-debounced (mf/use-callback
|
|
||||||
|
on-update-name-debounced
|
||||||
|
(mf/use-fn
|
||||||
(debounce (fn [e]
|
(debounce (fn [e]
|
||||||
(let [value (dom/get-target-val e)
|
(let [value (dom/get-target-val e)
|
||||||
errors (validate-name value)]
|
errors (validate-name value)]
|
||||||
|
@ -226,11 +237,14 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
(when-not (and validate-name? (str/empty? value))
|
(when-not (and validate-name? (str/empty? value))
|
||||||
(reset! validate-name? false)
|
(reset! validate-name? false)
|
||||||
(reset! name-errors errors))))))
|
(reset! name-errors errors))))))
|
||||||
on-update-name (mf/use-callback
|
|
||||||
|
on-update-name
|
||||||
|
(mf/use-fn
|
||||||
(mf/deps on-update-name-debounced)
|
(mf/deps on-update-name-debounced)
|
||||||
(fn [e]
|
(fn [e]
|
||||||
(reset! name-ref (dom/get-target-val e))
|
(reset! name-ref (dom/get-target-val e))
|
||||||
(on-update-name-debounced e)))
|
(on-update-name-debounced e)))
|
||||||
|
|
||||||
valid-name-field? (and
|
valid-name-field? (and
|
||||||
(not @name-errors)
|
(not @name-errors)
|
||||||
(valid-name? @name-ref))
|
(valid-name? @name-ref))
|
||||||
|
@ -241,7 +255,8 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
value-input-ref (mf/use-ref nil)
|
value-input-ref (mf/use-ref nil)
|
||||||
value-ref (mf/use-var (:value token))
|
value-ref (mf/use-var (:value token))
|
||||||
token-resolve-result (mf/use-state (get-in resolved-tokens [(wtt/token-identifier token) :resolved-value]))
|
token-resolve-result (mf/use-state (get-in resolved-tokens [(wtt/token-identifier token) :resolved-value]))
|
||||||
set-resolve-value (mf/use-callback
|
set-resolve-value
|
||||||
|
(mf/use-fn
|
||||||
(fn [token-or-err]
|
(fn [token-or-err]
|
||||||
(let [error? (:errors token-or-err)
|
(let [error? (:errors token-or-err)
|
||||||
v (if error?
|
v (if error?
|
||||||
|
@ -250,18 +265,19 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
(when color? (reset! color (if error? nil v)))
|
(when color? (reset! color (if error? nil v)))
|
||||||
(reset! token-resolve-result v))))
|
(reset! token-resolve-result v))))
|
||||||
on-update-value-debounced (use-debonced-resolve-callback name-ref token active-theme-tokens set-resolve-value)
|
on-update-value-debounced (use-debonced-resolve-callback name-ref token active-theme-tokens set-resolve-value)
|
||||||
on-update-value (mf/use-callback
|
on-update-value (mf/use-fn
|
||||||
(mf/deps on-update-value-debounced)
|
(mf/deps on-update-value-debounced)
|
||||||
(fn [e]
|
(fn [e]
|
||||||
(let [value (dom/get-target-val e)]
|
(let [value (dom/get-target-val e)]
|
||||||
(reset! value-ref value)
|
(reset! value-ref value)
|
||||||
(on-update-value-debounced value))))
|
(on-update-value-debounced value))))
|
||||||
on-update-color (mf/use-callback
|
on-update-color (mf/use-fn
|
||||||
(mf/deps on-update-value-debounced)
|
(mf/deps on-update-value-debounced)
|
||||||
(fn [hex-value]
|
(fn [hex-value]
|
||||||
(reset! value-ref hex-value)
|
(reset! value-ref hex-value)
|
||||||
(set! (.-value (mf/ref-val value-input-ref)) hex-value)
|
(set! (.-value (mf/ref-val value-input-ref)) hex-value)
|
||||||
(on-update-value-debounced hex-value)))
|
(on-update-value-debounced hex-value)))
|
||||||
|
|
||||||
value-error? (seq (:errors @token-resolve-result))
|
value-error? (seq (:errors @token-resolve-result))
|
||||||
valid-value-field? (and
|
valid-value-field? (and
|
||||||
(not value-error?)
|
(not value-error?)
|
||||||
|
@ -270,13 +286,14 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
;; Description
|
;; Description
|
||||||
description-ref (mf/use-var (:description token))
|
description-ref (mf/use-var (:description token))
|
||||||
description-errors (mf/use-state nil)
|
description-errors (mf/use-state nil)
|
||||||
validate-descripion (mf/use-callback #(m/explain token-description-schema %))
|
validate-descripion (mf/use-fn #(m/explain token-description-schema %))
|
||||||
on-update-description-debounced (mf/use-callback
|
on-update-description-debounced (mf/use-fn
|
||||||
(debounce (fn [e]
|
(debounce (fn [e]
|
||||||
(let [value (dom/get-target-val e)
|
(let [value (dom/get-target-val e)
|
||||||
errors (validate-descripion value)]
|
errors (validate-descripion value)]
|
||||||
(reset! description-errors errors)))))
|
(reset! description-errors errors)))))
|
||||||
on-update-description (mf/use-callback
|
on-update-description
|
||||||
|
(mf/use-fn
|
||||||
(mf/deps on-update-description-debounced)
|
(mf/deps on-update-description-debounced)
|
||||||
(fn [e]
|
(fn [e]
|
||||||
(reset! description-ref (dom/get-target-val e))
|
(reset! description-ref (dom/get-target-val e))
|
||||||
|
@ -288,7 +305,8 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
(not valid-value-field?)
|
(not valid-value-field?)
|
||||||
(not valid-description-field?))
|
(not valid-description-field?))
|
||||||
|
|
||||||
on-submit (mf/use-callback
|
on-submit
|
||||||
|
(mf/use-fn
|
||||||
(mf/deps validate-name validate-descripion token resolved-tokens)
|
(mf/deps validate-name validate-descripion token resolved-tokens)
|
||||||
(fn [e]
|
(fn [e]
|
||||||
(dom/prevent-default e)
|
(dom/prevent-default e)
|
||||||
|
@ -317,12 +335,32 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
:description final-description)
|
:description final-description)
|
||||||
:prev-token-name (:name token)}))
|
:prev-token-name (:name token)}))
|
||||||
(st/emit! (wtu/update-workspace-tokens))
|
(st/emit! (wtu/update-workspace-tokens))
|
||||||
(modal/hide!))))))))]
|
(modal/hide!))))))))
|
||||||
[:form
|
on-delete-token
|
||||||
{:class (stl/css :form-wrapper)
|
(mf/use-fn
|
||||||
|
(mf/deps selected-token-set-id)
|
||||||
|
(fn [e]
|
||||||
|
(dom/prevent-default e)
|
||||||
|
(modal/hide!)
|
||||||
|
(st/emit! (dt/delete-token selected-token-set-id (:name token)))))
|
||||||
|
|
||||||
|
on-cancel
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [e]
|
||||||
|
(dom/prevent-default e)
|
||||||
|
(modal/hide!)))]
|
||||||
|
|
||||||
|
[:form {:class (stl/css :form-wrapper)
|
||||||
:on-submit on-submit}
|
:on-submit on-submit}
|
||||||
[:div {:class (stl/css :token-rows)}
|
[:div {:class (stl/css :token-rows)}
|
||||||
[:div
|
[:> text* {:as "span" :typography "headline-medium"}
|
||||||
|
(if (= action "edit")
|
||||||
|
(tr "workspace.token.edit-token")
|
||||||
|
(tr "workspace.token.create-token" token-type))]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :input-row)}
|
||||||
|
;; This should be remove when labeled-imput is modified
|
||||||
|
[:span "Name"]
|
||||||
[:& tokens.common/labeled-input {:label "Name"
|
[:& tokens.common/labeled-input {:label "Name"
|
||||||
:error? @name-errors
|
:error? @name-errors
|
||||||
:input-props {:default-value @name-ref
|
:input-props {:default-value @name-ref
|
||||||
|
@ -332,9 +370,15 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
(for [error (->> (:errors @name-errors)
|
(for [error (->> (:errors @name-errors)
|
||||||
(map #(-> (assoc @name-errors :errors [%])
|
(map #(-> (assoc @name-errors :errors [%])
|
||||||
(me/humanize))))]
|
(me/humanize))))]
|
||||||
[:p {:key error
|
[:> text* {:as "p"
|
||||||
|
:key error
|
||||||
|
:typography "body-small"
|
||||||
:class (stl/css :error)}
|
:class (stl/css :error)}
|
||||||
error])]
|
error])]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :input-row)}
|
||||||
|
;; This should be remove when labeled-imput is modified
|
||||||
|
[:span "value"]
|
||||||
[:& tokens.common/labeled-input {:label "Value"
|
[:& tokens.common/labeled-input {:label "Value"
|
||||||
:input-props {:default-value @value-ref
|
:input-props {:default-value @value-ref
|
||||||
:on-blur on-update-value
|
:on-blur on-update-value
|
||||||
|
@ -352,17 +396,33 @@ Token names should only contain letters and digits separated by . characters.")}
|
||||||
[:& ramp {:color (some-> (or @token-resolve-result (:value token))
|
[:& ramp {:color (some-> (or @token-resolve-result (:value token))
|
||||||
(tinycolor/valid-color))
|
(tinycolor/valid-color))
|
||||||
:on-change on-update-color}])
|
:on-change on-update-color}])
|
||||||
[:& token-value-or-errors {:result-or-errors @token-resolve-result}]
|
[:& token-value-or-errors {:result-or-errors @token-resolve-result}]]
|
||||||
|
|
||||||
[:div
|
|
||||||
|
[:div {:class (stl/css :input-row)}
|
||||||
|
;; This should be remove when labeled-imput is modified
|
||||||
|
[:span "Description"]
|
||||||
[:& tokens.common/labeled-input {:label "Description"
|
[:& tokens.common/labeled-input {:label "Description"
|
||||||
:input-props {:default-value @description-ref
|
:input-props {:default-value @description-ref
|
||||||
:on-change on-update-description}}]
|
:on-change on-update-description}}]
|
||||||
(when @description-errors
|
(when @description-errors
|
||||||
[:p {:class (stl/css :error)}
|
[:> text* {:as "p"
|
||||||
|
:typography "body-small"
|
||||||
|
:class (stl/css :error)}
|
||||||
(me/humanize @description-errors)])]
|
(me/humanize @description-errors)])]
|
||||||
[:div {:class (stl/css :button-row)}
|
|
||||||
[:button {:class (stl/css :button)
|
[:div {:class (stl/css-case :button-row true
|
||||||
:type "submit"
|
:with-delete (= action "edit"))}
|
||||||
|
(when (= action "edit")
|
||||||
|
[:> button* {:on-click on-delete-token
|
||||||
|
:class (stl/css :delete-btn)
|
||||||
|
:icon i/delete
|
||||||
|
:variant "secondary"}
|
||||||
|
(tr "labels.delete")])
|
||||||
|
[:> button* {:on-click on-cancel
|
||||||
|
:variant "secondary"}
|
||||||
|
(tr "labels.cancel")]
|
||||||
|
[:> button* {:type "submit"
|
||||||
|
:variant "primary"
|
||||||
:disabled disabled?}
|
:disabled disabled?}
|
||||||
"Save"]]]]))
|
(tr "labels.save")]]]]))
|
||||||
|
|
|
@ -8,49 +8,56 @@
|
||||||
@import "./common.scss";
|
@import "./common.scss";
|
||||||
|
|
||||||
.form-wrapper {
|
.form-wrapper {
|
||||||
width: $s-260;
|
width: $s-384;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-row {
|
.button-row {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: column;
|
grid-template-columns: auto auto;
|
||||||
margin-top: $s-16;
|
justify-content: end;
|
||||||
|
gap: $s-12;
|
||||||
|
padding-block-start: $s-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.with-delete {
|
||||||
|
grid-template-columns: 1fr auto auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
justify-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.token-rows {
|
.token-rows {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $s-8;
|
gap: $s-16;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: $s-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
@include bodySmallTypography;
|
padding: $s-4 $s-6;
|
||||||
margin-top: $s-6;
|
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
color: var(--status-color-error-500);
|
color: var(--status-color-error-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
.resolved-value {
|
.resolved-value {
|
||||||
@include bodySmallTypography;
|
--input-hint-color: var(--color-foreground-primary);
|
||||||
|
margin-bottom: 0;
|
||||||
padding: $s-4 $s-6;
|
padding: $s-4 $s-6;
|
||||||
font-weight: medium;
|
color: var(--input-hint-color);
|
||||||
min-height: 1lh;
|
|
||||||
|
|
||||||
color: var(--color-foreground-primary);
|
|
||||||
border: 1px solid color-mix(in hsl, var(--color-foreground-secondary) 30%, transparent);
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: $fs-12;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.resolved-value-placeholder {
|
.resolved-value-placeholder {
|
||||||
color: var(--color-foreground-secondary);
|
--input-hint-color: var(--color-foreground-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.resolved-value-error {
|
.resolved-value-error {
|
||||||
color: var(--status-color-error-500);
|
--input-hint-color: var(--status-color-error-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-bullet {
|
.color-bullet {
|
||||||
|
|
|
@ -8,9 +8,12 @@
|
||||||
(:require-macros [app.main.style :as stl])
|
(:require-macros [app.main.style :as stl])
|
||||||
(:require
|
(:require
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.ui.workspace.tokens.modals.themes :as wtmt]
|
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
|
[app.main.ui.ds.foundations.assets.icon :as i]
|
||||||
[app.main.ui.workspace.tokens.form :refer [form]]
|
[app.main.ui.workspace.tokens.form :refer [form]]
|
||||||
|
[app.main.ui.workspace.tokens.modals.themes :as wtmt]
|
||||||
|
[app.util.i18n :refer [tr]]
|
||||||
[okulary.core :as l]
|
[okulary.core :as l]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
@ -40,12 +43,21 @@
|
||||||
|
|
||||||
(mf/defc token-update-create-modal
|
(mf/defc token-update-create-modal
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[{:keys [x y position token token-type] :as _args}]
|
[{:keys [x y position token token-type action selected-token-set-id] :as _args}]
|
||||||
(let [wrapper-style (use-viewport-position-style x y position)]
|
(let [wrapper-style (use-viewport-position-style x y position)
|
||||||
[:div
|
close-modal (mf/use-fn
|
||||||
{:class (stl/css :shadow)
|
(fn []
|
||||||
|
(modal/hide!)))]
|
||||||
|
[:div {:class (stl/css :token-modal-wrapper)
|
||||||
:style wrapper-style}
|
:style wrapper-style}
|
||||||
|
[:> icon-button* {:on-click close-modal
|
||||||
|
:class (stl/css :close-btn)
|
||||||
|
:icon i/close
|
||||||
|
:variant "action"
|
||||||
|
:aria-label (tr "labels.close")}]
|
||||||
[:& form {:token token
|
[:& form {:token token
|
||||||
|
:action action
|
||||||
|
:selected-token-set-id selected-token-set-id
|
||||||
:token-type token-type}]]))
|
:token-type token-type}]]))
|
||||||
|
|
||||||
(mf/defc token-themes-modal
|
(mf/defc token-themes-modal
|
||||||
|
|
|
@ -6,14 +6,19 @@
|
||||||
|
|
||||||
@import "refactor/common-refactor.scss";
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
.shadow {
|
.token-modal-wrapper {
|
||||||
@extend .modal-container-base;
|
@extend .modal-container-base;
|
||||||
width: auto;
|
|
||||||
max-width: auto;
|
|
||||||
min-width: auto;
|
|
||||||
@include menuShadow;
|
@include menuShadow;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
width: auto;
|
||||||
|
min-width: auto;
|
||||||
z-index: 11;
|
z-index: 11;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: $s-6;
|
||||||
|
right: $s-6;
|
||||||
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.transit :as t]
|
[app.common.transit :as t]
|
||||||
[app.common.types.tokens-lib :as ctob]
|
[app.common.types.tokens-lib :as ctob]
|
||||||
[app.main.data.notifications :as ntf]
|
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
|
[app.main.data.notifications :as ntf]
|
||||||
[app.main.data.tokens :as dt]
|
[app.main.data.tokens :as dt]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
@ -33,6 +33,7 @@
|
||||||
[app.main.ui.workspace.tokens.token :as wtt]
|
[app.main.ui.workspace.tokens.token :as wtt]
|
||||||
[app.main.ui.workspace.tokens.token-types :as wtty]
|
[app.main.ui.workspace.tokens.token-types :as wtty]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
[app.util.i18n :refer [tr]]
|
||||||
[app.util.webapi :as wapi]
|
[app.util.webapi :as wapi]
|
||||||
[beicon.v2.core :as rx]
|
[beicon.v2.core :as rx]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
|
@ -60,8 +61,8 @@
|
||||||
:title (cond
|
:title (cond
|
||||||
errors? (sd/humanize-errors token)
|
errors? (sd/humanize-errors token)
|
||||||
:else (->> [(str "Token: " name)
|
:else (->> [(str "Token: " name)
|
||||||
(str "Original value: " value)
|
(str (tr "workspace.token.original-value") value)
|
||||||
(str "Resolved value: " resolved-value)]
|
(str (tr "workspace.token.resolved-value") resolved-value)]
|
||||||
(str/join "\n")))
|
(str/join "\n")))
|
||||||
:on-click on-click
|
:on-click on-click
|
||||||
:on-context-menu on-context-menu
|
:on-context-menu on-context-menu
|
||||||
|
@ -111,6 +112,7 @@
|
||||||
#(st/emit! (dt/set-token-type-section-open type (not open?))))
|
#(st/emit! (dt/set-token-type-section-open type (not open?))))
|
||||||
on-popover-open-click (mf/use-fn
|
on-popover-open-click (mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
|
(mf/deps type title)
|
||||||
(let [{:keys [key fields]} modal]
|
(let [{:keys [key fields]} modal]
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(st/emit! (dt/set-token-type-section-open type true))
|
(st/emit! (dt/set-token-type-section-open type true))
|
||||||
|
@ -118,6 +120,8 @@
|
||||||
:y (.-clientY ^js event)
|
:y (.-clientY ^js event)
|
||||||
:position :right
|
:position :right
|
||||||
:fields fields
|
:fields fields
|
||||||
|
:title title
|
||||||
|
:action "create"
|
||||||
:token-type type}))))
|
:token-type type}))))
|
||||||
|
|
||||||
on-token-pill-click (mf/use-fn
|
on-token-pill-click (mf/use-fn
|
||||||
|
@ -175,13 +179,13 @@
|
||||||
:on-click (fn [e]
|
:on-click (fn [e]
|
||||||
(dom/stop-propagation e)
|
(dom/stop-propagation e)
|
||||||
(modal/show! :tokens/themes {}))}
|
(modal/show! :tokens/themes {}))}
|
||||||
(if create? "Create" "Edit")])
|
(if create? (tr "labels.create") (tr "labels.edit"))])
|
||||||
|
|
||||||
(mf/defc themes-header
|
(mf/defc themes-header
|
||||||
[_props]
|
[_props]
|
||||||
(let [ordered-themes (mf/deref refs/workspace-token-themes-no-hidden)]
|
(let [ordered-themes (mf/deref refs/workspace-token-themes-no-hidden)]
|
||||||
[:div {:class (stl/css :themes-wrapper)}
|
[:div {:class (stl/css :themes-wrapper)}
|
||||||
[:span {:class (stl/css :themes-header)} "Themes"]
|
[:span {:class (stl/css :themes-header)} (tr "labels.themes")]
|
||||||
[:div {:class (stl/css :theme-select-wrapper)}
|
[:div {:class (stl/css :theme-select-wrapper)}
|
||||||
[:& theme-select]
|
[:& theme-select]
|
||||||
[:& edit-button {:create? (empty? ordered-themes)}]]]))
|
[:& edit-button {:create? (empty? ordered-themes)}]]]))
|
||||||
|
@ -207,7 +211,7 @@
|
||||||
[:& title-bar {:collapsable true
|
[:& title-bar {:collapsable true
|
||||||
:collapsed (not @open?)
|
:collapsed (not @open?)
|
||||||
:all-clickable true
|
:all-clickable true
|
||||||
:title "SETS"
|
:title (tr "labels.sets")
|
||||||
:on-collapsed #(swap! open? not)}
|
:on-collapsed #(swap! open? not)}
|
||||||
[:& add-set-button {:on-open on-open}]]]
|
[:& add-set-button {:on-open on-open}]]]
|
||||||
(when @open?
|
(when @open?
|
||||||
|
|
|
@ -1993,6 +1993,14 @@ msgstr "Team Leader"
|
||||||
msgid "labels.team-member"
|
msgid "labels.team-member"
|
||||||
msgstr "Team member"
|
msgstr "Team member"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/sidebar.cljs
|
||||||
|
msgid "labels.themes"
|
||||||
|
msgstr "Themes"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/sidebar.cljs
|
||||||
|
msgid "labels.sets"
|
||||||
|
msgstr "Sets"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs:992, src/app/main/ui/workspace/main_menu.cljs:118
|
#: src/app/main/ui/dashboard/sidebar.cljs:992, src/app/main/ui/workspace/main_menu.cljs:118
|
||||||
msgid "labels.tutorials"
|
msgid "labels.tutorials"
|
||||||
msgstr "Tutorials"
|
msgstr "Tutorials"
|
||||||
|
@ -6139,3 +6147,20 @@ msgstr "Update"
|
||||||
#, unused
|
#, unused
|
||||||
msgid "workspace.viewport.click-to-close-path"
|
msgid "workspace.viewport.click-to-close-path"
|
||||||
msgstr "Click to close the path"
|
msgstr "Click to close the path"
|
||||||
|
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/form.cljs
|
||||||
|
msgid "workspace.token.create-token"
|
||||||
|
msgstr "Create new %s token"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/form.cljs
|
||||||
|
msgid "workspace.token.edit-token"
|
||||||
|
msgstr "Edit token"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/form.cljs
|
||||||
|
msgid "workspace.token.resolved-value"
|
||||||
|
msgstr "Resolved value: "
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/sidebar.cljs
|
||||||
|
msgid "workspace.token.original-value"
|
||||||
|
msgstr "Original value: "
|
|
@ -1991,6 +1991,14 @@ msgstr "Líder de equipo"
|
||||||
msgid "labels.team-member"
|
msgid "labels.team-member"
|
||||||
msgstr "Miembro de equipo"
|
msgstr "Miembro de equipo"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/sidebar.cljs
|
||||||
|
msgid "labels.themes"
|
||||||
|
msgstr "Temas"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/sidebar.cljs
|
||||||
|
msgid "labels.sets"
|
||||||
|
msgstr "Sets"
|
||||||
|
|
||||||
#: src/app/main/ui/dashboard/sidebar.cljs:992, src/app/main/ui/workspace/main_menu.cljs:118
|
#: src/app/main/ui/dashboard/sidebar.cljs:992, src/app/main/ui/workspace/main_menu.cljs:118
|
||||||
msgid "labels.tutorials"
|
msgid "labels.tutorials"
|
||||||
msgstr "Tutoriales"
|
msgstr "Tutoriales"
|
||||||
|
@ -6126,3 +6134,20 @@ msgstr "Pulsar para cerrar la ruta"
|
||||||
|
|
||||||
msgid "errors.maximum-invitations-by-request-reached"
|
msgid "errors.maximum-invitations-by-request-reached"
|
||||||
msgstr "Se ha alcanzado el número máximo (%s) de correos electrónicos que se pueden invitar en una sola solicitud"
|
msgstr "Se ha alcanzado el número máximo (%s) de correos electrónicos que se pueden invitar en una sola solicitud"
|
||||||
|
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/form.cljs
|
||||||
|
msgid "workspace.token.create-token"
|
||||||
|
msgstr "Crear un token de %s"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/form.cljs
|
||||||
|
msgid "workspace.token.edit-token"
|
||||||
|
msgstr "Editar token"
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/form.cljs
|
||||||
|
msgid "workspace.token.resolved-value"
|
||||||
|
msgstr "Valor resuelto: "
|
||||||
|
|
||||||
|
#: src/app/main/ui/workspace/tokens/sidebar.cljs
|
||||||
|
msgid "workspace.token.original-value"
|
||||||
|
msgstr "Valor original: "
|
Loading…
Add table
Reference in a new issue