mirror of
https://github.com/penpot/penpot.git
synced 2025-06-08 07:11:38 +02:00
🎉 Add variations POC
This commit is contained in:
parent
91fa39705d
commit
3268225941
24 changed files with 751 additions and 124 deletions
|
@ -556,6 +556,11 @@
|
||||||
"fdata/shape-data-type"
|
"fdata/shape-data-type"
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
;; There is no migration needed, but we don't want to allow
|
||||||
|
;; copy paste nor import of variant files into no-variant teams
|
||||||
|
"variants/v1"
|
||||||
|
nil
|
||||||
|
|
||||||
(ex/raise :type :internal
|
(ex/raise :type :internal
|
||||||
:code :no-migration-defined
|
:code :no-migration-defined
|
||||||
:hint (str/ffmt "no migation for feature '%' on file importation" feature)
|
:hint (str/ffmt "no migation for feature '%' on file importation" feature)
|
||||||
|
|
|
@ -52,7 +52,8 @@
|
||||||
"plugins/runtime"
|
"plugins/runtime"
|
||||||
"design-tokens/v1"
|
"design-tokens/v1"
|
||||||
"text-editor/v2"
|
"text-editor/v2"
|
||||||
"render-wasm/v1"})
|
"render-wasm/v1"
|
||||||
|
"variants/v1"})
|
||||||
|
|
||||||
;; A set of features enabled by default
|
;; A set of features enabled by default
|
||||||
(def default-features
|
(def default-features
|
||||||
|
@ -111,6 +112,7 @@
|
||||||
:feature-design-tokens "design-tokens/v1"
|
:feature-design-tokens "design-tokens/v1"
|
||||||
:feature-text-editor-v2 "text-editor/v2"
|
:feature-text-editor-v2 "text-editor/v2"
|
||||||
:feature-render-wasm "render-wasm/v1"
|
:feature-render-wasm "render-wasm/v1"
|
||||||
|
:feature-variants "variants/v1"
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
(defn migrate-legacy-features
|
(defn migrate-legacy-features
|
||||||
|
|
|
@ -861,7 +861,6 @@
|
||||||
|
|
||||||
(defn move-token-set-group-before
|
(defn move-token-set-group-before
|
||||||
[changes {:keys [from-path to-path before-path before-group? prev-before-path prev-before-group?]}]
|
[changes {:keys [from-path to-path before-path before-group? prev-before-path prev-before-group?]}]
|
||||||
(prn prev-before-path prev-before-group?)
|
|
||||||
(-> changes
|
(-> changes
|
||||||
(update :redo-changes conj {:type :move-token-set-group-before
|
(update :redo-changes conj {:type :move-token-set-group-before
|
||||||
:from-path from-path
|
:from-path from-path
|
||||||
|
@ -971,31 +970,37 @@
|
||||||
(apply-changes-local)))))
|
(apply-changes-local)))))
|
||||||
|
|
||||||
(defn update-component
|
(defn update-component
|
||||||
[changes id update-fn]
|
([changes id update-fn]
|
||||||
(assert-library! changes)
|
(let [library-data (::library-data (meta changes))
|
||||||
(let [library-data (::library-data (meta changes))
|
prev-component (get-in library-data [:components id])]
|
||||||
prev-component (get-in library-data [:components id])
|
(update-component changes id prev-component update-fn)))
|
||||||
new-component (update-fn prev-component)]
|
([changes id prev-component update-fn]
|
||||||
(if prev-component
|
(assert-library! changes)
|
||||||
(-> changes
|
(let [new-component (update-fn prev-component)]
|
||||||
(update :redo-changes conj {:type :mod-component
|
(if prev-component
|
||||||
:id id
|
(-> changes
|
||||||
:name (:name new-component)
|
(update :redo-changes conj {:type :mod-component
|
||||||
:path (:path new-component)
|
:id id
|
||||||
:main-instance-id (:main-instance-id new-component)
|
:name (:name new-component)
|
||||||
:main-instance-page (:main-instance-page new-component)
|
:path (:path new-component)
|
||||||
:annotation (:annotation new-component)
|
:main-instance-id (:main-instance-id new-component)
|
||||||
:objects (:objects new-component) ;; this won't exist in components-v2 (except for deleted components)
|
:main-instance-page (:main-instance-page new-component)
|
||||||
:modified-at (:modified-at new-component)})
|
:annotation (:annotation new-component)
|
||||||
(update :undo-changes conj {:type :mod-component
|
:variant-id (:variant-id new-component)
|
||||||
:id id
|
:variant-properties (:variant-properties new-component)
|
||||||
:name (:name prev-component)
|
:objects (:objects new-component) ;; this won't exist in components-v2 (except for deleted components)
|
||||||
:path (:path prev-component)
|
:modified-at (:modified-at new-component)})
|
||||||
:main-instance-id (:main-instance-id prev-component)
|
(update :undo-changes conj {:type :mod-component
|
||||||
:main-instance-page (:main-instance-page prev-component)
|
:id id
|
||||||
:annotation (:annotation prev-component)
|
:name (:name prev-component)
|
||||||
:objects (:objects prev-component)}))
|
:path (:path prev-component)
|
||||||
changes)))
|
:main-instance-id (:main-instance-id prev-component)
|
||||||
|
:main-instance-page (:main-instance-page prev-component)
|
||||||
|
:annotation (:annotation prev-component)
|
||||||
|
:variant-id (:variant-id prev-component)
|
||||||
|
:variant-properties (:variant-properties prev-component)
|
||||||
|
:objects (:objects prev-component)}))
|
||||||
|
changes))))
|
||||||
|
|
||||||
(defn delete-component
|
(defn delete-component
|
||||||
[changes id page-id]
|
[changes id page-id]
|
||||||
|
|
|
@ -152,7 +152,7 @@
|
||||||
|
|
||||||
(defn generate-duplicate-component
|
(defn generate-duplicate-component
|
||||||
"Create a new component copied from the one with the given id."
|
"Create a new component copied from the one with the given id."
|
||||||
[changes library component-id components-v2]
|
[changes library component-id new-component-id components-v2]
|
||||||
(let [component (ctkl/get-component (:data library) component-id)
|
(let [component (ctkl/get-component (:data library) component-id)
|
||||||
new-name (:name component)
|
new-name (:name component)
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@
|
||||||
(ctf/get-component-page (:data library) component))
|
(ctf/get-component-page (:data library) component))
|
||||||
|
|
||||||
new-component-id (when components-v2
|
new-component-id (when components-v2
|
||||||
(uuid/next))
|
new-component-id)
|
||||||
|
|
||||||
[new-component-shape new-component-shapes ; <- null in components-v2
|
[new-component-shape new-component-shapes ; <- null in components-v2
|
||||||
new-main-instance-shape new-main-instance-shapes]
|
new-main-instance-shape new-main-instance-shapes]
|
||||||
|
@ -181,6 +181,7 @@
|
||||||
(:id main-instance-page)
|
(:id main-instance-page)
|
||||||
(:annotation component)))))
|
(:annotation component)))))
|
||||||
|
|
||||||
|
|
||||||
(defn generate-instantiate-component
|
(defn generate-instantiate-component
|
||||||
"Generate changes to create a new instance from a component."
|
"Generate changes to create a new instance from a component."
|
||||||
([changes objects file-id component-id position page libraries]
|
([changes objects file-id component-id position page libraries]
|
||||||
|
|
62
common/src/app/common/logic/variants.cljc
Normal file
62
common/src/app/common/logic/variants.cljc
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
;; 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 INC
|
||||||
|
(ns app.common.logic.variants
|
||||||
|
(:require
|
||||||
|
[app.common.files.changes-builder :as pcb]
|
||||||
|
[cuerdas.core :as str]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn properties-to-name
|
||||||
|
[properties]
|
||||||
|
(->> properties
|
||||||
|
(map :value)
|
||||||
|
(str/join ", ")))
|
||||||
|
|
||||||
|
(defn generate-update-property-name
|
||||||
|
[changes related-components pos new-name]
|
||||||
|
(reduce (fn [changes component]
|
||||||
|
(pcb/update-component
|
||||||
|
changes (:id component)
|
||||||
|
#(assoc-in % [:variant-properties pos :name] new-name)))
|
||||||
|
changes
|
||||||
|
related-components))
|
||||||
|
|
||||||
|
|
||||||
|
(defn generate-remove-property
|
||||||
|
[changes related-components pos]
|
||||||
|
(reduce (fn [changes component]
|
||||||
|
(let [props (:variant-properties component)
|
||||||
|
props (vec (concat (subvec props 0 pos) (subvec props (inc pos))))
|
||||||
|
main-id (:main-instance-id component)
|
||||||
|
name (properties-to-name props)]
|
||||||
|
(-> changes
|
||||||
|
(pcb/update-component (:id component) #(assoc % :variant-properties props))
|
||||||
|
(pcb/update-shapes [main-id] #(assoc % :variant-name name)))))
|
||||||
|
changes
|
||||||
|
related-components))
|
||||||
|
|
||||||
|
|
||||||
|
(defn generate-update-property-value
|
||||||
|
[changes component-id main-id pos value name]
|
||||||
|
(-> changes
|
||||||
|
(pcb/update-component component-id #(assoc-in % [:variant-properties pos :value] value))
|
||||||
|
(pcb/update-shapes [main-id] #(assoc % :variant-name name))))
|
||||||
|
|
||||||
|
(defn generate-add-new-property
|
||||||
|
[changes related-components property-name]
|
||||||
|
(let [[_ changes]
|
||||||
|
(reduce (fn [[num changes] component]
|
||||||
|
(let [props (-> (or (:variant-properties component) [])
|
||||||
|
(conj {:name property-name :value (str "Value" num)}))
|
||||||
|
main-id (:main-instance-id component)
|
||||||
|
variant-name (properties-to-name props)]
|
||||||
|
[(inc num)
|
||||||
|
(-> changes
|
||||||
|
(pcb/update-component (:id component) #(assoc % :variant-properties props))
|
||||||
|
(pcb/update-shapes [main-id] #(assoc % :variant-name variant-name)))]))
|
||||||
|
[1 changes]
|
||||||
|
related-components)]
|
||||||
|
changes))
|
|
@ -215,6 +215,19 @@
|
||||||
(and (= shape-id (:main-instance-id component))
|
(and (= shape-id (:main-instance-id component))
|
||||||
(= page-id (:main-instance-page component))))
|
(= page-id (:main-instance-page component))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn is-variant?
|
||||||
|
"Check if this shape or component is a variant component"
|
||||||
|
[item]
|
||||||
|
(some? (:variant-id item)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn is-variant-container?
|
||||||
|
"Check if this shape is a variant container"
|
||||||
|
[shape]
|
||||||
|
(:is-variant-container shape))
|
||||||
|
|
||||||
|
|
||||||
(defn set-touched-group
|
(defn set-touched-group
|
||||||
[touched group]
|
[touched group]
|
||||||
(when group
|
(when group
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
(wrap-object-fn)))))))
|
(wrap-object-fn)))))))
|
||||||
|
|
||||||
(defn mod-component
|
(defn mod-component
|
||||||
[file-data {:keys [id name path main-instance-id main-instance-page objects annotation modified-at]}]
|
[file-data {:keys [id name path main-instance-id main-instance-page objects annotation variant-id variant-properties modified-at]}]
|
||||||
(let [wrap-objects-fn cfeat/*wrap-with-objects-map-fn*]
|
(let [wrap-objects-fn cfeat/*wrap-with-objects-map-fn*]
|
||||||
(d/update-in-when file-data [:components id]
|
(d/update-in-when file-data [:components id]
|
||||||
(fn [component]
|
(fn [component]
|
||||||
|
@ -76,10 +76,22 @@
|
||||||
(assoc :annotation annotation)
|
(assoc :annotation annotation)
|
||||||
|
|
||||||
(nil? annotation)
|
(nil? annotation)
|
||||||
(dissoc :annotation))
|
(dissoc :annotation)
|
||||||
|
|
||||||
|
(some? variant-id)
|
||||||
|
(assoc :variant-id variant-id)
|
||||||
|
|
||||||
|
(nil? variant-id)
|
||||||
|
(dissoc :variant-id)
|
||||||
|
|
||||||
|
(some? variant-properties)
|
||||||
|
(assoc :variant-properties variant-properties)
|
||||||
|
|
||||||
|
(nil? variant-properties)
|
||||||
|
(dissoc :variant-properties))
|
||||||
diff (set/difference
|
diff (set/difference
|
||||||
(ctk/diff-components component new-comp)
|
(ctk/diff-components component new-comp)
|
||||||
#{:annotation :modified-at})] ;; The set of properties that doesn't mark a component as touched
|
#{:annotation :modified-at :variant-id :variant-properties})] ;; The set of properties that doesn't mark a component as touched
|
||||||
|
|
||||||
(if (empty? diff)
|
(if (empty? diff)
|
||||||
new-comp
|
new-comp
|
||||||
|
|
|
@ -406,7 +406,7 @@
|
||||||
(cond-> new-shape
|
(cond-> new-shape
|
||||||
:always
|
:always
|
||||||
(-> (gsh/move delta)
|
(-> (gsh/move delta)
|
||||||
(dissoc :touched))
|
(dissoc :touched :variant-id :variant-name))
|
||||||
|
|
||||||
(and main-instance? root?)
|
(and main-instance? root?)
|
||||||
(assoc :main-instance true)
|
(assoc :main-instance true)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
[app.common.types.components-list :as ctkl]
|
[app.common.types.components-list :as ctkl]
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[clojure.test :as t]))
|
[clojure.test :as t]))
|
||||||
|
|
||||||
(t/use-fixtures :each thi/test-fixture)
|
(t/use-fixtures :each thi/test-fixture)
|
||||||
|
@ -288,6 +289,7 @@
|
||||||
changes (cll/generate-duplicate-component (pcb/empty-changes)
|
changes (cll/generate-duplicate-component (pcb/empty-changes)
|
||||||
file
|
file
|
||||||
(:id component)
|
(:id component)
|
||||||
|
(uuid/next)
|
||||||
true)
|
true)
|
||||||
|
|
||||||
file' (thf/apply-changes file changes)
|
file' (thf/apply-changes file changes)
|
||||||
|
|
3
frontend/resources/images/icons/variant.svg
Normal file
3
frontend/resources/images/icons/variant.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="M8.75 1.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm-1.5 13.5a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0ZM8.75 8a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0ZM5.375 4.625a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm0 6.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm5.25 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm0-6.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0ZM1.25 8.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm13.5-1.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 558 B |
|
@ -520,17 +520,19 @@
|
||||||
|
|
||||||
(defn duplicate-component
|
(defn duplicate-component
|
||||||
"Create a new component copied from the one with the given id."
|
"Create a new component copied from the one with the given id."
|
||||||
[library-id component-id]
|
([library-id component-id]
|
||||||
(ptk/reify ::duplicate-component
|
(duplicate-component library-id component-id (uuid/next)))
|
||||||
ptk/WatchEvent
|
([library-id component-id new-component-id]
|
||||||
(watch [it state _]
|
(ptk/reify ::duplicate-component
|
||||||
(let [libraries (dsh/lookup-libraries state)
|
ptk/WatchEvent
|
||||||
library (get libraries library-id)
|
(watch [it state _]
|
||||||
components-v2 (features/active-feature? state "components/v2")
|
(let [libraries (dsh/lookup-libraries state)
|
||||||
changes (-> (pcb/empty-changes it nil)
|
library (get libraries library-id)
|
||||||
(cll/generate-duplicate-component library component-id components-v2))]
|
components-v2 (features/active-feature? state "components/v2")
|
||||||
|
changes (-> (pcb/empty-changes it nil)
|
||||||
|
(cll/generate-duplicate-component library component-id new-component-id components-v2))]
|
||||||
|
|
||||||
(rx/of (dch/commit-changes changes))))))
|
(rx/of (dch/commit-changes changes)))))))
|
||||||
|
|
||||||
(defn delete-component
|
(defn delete-component
|
||||||
"Delete the component with the given id, from the current file library."
|
"Delete the component with the given id, from the current file library."
|
||||||
|
@ -984,7 +986,7 @@
|
||||||
second)
|
second)
|
||||||
0)))))
|
0)))))
|
||||||
|
|
||||||
(defn- component-swap
|
(defn component-swap
|
||||||
"Swaps a component with another one"
|
"Swaps a component with another one"
|
||||||
[shape file-id id-new-component]
|
[shape file-id id-new-component]
|
||||||
(dm/assert! (uuid? id-new-component))
|
(dm/assert! (uuid? id-new-component))
|
||||||
|
|
197
frontend/src/app/main/data/workspace/variants.cljs
Normal file
197
frontend/src/app/main/data/workspace/variants.cljs
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
;; 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 INC
|
||||||
|
|
||||||
|
(ns app.main.data.workspace.variants
|
||||||
|
(:require
|
||||||
|
[app.common.colors :as clr]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.files.changes-builder :as pcb]
|
||||||
|
[app.common.logic.variants :as clv]
|
||||||
|
[app.common.types.components-list :as ctcl]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.main.data.changes :as dch]
|
||||||
|
[app.main.data.helpers :as dsh]
|
||||||
|
[app.main.data.workspace.colors :as cl]
|
||||||
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
|
[app.main.data.workspace.shape-layout :as dwsl]
|
||||||
|
[app.main.data.workspace.shapes :as dwsh]
|
||||||
|
[app.main.data.workspace.undo :as dwu]
|
||||||
|
[beicon.v2.core :as rx]
|
||||||
|
[potok.v2.core :as ptk]))
|
||||||
|
|
||||||
|
(defn find-related-components
|
||||||
|
[data objects variant-id]
|
||||||
|
(->> (dm/get-in objects [variant-id :shapes])
|
||||||
|
(map #(dm/get-in objects [% :component-id]))
|
||||||
|
(map #(ctcl/get-component data % true))))
|
||||||
|
|
||||||
|
(defn update-property-name
|
||||||
|
"Update the variant property name on the position pos
|
||||||
|
in all the components with this variant-id"
|
||||||
|
[variant-id pos new-name]
|
||||||
|
(ptk/reify ::update-property-name
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [it state _]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
data (dsh/lookup-file-data state)
|
||||||
|
objects (-> (dsh/get-page data page-id)
|
||||||
|
(get :objects))
|
||||||
|
related-components (find-related-components data objects variant-id)
|
||||||
|
changes (-> (pcb/empty-changes it page-id)
|
||||||
|
(pcb/with-library-data data)
|
||||||
|
(clv/generate-update-property-name related-components pos new-name))
|
||||||
|
undo-id (js/Symbol)]
|
||||||
|
(rx/of
|
||||||
|
(dwu/start-undo-transaction undo-id)
|
||||||
|
(dch/commit-changes changes)
|
||||||
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
(defn update-property-value
|
||||||
|
"Updates the variant property value on the position pos in a component"
|
||||||
|
[component-id pos value]
|
||||||
|
(ptk/reify ::update-property-value
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [it state _]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
data (dsh/lookup-file-data state)
|
||||||
|
objects (-> (dsh/get-page data page-id)
|
||||||
|
(get :objects))
|
||||||
|
component (ctcl/get-component data component-id true)
|
||||||
|
main-id (:main-instance-id component)
|
||||||
|
properties (-> (:variant-properties component)
|
||||||
|
(update pos assoc :value value))
|
||||||
|
|
||||||
|
name (clv/properties-to-name properties)
|
||||||
|
|
||||||
|
changes (-> (pcb/empty-changes it page-id)
|
||||||
|
(pcb/with-library-data data)
|
||||||
|
(pcb/with-objects objects)
|
||||||
|
(clv/generate-update-property-value component-id main-id pos value name))
|
||||||
|
undo-id (js/Symbol)]
|
||||||
|
(rx/of
|
||||||
|
(dwu/start-undo-transaction undo-id)
|
||||||
|
(dch/commit-changes changes)
|
||||||
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn remove-property
|
||||||
|
"Remove the variant property on the position pos
|
||||||
|
in all the components with this variant-id"
|
||||||
|
[variant-id pos]
|
||||||
|
(ptk/reify ::remove-property
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [it state _]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
data (dsh/lookup-file-data state)
|
||||||
|
objects (-> (dsh/get-page data page-id)
|
||||||
|
(get :objects))
|
||||||
|
related-components (find-related-components data objects variant-id)
|
||||||
|
|
||||||
|
changes (-> (pcb/empty-changes it page-id)
|
||||||
|
(pcb/with-library-data data)
|
||||||
|
(pcb/with-objects objects)
|
||||||
|
(clv/generate-remove-property related-components pos))
|
||||||
|
|
||||||
|
undo-id (js/Symbol)]
|
||||||
|
(rx/of
|
||||||
|
(dwu/start-undo-transaction undo-id)
|
||||||
|
(dch/commit-changes changes)
|
||||||
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn add-new-property
|
||||||
|
"Add a new variant property to all the components with this variant-id"
|
||||||
|
[variant-id]
|
||||||
|
(ptk/reify ::add-new-property
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [it state _]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
data (dsh/lookup-file-data state)
|
||||||
|
objects (-> (dsh/get-page data page-id)
|
||||||
|
(get :objects))
|
||||||
|
|
||||||
|
related-components (find-related-components data objects variant-id)
|
||||||
|
|
||||||
|
|
||||||
|
property-name (str "Property" (-> related-components
|
||||||
|
first
|
||||||
|
:variant-properties
|
||||||
|
count
|
||||||
|
inc))
|
||||||
|
|
||||||
|
changes (-> (pcb/empty-changes it page-id)
|
||||||
|
(pcb/with-library-data data)
|
||||||
|
(pcb/with-objects objects)
|
||||||
|
(clv/generate-add-new-property related-components property-name))
|
||||||
|
|
||||||
|
|
||||||
|
undo-id (js/Symbol)]
|
||||||
|
(rx/of
|
||||||
|
(dwu/start-undo-transaction undo-id)
|
||||||
|
(dch/commit-changes changes)
|
||||||
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
(defn set-variant-id
|
||||||
|
"Sets the variant-id on a component"
|
||||||
|
[component-id variant-id]
|
||||||
|
(ptk/reify ::set-variant-id
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [it state _]
|
||||||
|
(let [page-id (:current-page-id state)
|
||||||
|
data (dsh/lookup-file-data state)
|
||||||
|
changes (-> (pcb/empty-changes it page-id)
|
||||||
|
(pcb/with-library-data data)
|
||||||
|
(pcb/update-component component-id #(assoc % :variant-id variant-id)))
|
||||||
|
undo-id (js/Symbol)]
|
||||||
|
(rx/of
|
||||||
|
(dwu/start-undo-transaction undo-id)
|
||||||
|
(dch/commit-changes changes)
|
||||||
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
|
(defn transform-in-variant
|
||||||
|
"Given the id of a main shape of a component, creates a variant structure for
|
||||||
|
that component"
|
||||||
|
[id]
|
||||||
|
(ptk/reify ::transform-in-variant
|
||||||
|
ptk/WatchEvent
|
||||||
|
(watch [_ state _]
|
||||||
|
(let [variant-id (uuid/next)
|
||||||
|
variant-vec [variant-id]
|
||||||
|
new-component-id (uuid/next)
|
||||||
|
file-id (:current-file-id state)
|
||||||
|
page-id (:current-page-id state)
|
||||||
|
objects (dsh/lookup-page-objects state file-id page-id)
|
||||||
|
main (get objects id)
|
||||||
|
main-id (:id main)
|
||||||
|
undo-id (js/Symbol)]
|
||||||
|
|
||||||
|
(rx/of
|
||||||
|
(dwu/start-undo-transaction undo-id)
|
||||||
|
(dwsh/create-artboard-from-selection variant-id)
|
||||||
|
(cl/remove-all-fills variant-vec {:color clr/black :opacity 1})
|
||||||
|
(dwsl/create-layout-from-id variant-id :flex)
|
||||||
|
(dwsh/update-shapes variant-vec #(assoc % :layout-item-h-sizing :auto
|
||||||
|
:layout-item-v-sizing :auto
|
||||||
|
:layout-padding {:p1 30 :p2 30 :p3 30 :p4 30}
|
||||||
|
:layout-gap {:row-gap 0 :column-gap 20}
|
||||||
|
:name (:name main)
|
||||||
|
:r1 20
|
||||||
|
:r2 20
|
||||||
|
:r3 20
|
||||||
|
:r4 20
|
||||||
|
:is-variant-container true))
|
||||||
|
(dwsh/update-shapes [main-id] #(assoc % :layout-item-h-sizing :fix :layout-item-v-sizing :fix :variant-id variant-id))
|
||||||
|
(cl/add-stroke variant-vec {:stroke-alignment :inner
|
||||||
|
:stroke-style :solid
|
||||||
|
:stroke-color "#bb97d8" ;; todo use color var?
|
||||||
|
:stroke-opacity 1
|
||||||
|
:stroke-width 2})
|
||||||
|
(dwl/duplicate-component file-id (:component-id main) new-component-id)
|
||||||
|
(set-variant-id (:component-id main) variant-id)
|
||||||
|
(set-variant-id new-component-id variant-id)
|
||||||
|
(add-new-property variant-id)
|
||||||
|
(dwu/commit-undo-transaction undo-id))))))
|
|
@ -17,10 +17,15 @@
|
||||||
[{:keys [shape main-instance?]}]
|
[{:keys [shape main-instance?]}]
|
||||||
(if (ctk/instance-head? shape)
|
(if (ctk/instance-head? shape)
|
||||||
(if main-instance?
|
(if main-instance?
|
||||||
i/component
|
(if (ctk/is-variant? shape)
|
||||||
|
i/variant
|
||||||
|
i/component)
|
||||||
i/component-copy)
|
i/component-copy)
|
||||||
(case (:type shape)
|
(case (:type shape)
|
||||||
:frame (cond
|
:frame (cond
|
||||||
|
(ctk/is-variant-container? shape)
|
||||||
|
i/component
|
||||||
|
|
||||||
(and (ctl/flex-layout? shape) (ctl/col? shape))
|
(and (ctl/flex-layout? shape) (ctl/col? shape))
|
||||||
i/flex-horizontal
|
i/flex-horizontal
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
max-height: $sz-400;
|
max-height: $sz-400;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
z-index: var(--z-index-dropdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
|
|
|
@ -257,6 +257,7 @@
|
||||||
(def ^:icon v2-icon-2 (icon-xref :v2-icon-2))
|
(def ^:icon v2-icon-2 (icon-xref :v2-icon-2))
|
||||||
(def ^:icon v2-icon-3 (icon-xref :v2-icon-3))
|
(def ^:icon v2-icon-3 (icon-xref :v2-icon-3))
|
||||||
(def ^:icon v2-icon-4 (icon-xref :v2-icon-4))
|
(def ^:icon v2-icon-4 (icon-xref :v2-icon-4))
|
||||||
|
(def ^:icon variant (icon-xref :variant))
|
||||||
(def ^:icon vertical-align-items-center (icon-xref :vertical-align-items-center))
|
(def ^:icon vertical-align-items-center (icon-xref :vertical-align-items-center))
|
||||||
(def ^:icon vertical-align-items-end (icon-xref :vertical-align-items-end))
|
(def ^:icon vertical-align-items-end (icon-xref :vertical-align-items-end))
|
||||||
(def ^:icon vertical-align-items-start (icon-xref :vertical-align-items-start))
|
(def ^:icon vertical-align-items-start (icon-xref :vertical-align-items-start))
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.libraries :as dwl]
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
|
[app.main.data.workspace.variants :as dwv]
|
||||||
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.render :refer [component-svg component-svg-thumbnail]]
|
[app.main.render :refer [component-svg component-svg-thumbnail]]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
|
@ -372,6 +374,8 @@
|
||||||
can-detach? (and (seq copies)
|
can-detach? (and (seq copies)
|
||||||
(every? #(not (ctn/has-any-copy-parent? objects %)) copies))
|
(every? #(not (ctn/has-any-copy-parent? objects %)) copies))
|
||||||
|
|
||||||
|
variants? (features/use-feature "variants/v1")
|
||||||
|
|
||||||
|
|
||||||
do-detach-component
|
do-detach-component
|
||||||
#(st/emit! (dwl/detach-components (map :id copies)))
|
#(st/emit! (dwl/detach-components (map :id copies)))
|
||||||
|
@ -405,6 +409,10 @@
|
||||||
do-create-annotation
|
do-create-annotation
|
||||||
#(st/emit! (dw/set-annotations-id-for-create id))
|
#(st/emit! (dw/set-annotations-id-for-create id))
|
||||||
|
|
||||||
|
do-add-variant
|
||||||
|
#(when variants?
|
||||||
|
(st/emit! (dwv/transform-in-variant id)))
|
||||||
|
|
||||||
do-show-local-component
|
do-show-local-component
|
||||||
#(st/emit! (dwl/go-to-local-component :id component-id))
|
#(st/emit! (dwl/go-to-local-component :id component-id))
|
||||||
|
|
||||||
|
@ -454,5 +462,8 @@
|
||||||
:action do-show-component})
|
:action do-show-component})
|
||||||
(when can-update-main?
|
(when can-update-main?
|
||||||
{:title (tr "workspace.shape.menu.update-main")
|
{:title (tr "workspace.shape.menu.update-main")
|
||||||
:action do-update-component})]]
|
:action do-update-component})
|
||||||
|
(when (and variants? (not multi) main-instance?)
|
||||||
|
{:title (tr "workspace.shape.menu.add-variant")
|
||||||
|
:action do-add-variant})]]
|
||||||
(filter (complement nil?) menu-entries)))
|
(filter (complement nil?) menu-entries)))
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.collapse :as dwc]
|
[app.main.data.workspace.collapse :as dwc]
|
||||||
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.shape-icon :as sic]
|
[app.main.ui.components.shape-icon :as sic]
|
||||||
|
@ -53,7 +54,10 @@
|
||||||
(= uuid/zero (:parent-id item)))
|
(= uuid/zero (:parent-id item)))
|
||||||
absolute? (ctl/item-absolute? item)
|
absolute? (ctl/item-absolute? item)
|
||||||
components-v2 (mf/use-ctx ctx/components-v2)
|
components-v2 (mf/use-ctx ctx/components-v2)
|
||||||
main-instance? (or (not components-v2) (:main-instance item))]
|
main-instance? (or (not components-v2) (:main-instance item))
|
||||||
|
variants? (features/use-feature "variants/v1")
|
||||||
|
is-variant? (when variants? (ctk/is-variant? item))
|
||||||
|
variant-name (when is-variant? (:variant-name item))]
|
||||||
[:*
|
[:*
|
||||||
[:div {:id id
|
[:div {:id id
|
||||||
:ref dref
|
:ref dref
|
||||||
|
@ -130,6 +134,7 @@
|
||||||
:is-selected selected?
|
:is-selected selected?
|
||||||
:type-comp component-tree?
|
:type-comp component-tree?
|
||||||
:type-frame (cfh/frame-shape? item)
|
:type-frame (cfh/frame-shape? item)
|
||||||
|
:variant-name variant-name
|
||||||
:is-hidden hidden?}]
|
:is-hidden hidden?}]
|
||||||
|
|
||||||
(when (not read-only?)
|
(when (not read-only?)
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
::mf/forward-ref true}
|
::mf/forward-ref true}
|
||||||
[{:keys [shape-id shape-name is-shape-touched disabled-double-click
|
[{:keys [shape-id shape-name is-shape-touched disabled-double-click
|
||||||
on-start-edit on-stop-edit depth parent-size is-selected
|
on-start-edit on-stop-edit depth parent-size is-selected
|
||||||
type-comp type-frame is-hidden is-blocked]} external-ref]
|
type-comp type-frame variant-name is-hidden is-blocked]} external-ref]
|
||||||
(let [edition* (mf/use-state false)
|
(let [edition* (mf/use-state false)
|
||||||
edition? (deref edition*)
|
edition? (deref edition*)
|
||||||
|
|
||||||
|
@ -38,6 +38,8 @@
|
||||||
|
|
||||||
shape-for-rename (mf/deref lens:shape-for-rename)
|
shape-for-rename (mf/deref lens:shape-for-rename)
|
||||||
|
|
||||||
|
shape-name (d/nilv variant-name shape-name)
|
||||||
|
|
||||||
has-path? (str/includes? shape-name "/")
|
has-path? (str/includes? shape-name "/")
|
||||||
|
|
||||||
start-edit
|
start-edit
|
||||||
|
|
|
@ -11,10 +11,13 @@
|
||||||
[app.common.files.helpers :as cfh]
|
[app.common.files.helpers :as cfh]
|
||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
[app.common.types.file :as ctf]
|
[app.common.types.file :as ctf]
|
||||||
|
[app.main.data.helpers :as dsh]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.libraries :as dwl]
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
[app.main.data.workspace.specialized-panel :as dwsp]
|
[app.main.data.workspace.specialized-panel :as dwsp]
|
||||||
|
[app.main.data.workspace.variants :as dwv]
|
||||||
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
|
@ -23,6 +26,9 @@
|
||||||
[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 ctx]
|
[app.main.ui.context :as ctx]
|
||||||
|
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
|
||||||
|
[app.main.ui.ds.controls.combobox :refer [combobox*]]
|
||||||
|
[app.main.ui.ds.controls.input-with-values :refer [input-with-values*]]
|
||||||
[app.main.ui.hooks :as h]
|
[app.main.ui.hooks :as h]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.workspace.sidebar.assets.common :as cmm]
|
[app.main.ui.workspace.sidebar.assets.common :as cmm]
|
||||||
|
@ -225,6 +231,78 @@
|
||||||
(when (or editing? creating?)
|
(when (or editing? creating?)
|
||||||
[:div {:class (stl/css :counter)} (str size "/300")])]])))
|
[:div {:class (stl/css :counter)} (str size "/300")])]])))
|
||||||
|
|
||||||
|
|
||||||
|
(mf/defc component-variant*
|
||||||
|
[{:keys [component shape data page-id]}]
|
||||||
|
(let [id-component (:id component)
|
||||||
|
properties (:variant-properties component)
|
||||||
|
variant-id (:variant-id component)
|
||||||
|
objects (-> (dsh/get-page data page-id)
|
||||||
|
(get :objects))
|
||||||
|
|
||||||
|
related-components (dwv/find-related-components data objects variant-id)
|
||||||
|
|
||||||
|
flat-comps ;; Get a list like [{:id 0 :prop1 "v1" :prop2 "v2"} {:id 1, :prop1 "v3" :prop2 "v4"}]
|
||||||
|
(map (fn [{:keys [id variant-properties]}]
|
||||||
|
(into {:id id}
|
||||||
|
(map (fn [{:keys [name value]}] [(keyword name) value])
|
||||||
|
variant-properties)))
|
||||||
|
related-components)
|
||||||
|
|
||||||
|
get-options
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps related-components)
|
||||||
|
(fn [prop-name]
|
||||||
|
(->> related-components
|
||||||
|
(mapcat (fn [item]
|
||||||
|
(map :value (filter (fn [prop] (= (:name prop) prop-name))
|
||||||
|
(:variant-properties item)))))
|
||||||
|
(filter some?)
|
||||||
|
distinct
|
||||||
|
(map (fn [val] {:label val :id val})))))
|
||||||
|
|
||||||
|
filter-matching
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps flat-comps)
|
||||||
|
(fn [id exclude-key]
|
||||||
|
(let [reference-item (first (filter #(= (:id %) id) flat-comps))
|
||||||
|
reference-values (dissoc reference-item :id exclude-key)]
|
||||||
|
|
||||||
|
(->> flat-comps
|
||||||
|
(filter (fn [item]
|
||||||
|
(= (dissoc item :id exclude-key) reference-values)))
|
||||||
|
(map (fn [item] {:label (get item exclude-key) :value (:id item)}))))))
|
||||||
|
|
||||||
|
|
||||||
|
change-property-value
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps id-component)
|
||||||
|
(fn [pos value]
|
||||||
|
(when-not (str/empty? value)
|
||||||
|
(st/emit! (dwv/update-property-value id-component pos value)))))
|
||||||
|
|
||||||
|
switch-component
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps shape)
|
||||||
|
(fn [id]
|
||||||
|
(st/emit! (dwl/component-swap shape (:component-file shape) id))))]
|
||||||
|
[:*
|
||||||
|
(for [[pos prop] (map vector (range) properties)]
|
||||||
|
|
||||||
|
[:div {:key (str (:id shape) (:name prop)) :class (stl/css :variant-property-container)}
|
||||||
|
(if (ctk/main-instance? shape)
|
||||||
|
[:*
|
||||||
|
[:span {:class (stl/css :variant-property-name :variant-property-name-bg)} (:name prop)]
|
||||||
|
[:> combobox* {:default-selected (str (or (:value prop) ""))
|
||||||
|
:options (clj->js (get-options (:name prop)))
|
||||||
|
:on-change (partial change-property-value pos)}]]
|
||||||
|
|
||||||
|
[:*
|
||||||
|
[:span {:class (stl/css :variant-property-name)} (:name prop)]
|
||||||
|
[:& select {:default-value id-component
|
||||||
|
:options (filter-matching id-component (keyword (:name prop)))
|
||||||
|
:on-change switch-component}]])])]))
|
||||||
|
|
||||||
(mf/defc component-swap-item
|
(mf/defc component-swap-item
|
||||||
{::mf/props :obj}
|
{::mf/props :obj}
|
||||||
[{:keys [item loop shapes file-id root-shape container component-id is-search listing-thumbs]}]
|
[{:keys [item loop shapes file-id root-shape container component-id is-search listing-thumbs]}]
|
||||||
|
@ -508,36 +586,43 @@
|
||||||
:on-click (partial do-action action)}
|
:on-click (partial do-action action)}
|
||||||
[:span {:class (stl/css :dropdown-label)} title]]))]]))
|
[:span {:class (stl/css :dropdown-label)} title]]))]]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(mf/defc component-menu
|
(mf/defc component-menu
|
||||||
{::mf/props :obj}
|
{::mf/props :obj}
|
||||||
[{:keys [shapes swap-opened?]}]
|
[{:keys [shapes swap-opened?]}]
|
||||||
(let [current-file-id (mf/use-ctx ctx/current-file-id)
|
(let [current-file-id (mf/use-ctx ctx/current-file-id)
|
||||||
|
current-page-id (mf/use-ctx ctx/current-page-id)
|
||||||
|
|
||||||
libraries (deref refs/libraries)
|
libraries (deref refs/libraries)
|
||||||
current-file (get libraries current-file-id)
|
current-file (get libraries current-file-id)
|
||||||
|
data (get-in libraries [current-file-id :data])
|
||||||
|
|
||||||
state* (mf/use-state
|
state* (mf/use-state
|
||||||
#(do {:show-content true
|
#(do {:show-content true
|
||||||
:menu-open false}))
|
:menu-open false}))
|
||||||
state (deref state*)
|
state (deref state*)
|
||||||
open? (:show-content state)
|
open? (:show-content state)
|
||||||
menu-open? (:menu-open state)
|
menu-open? (:menu-open state)
|
||||||
|
|
||||||
shapes (filter ctk/instance-head? shapes)
|
shapes (filter ctk/instance-head? shapes)
|
||||||
multi (> (count shapes) 1)
|
multi (> (count shapes) 1)
|
||||||
copies (filter ctk/in-component-copy? shapes)
|
copies (filter ctk/in-component-copy? shapes)
|
||||||
can-swap? (boolean (seq copies))
|
can-swap? (boolean (seq copies))
|
||||||
|
|
||||||
;; For when it's only one shape
|
;; For when it's only one shape
|
||||||
shape (first shapes)
|
shape (first shapes)
|
||||||
id (:id shape)
|
id (:id shape)
|
||||||
shape-name (:name shape)
|
shape-name (:name shape)
|
||||||
|
|
||||||
component (ctf/resolve-component shape
|
component (ctf/resolve-component shape
|
||||||
current-file
|
current-file
|
||||||
libraries
|
libraries
|
||||||
{:include-deleted? true})
|
{:include-deleted? true})
|
||||||
main-instance? (ctk/main-instance? shape)
|
|
||||||
|
variants? (features/use-feature "variants/v1")
|
||||||
|
is-variant? (when variants? (ctk/is-variant? component))
|
||||||
|
main-instance? (ctk/main-instance? shape)
|
||||||
|
|
||||||
toggle-content
|
toggle-content
|
||||||
(mf/use-fn #(swap! state* update :show-content not))
|
(mf/use-fn #(swap! state* update :show-content not))
|
||||||
|
@ -576,9 +661,9 @@
|
||||||
(fn []
|
(fn []
|
||||||
(swap! state* update :render inc)))
|
(swap! state* update :render inc)))
|
||||||
|
|
||||||
menu-entries (cmm/generate-components-menu-entries shapes true)
|
menu-entries (cmm/generate-components-menu-entries shapes true)
|
||||||
show-menu? (seq menu-entries)
|
show-menu? (seq menu-entries)
|
||||||
path (->> component (:path) (cfh/split-path) (cfh/join-path-with-dot))]
|
path (->> component (:path) (cfh/split-path) (cfh/join-path-with-dot))]
|
||||||
|
|
||||||
(when (seq shapes)
|
(when (seq shapes)
|
||||||
[:div {:class (stl/css :element-set)}
|
[:div {:class (stl/css :element-set)}
|
||||||
|
@ -612,7 +697,9 @@
|
||||||
|
|
||||||
[:span {:class (stl/css :component-icon)}
|
[:span {:class (stl/css :component-icon)}
|
||||||
(if main-instance?
|
(if main-instance?
|
||||||
i/component
|
(if is-variant?
|
||||||
|
i/variant
|
||||||
|
i/component)
|
||||||
i/component-copy)]
|
i/component-copy)]
|
||||||
|
|
||||||
[:div {:class (stl/css :name-wrapper)}
|
[:div {:class (stl/css :name-wrapper)}
|
||||||
|
@ -643,5 +730,119 @@
|
||||||
|
|
||||||
(when (and (not swap-opened?) (not multi))
|
(when (and (not swap-opened?) (not multi))
|
||||||
[:& component-annotation {:id id :shape shape :component component :rerender-fn rerender-fn}])
|
[:& component-annotation {:id id :shape shape :component component :rerender-fn rerender-fn}])
|
||||||
|
|
||||||
|
(when (and is-variant? (not swap-opened?) (not multi))
|
||||||
|
[:> component-variant* {:component component :shape shape :data data :page-id current-page-id}])
|
||||||
|
|
||||||
(when (dbg/enabled? :display-touched)
|
(when (dbg/enabled? :display-touched)
|
||||||
[:div ":touched " (str (:touched shape))])])])))
|
[:div ":touched " (str (:touched shape))])])])))
|
||||||
|
|
||||||
|
|
||||||
|
(mf/defc variant-menu*
|
||||||
|
[{:keys [shapes]}]
|
||||||
|
(let [;; TODO check multi. What is shown? User can change properties like width?
|
||||||
|
multi (> (count shapes) 1)
|
||||||
|
|
||||||
|
shape (first shapes)
|
||||||
|
shape-name (:name shape)
|
||||||
|
|
||||||
|
libraries (deref refs/libraries)
|
||||||
|
current-file-id (mf/use-ctx ctx/current-file-id)
|
||||||
|
current-page-id (mf/use-ctx ctx/current-page-id)
|
||||||
|
data (get-in libraries [current-file-id :data])
|
||||||
|
|
||||||
|
objects (-> (dsh/get-page data current-page-id)
|
||||||
|
(get :objects))
|
||||||
|
|
||||||
|
first-variant (get objects (first (:shapes shape)))
|
||||||
|
variant-id (:variant-id first-variant)
|
||||||
|
|
||||||
|
properties (->> (dwv/find-related-components data objects variant-id)
|
||||||
|
(mapcat :variant-properties)
|
||||||
|
(group-by :name)
|
||||||
|
(map (fn [[k v]] {:name k :values (map :value v)})))
|
||||||
|
|
||||||
|
menu-open* (mf/use-state false)
|
||||||
|
menu-open? (deref menu-open*)
|
||||||
|
|
||||||
|
|
||||||
|
menu-entries [{:title (tr "workspace.shape.menu.add-variant-property")
|
||||||
|
:action #(st/emit! (dwv/add-new-property variant-id))}]
|
||||||
|
|
||||||
|
show-menu? (seq menu-entries)
|
||||||
|
|
||||||
|
on-menu-click
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps menu-open* menu-open?)
|
||||||
|
(fn [event]
|
||||||
|
(dom/prevent-default event)
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(reset! menu-open* (not menu-open?))))
|
||||||
|
|
||||||
|
on-menu-close
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps menu-open*)
|
||||||
|
#(reset! menu-open* false))
|
||||||
|
|
||||||
|
update-property-name
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps variant-id)
|
||||||
|
(fn [pos new-name]
|
||||||
|
(st/emit! (dwv/update-property-name variant-id pos new-name))))
|
||||||
|
|
||||||
|
remove-property
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps variant-id)
|
||||||
|
(fn [pos]
|
||||||
|
(when (> (count properties) 1)
|
||||||
|
(st/emit! (dwv/remove-property variant-id pos)))))]
|
||||||
|
(when (seq shapes)
|
||||||
|
[:div {:class (stl/css :element-set)}
|
||||||
|
[:div {:class (stl/css :element-title)}
|
||||||
|
|
||||||
|
|
||||||
|
[:& title-bar {:collapsable false
|
||||||
|
:title (tr "workspace.options.component")
|
||||||
|
:class (stl/css :title-spacing-component)}
|
||||||
|
[:span {:class (stl/css :copy-text)}
|
||||||
|
(tr "workspace.options.component.main")]]]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :element-content)}
|
||||||
|
[:div {:class (stl/css-case :component-wrapper true
|
||||||
|
:with-actions show-menu?
|
||||||
|
:without-actions (not show-menu?))}
|
||||||
|
[:button {:class (stl/css-case :component-name-wrapper true
|
||||||
|
:with-main true
|
||||||
|
:swappeable false)}
|
||||||
|
|
||||||
|
[:span {:class (stl/css :component-icon)} i/component]
|
||||||
|
|
||||||
|
[:div {:class (stl/css :name-wrapper)}
|
||||||
|
[:div {:class (stl/css :component-name)}
|
||||||
|
[:span {:class (stl/css :component-name-inside)}
|
||||||
|
(if multi
|
||||||
|
(tr "settings.multiple")
|
||||||
|
(cfh/last-path shape-name))]]]]
|
||||||
|
|
||||||
|
|
||||||
|
(when show-menu?
|
||||||
|
[:div {:class (stl/css :component-actions)}
|
||||||
|
[:button {:class (stl/css-case :menu-btn true
|
||||||
|
:selected menu-open?)
|
||||||
|
:on-click on-menu-click}
|
||||||
|
i/menu]
|
||||||
|
|
||||||
|
[:& component-ctx-menu {:show menu-open?
|
||||||
|
:on-close on-menu-close
|
||||||
|
:menu-entries menu-entries
|
||||||
|
:main-instance true}]])]
|
||||||
|
[:*
|
||||||
|
(for [[pos property] (map vector (range) properties)]
|
||||||
|
(let [val (str/join ", " (:values property))]
|
||||||
|
[:div {:key (str (:id shape) (:name property)) :class (stl/css :variant-property-row)}
|
||||||
|
[:> input-with-values* {:name (:name property) :values val :on-blur (partial update-property-name pos)}]
|
||||||
|
[:> icon-button* {:variant "ghost"
|
||||||
|
:aria-label (tr "workspace.shape.menu.remove-variant-property")
|
||||||
|
:on-click (partial remove-property pos)
|
||||||
|
:icon "remove"
|
||||||
|
:disabled (<= (count properties) 1)}]]))]]])))
|
|
@ -4,7 +4,9 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) KALEIDOS INC
|
// Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
@use "../../../../ds/typography.scss" as t;
|
||||||
@import "refactor/common-refactor.scss";
|
@import "refactor/common-refactor.scss";
|
||||||
|
|
||||||
.element-set {
|
.element-set {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-top: $s-8;
|
padding-top: $s-8;
|
||||||
|
@ -33,6 +35,7 @@
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
width: $s-12;
|
width: $s-12;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
height: $s-12;
|
height: $s-12;
|
||||||
width: $s-12;
|
width: $s-12;
|
||||||
|
@ -54,6 +57,7 @@
|
||||||
|
|
||||||
&.without-actions {
|
&.without-actions {
|
||||||
padding-right: 0.5rem;
|
padding-right: 0.5rem;
|
||||||
|
|
||||||
.component-name-wrapper {
|
.component-name-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: $br-8;
|
border-radius: $br-8;
|
||||||
|
@ -71,6 +75,7 @@
|
||||||
border-radius: $br-8 0 0 $br-8;
|
border-radius: $br-8 0 0 $br-8;
|
||||||
background-color: var(--assets-item-background-color);
|
background-color: var(--assets-item-background-color);
|
||||||
color: var(--assets-item-name-foreground-color-hover);
|
color: var(--assets-item-name-foreground-color-hover);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--assets-item-background-color-hover);
|
background-color: var(--assets-item-background-color-hover);
|
||||||
color: var(--assets-item-name-foreground-color-hover);
|
color: var(--assets-item-name-foreground-color-hover);
|
||||||
|
@ -81,6 +86,7 @@
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
height: $s-32;
|
height: $s-32;
|
||||||
width: $s-12;
|
width: $s-12;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
@extend .button-icon-small;
|
@extend .button-icon-small;
|
||||||
stroke: var(--icon-foreground);
|
stroke: var(--icon-foreground);
|
||||||
|
@ -129,14 +135,17 @@
|
||||||
border-radius: 0 $br-8 $br-8 0;
|
border-radius: 0 $br-8 $br-8 0;
|
||||||
background-color: var(--assets-item-background-color);
|
background-color: var(--assets-item-background-color);
|
||||||
color: var(--assets-item-name-foreground-color-hover);
|
color: var(--assets-item-name-foreground-color-hover);
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
@extend .button-icon;
|
@extend .button-icon;
|
||||||
min-height: $s-16;
|
min-height: $s-16;
|
||||||
min-width: $s-16;
|
min-width: $s-16;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--assets-item-background-color-hover);
|
background-color: var(--assets-item-background-color-hover);
|
||||||
color: var(--assets-item-name-foreground-color-hover);
|
color: var(--assets-item-name-foreground-color-hover);
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
@extend .button-icon-selected;
|
@extend .button-icon-selected;
|
||||||
}
|
}
|
||||||
|
@ -177,6 +186,7 @@
|
||||||
|
|
||||||
.icon-wrapper {
|
.icon-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
@extend .button-icon-small;
|
@extend .button-icon-small;
|
||||||
stroke: var(--icon-foreground);
|
stroke: var(--icon-foreground);
|
||||||
|
@ -192,9 +202,11 @@
|
||||||
border: 0;
|
border: 0;
|
||||||
font-size: $fs-12;
|
font-size: $fs-12;
|
||||||
color: var(--input-foreground-color-active);
|
color: var(--input-foreground-color-active);
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: var(--input-foreground-color-disabled);
|
color: var(--input-foreground-color-disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
border-color: var(--input-border-outline-color-active);
|
border-color: var(--input-border-outline-color-active);
|
||||||
}
|
}
|
||||||
|
@ -205,8 +217,10 @@
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
height: $s-16;
|
height: $s-16;
|
||||||
width: $s-16;
|
width: $s-16;
|
||||||
|
|
||||||
.clear-icon {
|
.clear-icon {
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
@extend .button-icon-small;
|
@extend .button-icon-small;
|
||||||
stroke: var(--icon-foreground);
|
stroke: var(--icon-foreground);
|
||||||
|
@ -218,6 +232,7 @@
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
width: $s-12;
|
width: $s-12;
|
||||||
margin-left: $s-8;
|
margin-left: $s-8;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
@extend .button-icon-small;
|
@extend .button-icon-small;
|
||||||
stroke: var(--icon-foreground);
|
stroke: var(--icon-foreground);
|
||||||
|
@ -240,6 +255,7 @@
|
||||||
.back-arrow {
|
.back-arrow {
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
height: $s-32;
|
height: $s-32;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
height: $s-12;
|
height: $s-12;
|
||||||
width: $s-12;
|
width: $s-12;
|
||||||
|
@ -329,6 +345,7 @@
|
||||||
--assets-component-current-border-color: var(--assets-component-border-color);
|
--assets-component-current-border-color: var(--assets-component-border-color);
|
||||||
border: $s-4 solid var(--assets-component-current-border-color);
|
border: $s-4 solid var(--assets-component-current-border-color);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: auto;
|
height: auto;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
@ -337,12 +354,14 @@
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
stroke: none;
|
stroke: none;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.component-name {
|
.component-name {
|
||||||
@include bodySmallTypography;
|
@include bodySmallTypography;
|
||||||
@include textEllipsis;
|
@include textEllipsis;
|
||||||
|
@ -358,6 +377,7 @@
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--assets-item-background-color-hover);
|
background-color: var(--assets-item-background-color-hover);
|
||||||
|
|
||||||
.component-name {
|
.component-name {
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--assets-item-name-foreground-color-hover);
|
color: var(--assets-item-name-foreground-color-hover);
|
||||||
|
@ -367,6 +387,7 @@
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
--assets-component-current-border-color: var(--assets-item-border-color);
|
--assets-component-current-border-color: var(--assets-item-border-color);
|
||||||
|
|
||||||
.component-name {
|
.component-name {
|
||||||
color: var(--assets-item-name-foreground-color-hover);
|
color: var(--assets-item-name-foreground-color-hover);
|
||||||
}
|
}
|
||||||
|
@ -375,9 +396,11 @@
|
||||||
&.disabled {
|
&.disabled {
|
||||||
background: var(--assets-component-background-color-disabled);
|
background: var(--assets-component-background-color-disabled);
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
cursor: auto;
|
cursor: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.component-name {
|
.component-name {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
to top,
|
to top,
|
||||||
|
@ -461,8 +484,10 @@
|
||||||
@include textEllipsis;
|
@include textEllipsis;
|
||||||
color: var(--assets-item-name-foreground-color);
|
color: var(--assets-item-name-foreground-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: var(--assets-item-name-foreground-color-hover);
|
color: var(--assets-item-name-foreground-color-hover);
|
||||||
|
|
||||||
.component-group-name {
|
.component-group-name {
|
||||||
color: var(--assets-item-name-foreground-color-hover);
|
color: var(--assets-item-name-foreground-color-hover);
|
||||||
}
|
}
|
||||||
|
@ -472,6 +497,7 @@
|
||||||
.arrow-icon {
|
.arrow-icon {
|
||||||
@include flexCenter;
|
@include flexCenter;
|
||||||
height: $s-32;
|
height: $s-32;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
height: $s-12;
|
height: $s-12;
|
||||||
width: $s-12;
|
width: $s-12;
|
||||||
|
@ -525,12 +551,14 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
@extend .button-icon;
|
@extend .button-icon;
|
||||||
stroke: var(--icon-foreground);
|
stroke: var(--icon-foreground);
|
||||||
width: $s-16;
|
width: $s-16;
|
||||||
height: $s-16;
|
height: $s-16;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.expanded svg {
|
&.expanded svg {
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
|
@ -562,6 +590,7 @@
|
||||||
|
|
||||||
&.icon-tick.invalid:hover {
|
&.icon-tick.invalid:hover {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
stroke: var(--icon-foreground);
|
stroke: var(--icon-foreground);
|
||||||
}
|
}
|
||||||
|
@ -589,8 +618,10 @@
|
||||||
|
|
||||||
&.editing {
|
&.editing {
|
||||||
border: $s-1 solid var(--input-border-color-success);
|
border: $s-1 solid var(--input-border-color-success);
|
||||||
|
|
||||||
.annotation-title {
|
.annotation-title {
|
||||||
border-bottom: $s-1 solid var(--entry-border-color-disabled);
|
border-bottom: $s-1 solid var(--entry-border-color-disabled);
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
@ -603,9 +634,11 @@
|
||||||
|
|
||||||
&.creating {
|
&.creating {
|
||||||
border: $s-1 solid var(--input-border-color-success);
|
border: $s-1 solid var(--input-border-color-success);
|
||||||
|
|
||||||
.annotation-title .icon {
|
.annotation-title .icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
min-height: $s-252;
|
min-height: $s-252;
|
||||||
}
|
}
|
||||||
|
@ -613,6 +646,7 @@
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -650,7 +684,8 @@
|
||||||
-moz-box-shadow: none;
|
-moz-box-shadow: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|
||||||
resize: none; /*remove the resize handle on the bottom right*/
|
resize: none;
|
||||||
|
/*remove the resize handle on the bottom right*/
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea,
|
textarea,
|
||||||
|
@ -666,3 +701,37 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.variant-property-row {
|
||||||
|
@include flexRow;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
margin-block-start: $s-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.variant-property-container {
|
||||||
|
@include t.use-typography("body-small");
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
gap: var(--sp-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.variant-property-name-bg {
|
||||||
|
border-radius: $br-8;
|
||||||
|
background-color: var(--assets-item-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.variant-property-name {
|
||||||
|
color: var(--color-foreground-primary);
|
||||||
|
|
||||||
|
width: $s-104;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: var(--sp-xxxl);
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
|
[app.main.ui.workspace.sidebar.options.menus.blur :refer [blur-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]]
|
[app.main.ui.workspace.sidebar.options.menus.color-selection :refer [color-selection-menu*]]
|
||||||
[app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu]]
|
[app.main.ui.workspace.sidebar.options.menus.component :refer [component-menu variant-menu*]]
|
||||||
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
|
[app.main.ui.workspace.sidebar.options.menus.constraints :refer [constraint-attrs constraints-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-attrs-shape fill-menu]]
|
[app.main.ui.workspace.sidebar.options.menus.fill :refer [fill-attrs-shape fill-menu]]
|
||||||
[app.main.ui.workspace.sidebar.options.menus.frame-grid :refer [frame-grid]]
|
[app.main.ui.workspace.sidebar.options.menus.frame-grid :refer [frame-grid]]
|
||||||
|
@ -66,58 +67,62 @@
|
||||||
is-layout-container? (ctl/any-layout? shape)
|
is-layout-container? (ctl/any-layout? shape)
|
||||||
is-flex-layout? (ctl/flex-layout? shape)
|
is-flex-layout? (ctl/flex-layout? shape)
|
||||||
is-grid-layout? (ctl/grid-layout? shape)
|
is-grid-layout? (ctl/grid-layout? shape)
|
||||||
is-layout-child-absolute? (ctl/item-absolute? shape)]
|
is-layout-child-absolute? (ctl/item-absolute? shape)
|
||||||
|
variants? (features/use-feature "variants/v1")
|
||||||
|
is-variant? (when variants? (:is-variant-container shape))]
|
||||||
|
|
||||||
[:*
|
(if is-variant?
|
||||||
[:& layer-menu {:ids ids
|
[:> variant-menu* {:shapes [shape]}]
|
||||||
:type shape-type
|
[:*
|
||||||
:values layer-values}]
|
[:& layer-menu {:ids ids
|
||||||
[:> measures-menu* {:ids ids
|
:type shape-type
|
||||||
:values measure-values
|
:values layer-values}]
|
||||||
:type shape-type
|
[:> measures-menu* {:ids ids
|
||||||
:shape shape}]
|
:values measure-values
|
||||||
|
:type shape-type
|
||||||
|
:shape shape}]
|
||||||
|
|
||||||
[:& component-menu {:shapes [shape]}]
|
[:& component-menu {:shapes [shape]}]
|
||||||
|
|
||||||
[:& layout-container-menu
|
[:& layout-container-menu
|
||||||
{:type shape-type
|
{:type shape-type
|
||||||
:ids [(:id shape)]
|
:ids [(:id shape)]
|
||||||
:values layout-container-values
|
:values layout-container-values
|
||||||
:multiple false}]
|
:multiple false}]
|
||||||
|
|
||||||
(when (and (= (count ids) 1) is-layout-child? is-grid-parent?)
|
(when (and (= (count ids) 1) is-layout-child? is-grid-parent?)
|
||||||
[:& grid-cell/options
|
[:& grid-cell/options
|
||||||
{:shape (first parents)
|
{:shape (first parents)
|
||||||
:cell (ctl/get-cell-by-shape-id (first parents) (first ids))}])
|
:cell (ctl/get-cell-by-shape-id (first parents) (first ids))}])
|
||||||
|
|
||||||
(when (or is-layout-child? is-layout-container?)
|
(when (or is-layout-child? is-layout-container?)
|
||||||
[:& layout-item-menu
|
[:& layout-item-menu
|
||||||
{:ids ids
|
{:ids ids
|
||||||
:type shape-type
|
:type shape-type
|
||||||
:values layout-item-values
|
:values layout-item-values
|
||||||
:is-flex-parent? is-flex-parent?
|
:is-flex-parent? is-flex-parent?
|
||||||
:is-grid-parent? is-grid-parent?
|
:is-grid-parent? is-grid-parent?
|
||||||
:is-flex-layout? is-flex-layout?
|
:is-flex-layout? is-flex-layout?
|
||||||
:is-grid-layout? is-grid-layout?
|
:is-grid-layout? is-grid-layout?
|
||||||
:is-layout-child? is-layout-child?
|
:is-layout-child? is-layout-child?
|
||||||
:is-layout-container? is-layout-container?
|
:is-layout-container? is-layout-container?
|
||||||
:shape shape}])
|
:shape shape}])
|
||||||
|
|
||||||
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
|
(when (or (not ^boolean is-layout-child?) ^boolean is-layout-child-absolute?)
|
||||||
[:& constraints-menu {:ids ids
|
[:& constraints-menu {:ids ids
|
||||||
:values constraint-values}])
|
:values constraint-values}])
|
||||||
|
|
||||||
[:& fill-menu {:ids ids
|
[:& fill-menu {:ids ids
|
||||||
:type shape-type
|
|
||||||
:values (select-keys shape fill-attrs-shape)}]
|
|
||||||
[:& stroke-menu {:ids ids
|
|
||||||
:type shape-type
|
:type shape-type
|
||||||
:values stroke-values}]
|
:values (select-keys shape fill-attrs-shape)}]
|
||||||
[:> color-selection-menu* {:type shape-type
|
[:& stroke-menu {:ids ids
|
||||||
:shapes shapes-with-children
|
:type shape-type
|
||||||
:file-id file-id
|
:values stroke-values}]
|
||||||
:libraries shared-libs}]
|
[:> color-selection-menu* {:type shape-type
|
||||||
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
|
:shapes shapes-with-children
|
||||||
[:& blur-menu {:ids ids
|
:file-id file-id
|
||||||
:values (select-keys shape [:blur])}]
|
:libraries shared-libs}]
|
||||||
[:& frame-grid {:shape shape}]]))
|
[:> shadow-menu* {:ids ids :values (get shape :shadow)}]
|
||||||
|
[:& blur-menu {:ids ids
|
||||||
|
:values (select-keys shape [:blur])}]
|
||||||
|
[:& frame-grid {:shape shape}]])))
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
[app.main.data.common :as dcm]
|
[app.main.data.common :as dcm]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.interactions :as dwi]
|
[app.main.data.workspace.interactions :as dwi]
|
||||||
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.streams :as ms]
|
[app.main.streams :as ms]
|
||||||
|
@ -131,9 +132,11 @@
|
||||||
(on-frame-leave (:id frame))))
|
(on-frame-leave (:id frame))))
|
||||||
|
|
||||||
main-instance? (ctk/main-instance? frame)
|
main-instance? (ctk/main-instance? frame)
|
||||||
|
variants? (features/use-feature "variants/v1")
|
||||||
|
is-variant? (when variants? (:is-variant-container frame))
|
||||||
|
|
||||||
text-width (* (:width frame) zoom)
|
text-width (* (:width frame) zoom)
|
||||||
show-icon? (and (or (:use-for-thumbnail frame) grid-edition? main-instance?)
|
show-icon? (and (or (:use-for-thumbnail frame) grid-edition? main-instance? is-variant?)
|
||||||
(not (<= text-width 15)))
|
(not (<= text-width 15)))
|
||||||
text-pos-x (if show-icon? 15 0)
|
text-pos-x (if show-icon? 15 0)
|
||||||
|
|
||||||
|
@ -196,7 +199,8 @@
|
||||||
(cond
|
(cond
|
||||||
(:use-for-thumbnail frame) [:use {:href "#icon-boards-thumbnail"}]
|
(:use-for-thumbnail frame) [:use {:href "#icon-boards-thumbnail"}]
|
||||||
grid-edition? [:use {:href "#icon-grid"}]
|
grid-edition? [:use {:href "#icon-grid"}]
|
||||||
main-instance? [:use {:href "#icon-component"}])])
|
main-instance? [:use {:href "#icon-component"}]
|
||||||
|
is-variant? [:use {:href "#icon-component"}])])
|
||||||
|
|
||||||
(if ^boolean edition?
|
(if ^boolean edition?
|
||||||
;; Case when edition? is true
|
;; Case when edition? is true
|
||||||
|
|
|
@ -6210,6 +6210,15 @@ msgstr "Selection to board"
|
||||||
msgid "workspace.shape.menu.create-component"
|
msgid "workspace.shape.menu.create-component"
|
||||||
msgstr "Create component"
|
msgstr "Create component"
|
||||||
|
|
||||||
|
msgid "workspace.shape.menu.add-variant"
|
||||||
|
msgstr "Add variant"
|
||||||
|
|
||||||
|
msgid "workspace.shape.menu.add-variant-property"
|
||||||
|
msgstr "Add new property"
|
||||||
|
|
||||||
|
msgid "workspace.shape.menu.remove-variant-property"
|
||||||
|
msgstr "Remove property"
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/context_menu.cljs:565
|
#: src/app/main/ui/workspace/context_menu.cljs:565
|
||||||
msgid "workspace.shape.menu.create-multiple-components"
|
msgid "workspace.shape.menu.create-multiple-components"
|
||||||
msgstr "Create multiple components"
|
msgstr "Create multiple components"
|
||||||
|
|
|
@ -6224,6 +6224,16 @@ msgstr "Tablero de selección"
|
||||||
msgid "workspace.shape.menu.create-component"
|
msgid "workspace.shape.menu.create-component"
|
||||||
msgstr "Crear componente"
|
msgstr "Crear componente"
|
||||||
|
|
||||||
|
msgid "workspace.shape.menu.add-variant"
|
||||||
|
msgstr "Añadir variante"
|
||||||
|
|
||||||
|
msgid "workspace.shape.menu.add-variant-property"
|
||||||
|
msgstr "Añadir nueva propiedad"
|
||||||
|
|
||||||
|
msgid "workspace.shape.menu.remove-variant-property"
|
||||||
|
msgstr "Eliminar propiedad"
|
||||||
|
|
||||||
|
|
||||||
#: src/app/main/ui/workspace/context_menu.cljs:565
|
#: src/app/main/ui/workspace/context_menu.cljs:565
|
||||||
msgid "workspace.shape.menu.create-multiple-components"
|
msgid "workspace.shape.menu.create-multiple-components"
|
||||||
msgstr "Crear múltiples componentes"
|
msgstr "Crear múltiples componentes"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue