mirror of
https://github.com/penpot/penpot.git
synced 2025-04-11 06:21:30 -05:00
🎉 Add option to save the layouts
This commit is contained in:
parent
8d9e772dca
commit
1d2ae6d5eb
17 changed files with 310 additions and 271 deletions
|
@ -14,6 +14,38 @@
|
|||
[uxbox.common.uuid :as uuid]
|
||||
[uxbox.tests.helpers :as th]))
|
||||
|
||||
(t/deftest process-change-set-option
|
||||
(let [data cp/default-page-data]
|
||||
(t/testing "Sets option single"
|
||||
(let [chg {:type :set-option
|
||||
:option :test
|
||||
:value "test"}
|
||||
res (cp/process-changes data [chg])]
|
||||
(t/is (= "test" (get-in res [:options :test])))))
|
||||
|
||||
(t/testing "Sets option nested"
|
||||
(let [chgs [{:type :set-option
|
||||
:option [:values :test :a]
|
||||
:value "a"}
|
||||
{:type :set-option
|
||||
:option [:values :test :b]
|
||||
:value "b"}]
|
||||
res (cp/process-changes data chgs)]
|
||||
(t/is (= {:a "a" :b "b"} (get-in res [:options :values :test])))))
|
||||
|
||||
(t/testing "Remove option"
|
||||
(let [chgs [{:type :set-option
|
||||
:option [:values :test :a]
|
||||
:value "a"}
|
||||
{:type :set-option
|
||||
:option [:values :test :b]
|
||||
:value "b"}
|
||||
{:type :set-option
|
||||
:option [:values :test]
|
||||
:value nil}]
|
||||
res (cp/process-changes data chgs)]
|
||||
(t/is (= nil (get-in res [:options :values :test])))))))
|
||||
|
||||
(t/deftest process-change-add-obj
|
||||
(let [data cp/default-page-data
|
||||
id-a (uuid/next)
|
||||
|
|
|
@ -253,6 +253,12 @@
|
|||
|
||||
(defmulti change-spec-impl :type)
|
||||
|
||||
(s/def :set-option/option any? #_(s/or keyword? (s/coll-of keyword?)))
|
||||
(s/def :set-option/value any?)
|
||||
|
||||
(defmethod change-spec-impl :set-option [_]
|
||||
(s/keys :req-un [:set-option/option :set-option/value]))
|
||||
|
||||
(defmethod change-spec-impl :add-obj [_]
|
||||
(s/keys :req-un [::id ::frame-id ::obj]
|
||||
:opt-un [::session-id ::parent-id]))
|
||||
|
@ -313,6 +319,12 @@
|
|||
|
||||
(declare insert-at-index)
|
||||
|
||||
(defmethod process-change :set-option
|
||||
[data {:keys [option value]}]
|
||||
(let [path (if (seqable? option) option [option])]
|
||||
(-> data
|
||||
(assoc-in (into [:options] path) value))))
|
||||
|
||||
(defmethod process-change :add-obj
|
||||
[data {:keys [id obj frame-id parent-id index] :as change}]
|
||||
(let [parent-id (or parent-id frame-id)
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
{
|
||||
"dashboard.grid.delete" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:61", "src/uxbox/main/ui/dashboard/grid.cljs:92" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:102", "src/uxbox/main/ui/dashboard/project.cljs:62" ],
|
||||
"translations" : {
|
||||
"en" : "Delete"
|
||||
}
|
||||
},
|
||||
"dashboard.grid.edit" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:60", "src/uxbox/main/ui/dashboard/grid.cljs:91" ],
|
||||
"translations" : {
|
||||
"en" : "Edit"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"dashboard.grid.empty-files" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:124" ],
|
||||
"translations" : {
|
||||
"en" : "You still have no files here"
|
||||
}
|
||||
},
|
||||
"dashboard.grid.rename" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:60", "src/uxbox/main/ui/dashboard/grid.cljs:91" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:101", "src/uxbox/main/ui/dashboard/project.cljs:61" ],
|
||||
"translations" : {
|
||||
"en" : "Rename"
|
||||
}
|
||||
},
|
||||
"dashboard.grid.empty-files" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:114" ],
|
||||
"translations" : {
|
||||
"en" : "You still have no files here"
|
||||
}
|
||||
},
|
||||
"dashboard.header.draft" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:55" ],
|
||||
"translations" : {
|
||||
|
@ -63,7 +63,7 @@
|
|||
}
|
||||
},
|
||||
"dashboard.header.project" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:68" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/project.cljs:57" ],
|
||||
"translations" : {
|
||||
"en" : "Project %s"
|
||||
}
|
||||
|
@ -176,7 +176,7 @@
|
|||
}
|
||||
},
|
||||
"ds.button.delete" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:152", "src/uxbox/main/ui/dashboard/library.cljs:220", "src/uxbox/main/ui/dashboard/library.cljs:257", "src/uxbox/main/ui/dashboard/library.cljs:296" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/library.cljs:152", "src/uxbox/main/ui/dashboard/library.cljs:220", "src/uxbox/main/ui/dashboard/library.cljs:259", "src/uxbox/main/ui/dashboard/library.cljs:300" ],
|
||||
"translations" : {
|
||||
"en" : "Delete"
|
||||
}
|
||||
|
@ -257,7 +257,7 @@
|
|||
"unused" : true
|
||||
},
|
||||
"ds.new-file" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:110", "src/uxbox/main/ui/dashboard/grid.cljs:116" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:120", "src/uxbox/main/ui/dashboard/grid.cljs:126" ],
|
||||
"translations" : {
|
||||
"en" : "+ New File",
|
||||
"fr" : null
|
||||
|
@ -299,7 +299,7 @@
|
|||
}
|
||||
},
|
||||
"ds.updated-at" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:35" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/dashboard/grid.cljs:45" ],
|
||||
"translations" : {
|
||||
"en" : "Updated: %s",
|
||||
"fr" : "Mis à jour: %s"
|
||||
|
@ -341,21 +341,21 @@
|
|||
}
|
||||
},
|
||||
"errors.generic" : {
|
||||
"used-in" : [ "src/uxbox/main/ui.cljs:179" ],
|
||||
"used-in" : [ "src/uxbox/main/ui.cljs:178" ],
|
||||
"translations" : {
|
||||
"en" : "Something wrong has happened.",
|
||||
"fr" : "Quelque chose c'est mal passé."
|
||||
}
|
||||
},
|
||||
"errors.network" : {
|
||||
"used-in" : [ "src/uxbox/main/ui.cljs:173" ],
|
||||
"used-in" : [ "src/uxbox/main/ui.cljs:172" ],
|
||||
"translations" : {
|
||||
"en" : "Unable to connect to backend server.",
|
||||
"fr" : "Impossible de se connecter au serveur principal."
|
||||
}
|
||||
},
|
||||
"header.sitemap" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:74" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:68" ],
|
||||
"translations" : {
|
||||
"en" : null,
|
||||
"fr" : null
|
||||
|
@ -459,7 +459,7 @@
|
|||
}
|
||||
},
|
||||
"profile.recovery.go-to-login" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/profile/recovery_request.cljs:65", "src/uxbox/main/ui/profile/recovery.cljs:81" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/profile/recovery.cljs:81", "src/uxbox/main/ui/profile/recovery_request.cljs:65" ],
|
||||
"translations" : {
|
||||
"en" : "Go back!",
|
||||
"fr" : "Retour!"
|
||||
|
@ -702,73 +702,73 @@
|
|||
}
|
||||
},
|
||||
"viewer.header.dont-show-interactions" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:40" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:67" ],
|
||||
"translations" : {
|
||||
"en" : "Don't show interactions"
|
||||
}
|
||||
},
|
||||
"viewer.header.edit-page" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:137" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:164" ],
|
||||
"translations" : {
|
||||
"en" : "Edit page"
|
||||
}
|
||||
},
|
||||
"viewer.header.fullscreen" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:148" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:175" ],
|
||||
"translations" : {
|
||||
"en" : "Full Screen"
|
||||
}
|
||||
},
|
||||
"viewer.header.share.copy-link" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:86" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:113" ],
|
||||
"translations" : {
|
||||
"en" : "Copy link"
|
||||
}
|
||||
},
|
||||
"viewer.header.share.create-link" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:94" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:121" ],
|
||||
"translations" : {
|
||||
"en" : "Create link"
|
||||
}
|
||||
},
|
||||
"viewer.header.share.placeholder" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:84" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:111" ],
|
||||
"translations" : {
|
||||
"en" : "Share link will apear here"
|
||||
}
|
||||
},
|
||||
"viewer.header.share.remove-link" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:92" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:119" ],
|
||||
"translations" : {
|
||||
"en" : "Remove link"
|
||||
}
|
||||
},
|
||||
"viewer.header.share.subtitle" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:88" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:115" ],
|
||||
"translations" : {
|
||||
"en" : "Anyone with the link will have access"
|
||||
}
|
||||
},
|
||||
"viewer.header.share.title" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:72", "src/uxbox/main/ui/viewer/header.cljs:74", "src/uxbox/main/ui/viewer/header.cljs:80" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:99", "src/uxbox/main/ui/viewer/header.cljs:101", "src/uxbox/main/ui/viewer/header.cljs:107" ],
|
||||
"translations" : {
|
||||
"en" : "Share link"
|
||||
}
|
||||
},
|
||||
"viewer.header.show-interactions" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:44" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:71" ],
|
||||
"translations" : {
|
||||
"en" : "Show interactions"
|
||||
}
|
||||
},
|
||||
"viewer.header.show-interactions-on-click" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:48" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:75" ],
|
||||
"translations" : {
|
||||
"en" : "Show interactions on click"
|
||||
}
|
||||
},
|
||||
"viewer.header.sitemap" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:121" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/viewer/header.cljs:148" ],
|
||||
"translations" : {
|
||||
"en" : "Sitemap"
|
||||
}
|
||||
|
@ -821,70 +821,92 @@
|
|||
"en" : "Align top"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.disable-dynamic-alignment" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:116" ],
|
||||
"translations" : {
|
||||
"en" : "Disable dynamic alignment"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.disable-snap-grid" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:92" ],
|
||||
"translations" : {
|
||||
"en" : "Disable snap to grid"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.enable-dynamic-alignment" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:117" ],
|
||||
"translations" : {
|
||||
"en" : "Enable dynamic aligment"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.enable-snap-grid" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:93" ],
|
||||
"translations" : {
|
||||
"en" : "Snap to grid"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.hide-grid" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:94" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:86" ],
|
||||
"translations" : {
|
||||
"en" : "Hide grid"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.hide-layers" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:101" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:98" ],
|
||||
"translations" : {
|
||||
"en" : "Hide layers"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.hide-libraries" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:115" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:110" ],
|
||||
"translations" : {
|
||||
"en" : "Hide libraries"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.hide-palette" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:108" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:104" ],
|
||||
"translations" : {
|
||||
"en" : "Hide color palette"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.hide-rules" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:87" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:80" ],
|
||||
"translations" : {
|
||||
"en" : "Hide rules"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.show-grid" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:95" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:87" ],
|
||||
"translations" : {
|
||||
"en" : "Show grid"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.show-layers" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:102" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:99" ],
|
||||
"translations" : {
|
||||
"en" : "Show layers"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.show-libraries" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:116" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:111" ],
|
||||
"translations" : {
|
||||
"en" : "Show libraries"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.show-palette" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:109" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:105" ],
|
||||
"translations" : {
|
||||
"en" : "Show color palette"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.show-rules" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:88" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:81" ],
|
||||
"translations" : {
|
||||
"en" : "Show rules"
|
||||
}
|
||||
},
|
||||
"workspace.header.menu.disable-dynamic-alignment": "Disable dynamic alignment",
|
||||
"workspace.header.menu.enable-dynamic-alignment": "Enable dynamic aligment",
|
||||
"workspace.header.viewer" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:153" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/header.cljs:154" ],
|
||||
"translations" : {
|
||||
"en" : "View mode (Ctrl + P)",
|
||||
"fr" : "Mode visualisation (Ctrl + P)"
|
||||
|
@ -927,11 +949,11 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.color" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/page.cljs:89" ],
|
||||
"translations" : {
|
||||
"en" : "Color",
|
||||
"fr" : "Couleur"
|
||||
}
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.options.design" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options.cljs:76" ],
|
||||
|
@ -940,7 +962,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.fill" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:69", "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:446" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/text.cljs:446", "src/uxbox/main/ui/workspace/sidebar/options/fill.cljs:71" ],
|
||||
"translations" : {
|
||||
"en" : "Fill",
|
||||
"fr" : "Fond"
|
||||
|
@ -1076,11 +1098,11 @@
|
|||
"unused" : true
|
||||
},
|
||||
"workspace.options.grid-options" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/page.cljs:76" ],
|
||||
"translations" : {
|
||||
"en" : "Grid settings",
|
||||
"fr" : "Paramètres de la grille"
|
||||
}
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.options.line-height-letter-spacing" : {
|
||||
"translations" : {
|
||||
|
@ -1097,13 +1119,13 @@
|
|||
"unused" : true
|
||||
},
|
||||
"workspace.options.navigate-to" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:51" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:58" ],
|
||||
"translations" : {
|
||||
"en" : "Navigate to"
|
||||
}
|
||||
},
|
||||
"workspace.options.none" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:64" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:71" ],
|
||||
"translations" : {
|
||||
"en" : "None"
|
||||
}
|
||||
|
@ -1116,7 +1138,7 @@
|
|||
"unused" : true
|
||||
},
|
||||
"workspace.options.position" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:135", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:126" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:127", "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:138" ],
|
||||
"translations" : {
|
||||
"en" : "Position",
|
||||
"fr" : "Position"
|
||||
|
@ -1129,14 +1151,14 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.radius" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:183" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:179" ],
|
||||
"translations" : {
|
||||
"en" : "Radius",
|
||||
"fr" : "TODO"
|
||||
}
|
||||
},
|
||||
"workspace.options.rotation" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:159" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:154" ],
|
||||
"translations" : {
|
||||
"en" : "Rotation",
|
||||
"fr" : "TODO"
|
||||
|
@ -1150,78 +1172,78 @@
|
|||
"unused" : true
|
||||
},
|
||||
"workspace.options.select-a-shape" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:45" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:52" ],
|
||||
"translations" : {
|
||||
"en" : "Select a shape, artboard or group to drag a connection to other artboard."
|
||||
}
|
||||
},
|
||||
"workspace.options.select-artboard" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:57" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:64" ],
|
||||
"translations" : {
|
||||
"en" : "Select artboard"
|
||||
}
|
||||
},
|
||||
"workspace.options.size" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/page.cljs:79", "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:107", "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:101" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:102", "src/uxbox/main/ui/workspace/sidebar/options/measures.cljs:110" ],
|
||||
"translations" : {
|
||||
"en" : "Size",
|
||||
"fr" : "Taille"
|
||||
}
|
||||
},
|
||||
"workspace.options.size-presets" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:83" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/frame.cljs:84" ],
|
||||
"translations" : {
|
||||
"en" : "Size presets"
|
||||
}
|
||||
},
|
||||
"workspace.options.stroke" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:109", "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:173" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:111", "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:175" ],
|
||||
"translations" : {
|
||||
"en" : "Stroke",
|
||||
"fr" : null
|
||||
}
|
||||
},
|
||||
"workspace.options.stroke.center" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:159" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:161" ],
|
||||
"translations" : {
|
||||
"en" : "Center"
|
||||
}
|
||||
},
|
||||
"workspace.options.stroke.dashed" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:167" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:169" ],
|
||||
"translations" : {
|
||||
"en" : "Dashed",
|
||||
"fr" : "Tiré"
|
||||
}
|
||||
},
|
||||
"workspace.options.stroke.dotted" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:166" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:168" ],
|
||||
"translations" : {
|
||||
"en" : "Dotted",
|
||||
"fr" : "Pointillé"
|
||||
}
|
||||
},
|
||||
"workspace.options.stroke.inner" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:160" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:162" ],
|
||||
"translations" : {
|
||||
"en" : "Inside"
|
||||
}
|
||||
},
|
||||
"workspace.options.stroke.mixed" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:168" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:170" ],
|
||||
"translations" : {
|
||||
"en" : "Mixed",
|
||||
"fr" : "Mixte"
|
||||
}
|
||||
},
|
||||
"workspace.options.stroke.outer" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:161" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:163" ],
|
||||
"translations" : {
|
||||
"en" : "Outside"
|
||||
}
|
||||
},
|
||||
"workspace.options.stroke.solid" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:165" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/stroke.cljs:167" ],
|
||||
"translations" : {
|
||||
"en" : "Solid",
|
||||
"fr" : "Solide"
|
||||
|
@ -1242,7 +1264,7 @@
|
|||
"unused" : true
|
||||
},
|
||||
"workspace.options.use-play-button" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:47" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs:54" ],
|
||||
"translations" : {
|
||||
"en" : "Use the play button at the header to run the prototype view."
|
||||
}
|
||||
|
@ -1366,7 +1388,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.viewport.click-to-close-path" : {
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/drawarea.cljs:360" ],
|
||||
"used-in" : [ "src/uxbox/main/ui/workspace/drawarea.cljs:357" ],
|
||||
"translations" : {
|
||||
"en" : "Click to close the path"
|
||||
}
|
||||
|
|
|
@ -591,6 +591,13 @@
|
|||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.element-set-content .custom-select.input-option {
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.element-set-content .grid-option-main {
|
||||
display: flex;
|
||||
padding: 0.5rem 0;
|
||||
|
@ -626,7 +633,6 @@
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.grid-option-main-actions {
|
||||
|
@ -661,9 +667,9 @@
|
|||
.btn-options {
|
||||
cursor: pointer;
|
||||
border: 1px solid $color-black;
|
||||
background: #1F1F1F;
|
||||
background: $color-gray-60;
|
||||
border-radius: 2px;
|
||||
color: #B1B2B5;
|
||||
color: $color-gray-20;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
flex-grow: 1;
|
||||
|
@ -673,8 +679,13 @@
|
|||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:not([disabled]):hover {
|
||||
background: $color-primary;
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.4;
|
||||
cursor: auto;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,8 @@
|
|||
:element-options
|
||||
:rules
|
||||
:dynamic-alignment
|
||||
:layouts})
|
||||
:display-grid
|
||||
:snap-grid})
|
||||
|
||||
(s/def ::options-mode #{:design :prototype})
|
||||
|
||||
|
@ -1493,13 +1494,35 @@
|
|||
;; Layouts
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defonce default-layout-params
|
||||
{:square {:size 16
|
||||
:color {:value "#59B9E2"
|
||||
:opacity 0.9}}
|
||||
|
||||
:column {:size 12
|
||||
:type :stretch
|
||||
:item-width nil
|
||||
:gutter 8
|
||||
:margin 0
|
||||
:color {:value "#DE4762"
|
||||
:opacity 0.1}}
|
||||
:row {:size 12
|
||||
:type :stretch
|
||||
:item-height nil
|
||||
:gutter 8
|
||||
:margin 0
|
||||
:color {:value "#DE4762"
|
||||
:opacity 0.1}}})
|
||||
|
||||
(defn add-frame-layout [frame-id]
|
||||
(ptk/reify ::set-frame-layout
|
||||
dwc/IBatchedChange
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pid (:current-page-id state)
|
||||
default-params {:size 16 :color {:value "#59B9E2" :opacity 0.9}}
|
||||
default-params (or
|
||||
(get-in state [:workspace-data pid :options :saved-layouts :square])
|
||||
(:square default-layout-params))
|
||||
prop-path [:workspace-data pid :objects frame-id :layouts]
|
||||
layout {:type :square
|
||||
:params default-params
|
||||
|
@ -1528,14 +1551,13 @@
|
|||
|
||||
(defn set-default-layout [type params]
|
||||
(ptk/reify ::set-default-layout
|
||||
dwc/IBatchedChange
|
||||
|
||||
;; TODO: Save into the backend
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(->
|
||||
state
|
||||
(assoc-in [:workspace-page :options :saved-layouts type] params)))))
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(rx/of (dwc/commit-changes [{:type :set-option
|
||||
:option [:saved-layouts type]
|
||||
:value params}]
|
||||
[]
|
||||
{:commit-local? true})))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Exports
|
||||
|
|
|
@ -42,12 +42,6 @@
|
|||
(def workspace-page
|
||||
(l/derived :workspace-page st/state))
|
||||
|
||||
(def workspace-page-options
|
||||
(l/derived :options workspace-page))
|
||||
|
||||
(def workspace-saved-layouts
|
||||
(l/derived :saved-layouts workspace-page-options))
|
||||
|
||||
(def workspace-page-id
|
||||
(l/derived :id workspace-page))
|
||||
|
||||
|
@ -74,6 +68,13 @@
|
|||
(get-in % [:workspace-data page-id]))
|
||||
(l/derived st/state)))
|
||||
|
||||
(def workspace-page-options
|
||||
(l/derived :options workspace-data))
|
||||
|
||||
(def workspace-saved-layouts
|
||||
(l/derived :saved-layouts workspace-page-options))
|
||||
|
||||
|
||||
(def workspace-objects
|
||||
(l/derived :objects workspace-data))
|
||||
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
|
||||
(def ^:private snap-accuracy 5)
|
||||
|
||||
(defn- remove-from-snap-points [ids-to-remove]
|
||||
(defn- remove-from-snap-points [remove-id?]
|
||||
(fn [query-result]
|
||||
(->> query-result
|
||||
(map (fn [[value data]] [value (remove (comp ids-to-remove second) data)]))
|
||||
(map (fn [[value data]] [value (remove (comp remove-id? second) data)]))
|
||||
(filter (fn [[_ data]] (not (empty? data)))))))
|
||||
|
||||
(defn- flatten-to-points
|
||||
|
@ -90,24 +90,32 @@
|
|||
|
||||
(defn closest-snap-point
|
||||
[page-id shapes layout point]
|
||||
(if (layout :dynamic-alignment)
|
||||
(let [frame-id (snap-frame-id shapes)
|
||||
filter-shapes (into #{} (map :id shapes))]
|
||||
(->> (closest-snap page-id frame-id [point] filter-shapes)
|
||||
(rx/map #(gpt/add point %))))
|
||||
(rx/of point)))
|
||||
(let [frame-id (snap-frame-id shapes)
|
||||
filter-shapes (into #{} (map :id shapes))
|
||||
filter-shapes (fn [id] (if (= id :layout)
|
||||
(or (not (contains? layout :display-grid))
|
||||
(not (contains? layout :snap-grid)))
|
||||
(or (filter-shapes id)
|
||||
(not (contains? layout :dynamic-alignment)))))]
|
||||
(->> (closest-snap page-id frame-id [point] filter-shapes)
|
||||
(rx/map #(gpt/add point %))
|
||||
(rx/map gpt/round))))
|
||||
|
||||
(defn closest-snap-move
|
||||
[page-id shapes layout movev]
|
||||
(if (layout :dynamic-alignment)
|
||||
(let [frame-id (snap-frame-id shapes)
|
||||
filter-shapes (into #{} (map :id shapes))
|
||||
shapes-points (->> shapes
|
||||
;; Unroll all the possible snap-points
|
||||
(mapcat (partial sp/shape-snap-points))
|
||||
(let [frame-id (snap-frame-id shapes)
|
||||
filter-shapes (into #{} (map :id shapes))
|
||||
filter-shapes (fn [id] (if (= id :layout)
|
||||
(or (not (contains? layout :display-grid))
|
||||
(not (contains? layout :snap-grid)))
|
||||
(or (filter-shapes id)
|
||||
(not (contains? layout :dynamic-alignment)))))
|
||||
shapes-points (->> shapes
|
||||
;; Unroll all the possible snap-points
|
||||
(mapcat (partial sp/shape-snap-points))
|
||||
|
||||
;; Move the points in the translation vector
|
||||
(map #(gpt/add % movev)))]
|
||||
(->> (closest-snap page-id frame-id shapes-points filter-shapes)
|
||||
(rx/map #(gpt/add movev %))))
|
||||
(rx/of movev)))
|
||||
;; Move the points in the translation vector
|
||||
(map #(gpt/add % movev)))]
|
||||
(->> (closest-snap page-id frame-id shapes-points filter-shapes)
|
||||
(rx/map #(gpt/add movev %))
|
||||
(rx/map gpt/round))))
|
||||
|
|
|
@ -72,42 +72,42 @@
|
|||
:on-close #(reset! show-menu? false)}
|
||||
[:ul.menu
|
||||
[:li {:on-click #(st/emit! (dw/toggle-layout-flag :rules))}
|
||||
[:span i/ruler]
|
||||
[:span
|
||||
(if (contains? layout :rules)
|
||||
(t locale "workspace.header.menu.hide-rules")
|
||||
(t locale "workspace.header.menu.show-rules"))]]
|
||||
|
||||
[:li {:on-click #(st/emit! (dw/toggle-layout-flag :grid))}
|
||||
[:span i/grid]
|
||||
[:li {:on-click #(st/emit! (dw/toggle-layout-flag :display-grid))}
|
||||
[:span
|
||||
(if (contains? layout :grid)
|
||||
(if (contains? layout :display-grid)
|
||||
(t locale "workspace.header.menu.hide-grid")
|
||||
(t locale "workspace.header.menu.show-grid"))]]
|
||||
|
||||
[:li {:on-click #(st/emit! (dw/toggle-layout-flag :snap-grid))}
|
||||
[:span
|
||||
(if (contains? layout :snap-grid)
|
||||
(t locale "workspace.header.menu.disable-snap-grid")
|
||||
(t locale "workspace.header.menu.enable-snap-grid"))]]
|
||||
|
||||
[:li {:on-click #(st/emit! (dw/toggle-layout-flag :sitemap :layers))}
|
||||
[:span i/layers]
|
||||
[:span
|
||||
(if (or (contains? layout :sitemap) (contains? layout :layers))
|
||||
(t locale "workspace.header.menu.hide-layers")
|
||||
(t locale "workspace.header.menu.show-layers"))]]
|
||||
|
||||
[:li {:on-click #(st/emit! (dw/toggle-layout-flag :colorpalette))}
|
||||
[:span i/palette]
|
||||
[:span
|
||||
(if (contains? layout :colorpalette)
|
||||
(t locale "workspace.header.menu.hide-palette")
|
||||
(t locale "workspace.header.menu.show-palette"))]]
|
||||
|
||||
[:li {:on-click #(st/emit! (dw/toggle-layout-flag :libraries))}
|
||||
[:span i/icon-set]
|
||||
[:span
|
||||
(if (contains? layout :libraries)
|
||||
(t locale "workspace.header.menu.hide-libraries")
|
||||
(t locale "workspace.header.menu.show-libraries"))]]
|
||||
|
||||
[:li {:on-click #(st/emit! (dw/toggle-layout-flag :dynamic-alignment))}
|
||||
[:span i/shape-halign-left]
|
||||
[:span
|
||||
(if (contains? layout :dynamic-alignment)
|
||||
(t locale "workspace.header.menu.disable-dynamic-alignment")
|
||||
|
|
|
@ -19,26 +19,27 @@
|
|||
(let [{:keys [color size] :as params} (-> layout :params)
|
||||
{color-value :value color-opacity :opacity} (-> layout :params :color)
|
||||
{frame-width :width frame-height :height :keys [x y]} frame]
|
||||
[:g.layout
|
||||
[:*
|
||||
(for [xs (range size frame-width size)]
|
||||
[:line {:key (str (:id frame) "-y-" xs)
|
||||
:x1 (+ x xs)
|
||||
:y1 y
|
||||
:x2 (+ x xs)
|
||||
:y2 (+ y frame-height)
|
||||
:style {:stroke color-value
|
||||
:stroke-opacity color-opacity
|
||||
:stroke-width (str (/ 1 zoom))}}])
|
||||
(for [ys (range size frame-height size)]
|
||||
[:line {:key (str (:id frame) "-x-" ys)
|
||||
:x1 x
|
||||
:y1 (+ y ys)
|
||||
:x2 (+ x frame-width)
|
||||
:y2 (+ y ys)
|
||||
:style {:stroke color-value
|
||||
:stroke-opacity color-opacity
|
||||
:stroke-width (str (/ 1 zoom))}}])]]))
|
||||
(when (> size 0)
|
||||
[:g.layout
|
||||
[:*
|
||||
(for [xs (range size frame-width size)]
|
||||
[:line {:key (str (:id frame) "-y-" xs)
|
||||
:x1 (+ x xs)
|
||||
:y1 y
|
||||
:x2 (+ x xs)
|
||||
:y2 (+ y frame-height)
|
||||
:style {:stroke color-value
|
||||
:stroke-opacity color-opacity
|
||||
:stroke-width (str (/ 1 zoom))}}])
|
||||
(for [ys (range size frame-height size)]
|
||||
[:line {:key (str (:id frame) "-x-" ys)
|
||||
:x1 x
|
||||
:y1 (+ y ys)
|
||||
:x2 (+ x frame-width)
|
||||
:y2 (+ y ys)
|
||||
:style {:stroke color-value
|
||||
:stroke-opacity color-opacity
|
||||
:stroke-width (str (/ 1 zoom))}}])]])))
|
||||
|
||||
(mf/defc flex-layout [{:keys [key frame zoom layout]}]
|
||||
(let [{color-value :value color-opacity :opacity} (-> layout :params :color)]
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
[:div.advanced-options {}
|
||||
children]]))
|
||||
|
||||
(mf/defc layout-options [{:keys [layout default-layout-params on-change on-remove]}]
|
||||
(mf/defc layout-options [{:keys [layout default-layout-params on-change on-remove on-save-layout]}]
|
||||
(let [state (mf/use-state {:show-advanced-options false
|
||||
:changes {}})
|
||||
{:keys [type display params] :as layout} (d/deep-merge layout (:changes @state))
|
||||
|
@ -68,7 +68,15 @@
|
|||
(fn [event]
|
||||
(let [change-fn (apply handle-change keys)]
|
||||
(-> event dom/get-target dom/get-value parse-integer change-fn))))
|
||||
]
|
||||
|
||||
handle-use-default (fn []
|
||||
(emit-changes! #(hash-map :params ((:type layout) default-layout-params))))
|
||||
handle-set-as-default (fn []
|
||||
(let [current-layout (d/deep-merge layout (-> @state :changes))]
|
||||
(on-save-layout current-layout)))
|
||||
|
||||
is-default (= (->> @state :changes (d/deep-merge layout) :params)
|
||||
(->> layout :type default-layout-params))]
|
||||
|
||||
[:div.grid-option
|
||||
[:div.grid-option-main
|
||||
|
@ -85,7 +93,7 @@
|
|||
(if (= type :square)
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:min "0"
|
||||
:min "1"
|
||||
:no-validate true
|
||||
:value (:size params)
|
||||
:on-change (handle-change-event :params :size)}]]
|
||||
|
@ -102,6 +110,8 @@
|
|||
:on-close toggle-advanced-options}
|
||||
(when (= :square type)
|
||||
[:& input-row {:label "Size"
|
||||
:class "pixels"
|
||||
:min 1
|
||||
:value (:size params)
|
||||
:on-change (handle-change :params :size)}])
|
||||
|
||||
|
@ -128,52 +138,38 @@
|
|||
|
||||
(when (= :row type)
|
||||
[:& input-row {:label "Height"
|
||||
:class "pixels"
|
||||
:value (or (:item-height params) "")
|
||||
:on-change (handle-change :params :item-height)}])
|
||||
|
||||
(when (= :column type)
|
||||
[:& input-row {:label "Width"
|
||||
:class "pixels"
|
||||
:value (or (:item-width params) "")
|
||||
:on-change (handle-change :params :item-width)}])
|
||||
|
||||
(when (#{:row :column} type)
|
||||
[:*
|
||||
[:& input-row {:label "Gutter"
|
||||
:class "pixels"
|
||||
:value (:gutter params)
|
||||
:on-change (handle-change :params :gutter)}]
|
||||
[:& input-row {:label "Margin"
|
||||
:class "pixels"
|
||||
:value (:margin params)
|
||||
:on-change (handle-change :params :margin)}]])
|
||||
|
||||
[:& color-row {:value (:color params)
|
||||
:on-change (handle-change :params :color)}]
|
||||
[:div.row-flex
|
||||
[:button.btn-options "Use default"]
|
||||
[:button.btn-options "Set as default"]]]]))
|
||||
|
||||
(defonce ^:private default-layout-params
|
||||
{:square {:size 16
|
||||
:color {:value "#59B9E2"
|
||||
:opacity 0.9}}
|
||||
|
||||
:column {:size 12
|
||||
:type :stretch
|
||||
:item-width nil
|
||||
:gutter 8
|
||||
:margin 0
|
||||
:color {:value "#DE4762"
|
||||
:opacity 0.1}}
|
||||
:row {:size 12
|
||||
:type :stretch
|
||||
:item-height nil
|
||||
:gutter 8
|
||||
:margin 0
|
||||
:color {:value "#DE4762"
|
||||
:opacity 0.1}}})
|
||||
[:button.btn-options {:disabled is-default
|
||||
:on-click handle-use-default} "Use default"]
|
||||
[:button.btn-options {:disabled is-default
|
||||
:on-click handle-set-as-default} "Set as default"]]]]))
|
||||
|
||||
(mf/defc frame-layouts [{:keys [shape]}]
|
||||
(let [id (:id shape)
|
||||
default-layout-params (merge default-layout-params (mf/deref refs/workspace-saved-layouts))
|
||||
default-layout-params (merge dw/default-layout-params (mf/deref refs/workspace-saved-layouts))
|
||||
handle-create-layout #(st/emit! (dw/add-frame-layout id))
|
||||
handle-remove-layout (fn [index] #(st/emit! (dw/remove-frame-layout id index)))
|
||||
handle-edit-layout (fn [index] #(st/emit! (dw/set-frame-layout id index %)))
|
||||
|
|
|
@ -10,95 +10,14 @@
|
|||
(ns uxbox.main.ui.workspace.sidebar.options.page
|
||||
"Page options menu entries."
|
||||
(:require
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]
|
||||
[okulary.core :as l]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.main.ui.icons :as i]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.modal :as modal]
|
||||
[uxbox.main.ui.workspace.colorpicker :refer [colorpicker-modal]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.i18n :refer [tr]]))
|
||||
|
||||
(def default-options
|
||||
"Default data for page metadata."
|
||||
{:grid-x 10
|
||||
:grid-y 10
|
||||
:grid-color "#cccccc"})
|
||||
[uxbox.main.refs :as refs]))
|
||||
|
||||
(def options-iref
|
||||
(l/derived :options refs/workspace-data))
|
||||
|
||||
(mf/defc grid-options
|
||||
{:wrap [mf/memo]}
|
||||
[props]
|
||||
(let [options (->> (mf/deref options-iref)
|
||||
(merge default-options))
|
||||
on-x-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-integer 0))]
|
||||
(st/emit! (dw/update-options {:grid-x value}))))
|
||||
|
||||
on-y-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-integer 0))]
|
||||
(st/emit! (dw/update-options {:grid-y value}))))
|
||||
|
||||
change-color
|
||||
(fn [color]
|
||||
(st/emit! (dw/update-options {:grid-color color})))
|
||||
|
||||
on-color-input-change
|
||||
(fn [event]
|
||||
(let [input (dom/get-target event)
|
||||
value (dom/get-value input)]
|
||||
(when (dom/valid? input)
|
||||
(change-color value))))
|
||||
|
||||
show-color-picker
|
||||
(fn [event]
|
||||
(let [x (.-clientX event)
|
||||
y (.-clientY event)
|
||||
props {:x x :y y
|
||||
:transparent? true
|
||||
:default "#cccccc"
|
||||
:attr :grid-color
|
||||
:on-change change-color}]
|
||||
(modal/show! colorpicker-modal props)))]
|
||||
[:div.element-set
|
||||
[:div.element-set-title (tr "workspace.options.grid-options")]
|
||||
[:div.element-set-content
|
||||
[:div.row-flex
|
||||
[:span.element-set-subtitle (tr "workspace.options.size")]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:value (:grid-x options)
|
||||
:on-change on-x-change}]]
|
||||
[:div.input-element.pixels
|
||||
[:input.input-text {:type "number"
|
||||
:value (:grid-y options)
|
||||
:on-change on-y-change}]]]
|
||||
[:div.row-flex.color-data
|
||||
[:span.element-set-subtitle (tr "workspace.options.color")]
|
||||
[:span.color-th {:style {:background-color (:grid-color options)}
|
||||
:on-click show-color-picker}]
|
||||
[:div.color-info
|
||||
[:input {:default-value (:grid-color options)
|
||||
:ref (fn [el]
|
||||
(when el
|
||||
(set! (.-value el) (:grid-color options))))
|
||||
:pattern "^#(?:[0-9a-fA-F]{3}){1,2}$"
|
||||
:on-change on-color-input-change}]]]]]))
|
||||
|
||||
(mf/defc options
|
||||
[{:keys [page] :as props}]
|
||||
[:div
|
||||
[:& grid-options {:page page}]])
|
||||
;; TODO: Define properties for page
|
||||
[{:keys [page] :as props}])
|
||||
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
(/ 100)))
|
||||
|
||||
(mf/defc color-row [{:keys [value on-change]}]
|
||||
(let [state (mf/use-state value)
|
||||
(let [value (or value {:value "#FFFFFF" :opacity 1})
|
||||
state (mf/use-state value)
|
||||
change-color (fn [color]
|
||||
(let [update-color (fn [state] (assoc state :value color))]
|
||||
(swap! state update-color)
|
||||
|
@ -65,6 +66,10 @@
|
|||
string->opacity
|
||||
change-opacity))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps value)
|
||||
#(reset! state value))
|
||||
|
||||
[:div.row-flex.color-data
|
||||
[:span.color-th
|
||||
{:style {:background-color (-> @state :value)}
|
||||
|
@ -88,3 +93,4 @@
|
|||
:value (-> @state :opacity opacity->string)
|
||||
:step "1"
|
||||
:on-change handle-opacity-change}]]))
|
||||
|
||||
|
|
|
@ -14,17 +14,19 @@
|
|||
[uxbox.main.ui.components.select :refer [select]]
|
||||
[uxbox.util.dom :as dom]))
|
||||
|
||||
(mf/defc input-row [{:keys [label options value on-change]}]
|
||||
[:div.row-flex.input-row
|
||||
[:span.element-set-subtitle label]
|
||||
[:div.input-element
|
||||
(if options
|
||||
[:& select {:default-value value
|
||||
:class "input-option"
|
||||
:options options
|
||||
:on-change on-change}]
|
||||
[:input.input-text
|
||||
{:placeholder label
|
||||
:type "number"
|
||||
:on-change #(-> % dom/get-target dom/get-value d/parse-integer on-change)
|
||||
:value value}])]])
|
||||
(mf/defc input-row [{:keys [label options value class min max on-change]}]
|
||||
(let [handle-change (fn [value] (when (and (or (not min) (>= value min)) (or (not max) (<= value max)))
|
||||
(on-change value)))]
|
||||
[:div.row-flex.input-row
|
||||
[:span.element-set-subtitle label]
|
||||
[:div.input-element {:class class}
|
||||
(if options
|
||||
[:& select {:default-value value
|
||||
:class "input-option"
|
||||
:options options
|
||||
:on-change on-change}]
|
||||
[:input.input-text
|
||||
{:placeholder label
|
||||
:type "number"
|
||||
:on-change #(-> % dom/get-target dom/get-value d/parse-integer handle-change)
|
||||
:value value}])]]))
|
||||
|
|
|
@ -80,12 +80,17 @@
|
|||
:point point
|
||||
:zoom zoom}])]))]))
|
||||
|
||||
(mf/defc snap-feedback [{:keys []}]
|
||||
(mf/defc snap-feedback [{:keys [layout]}]
|
||||
(let [page-id (mf/deref refs/workspace-page-id)
|
||||
selected (mf/deref refs/selected-shapes)
|
||||
selected-shapes (mf/deref (refs/objects-by-id selected))
|
||||
drawing (mf/deref refs/current-drawing-shape)
|
||||
filter-shapes (mf/deref refs/selected-shapes-with-children)
|
||||
filter-shapes (fn [id] (if (= id :layout)
|
||||
(or (not (contains? layout :display-grid))
|
||||
(not (contains? layout :snap-grid)))
|
||||
(or (filter-shapes id)
|
||||
(not (contains? layout :dynamic-alignment)))))
|
||||
current-transform (mf/deref refs/current-transform)
|
||||
snap-data (mf/deref refs/workspace-snap-data)
|
||||
shapes (if drawing [drawing] selected-shapes)
|
||||
|
|
|
@ -386,10 +386,10 @@
|
|||
:zoom zoom
|
||||
:modifiers (:modifiers local)}])
|
||||
|
||||
(when (contains? layout :layouts)
|
||||
(when (contains? layout :display-grid)
|
||||
[:& layout-display {:zoom zoom}])
|
||||
|
||||
[:& snap-feedback]
|
||||
[:& snap-feedback {:layout layout}]
|
||||
|
||||
(when tooltip
|
||||
[:& cursor-tooltip {:zoom zoom :tooltip tooltip}])]
|
||||
|
|
|
@ -74,11 +74,12 @@
|
|||
(case type
|
||||
:square (let [{:keys [x y width height]} shape
|
||||
size (-> params :size)]
|
||||
(if (= coord :x)
|
||||
(mapcat #(vector (gpt/point (+ x %) y)
|
||||
(gpt/point (+ x %) (+ y height))) (range size width size))
|
||||
(mapcat #(vector (gpt/point x (+ y %))
|
||||
(gpt/point (+ x width) (+ y %))) (range size height size))))
|
||||
(when (> size 0)
|
||||
(if (= coord :x)
|
||||
(mapcat #(vector (gpt/point (+ x %) y)
|
||||
(gpt/point (+ x %) (+ y height))) (range size width size))
|
||||
(mapcat #(vector (gpt/point x (+ y %))
|
||||
(gpt/point (+ x width) (+ y %))) (range size height size)))))
|
||||
:column (when (= coord :x) (->> (layout-rects shape layout)
|
||||
(mapcat layout-rect-points)))
|
||||
|
||||
|
|
|
@ -151,11 +151,12 @@
|
|||
|
||||
(defn round
|
||||
"Change the precision of the point coordinates."
|
||||
[{:keys [x y] :as p} decimanls]
|
||||
(assert (point? p))
|
||||
(assert (number? decimanls))
|
||||
(Point. (mth/precision x decimanls)
|
||||
(mth/precision y decimanls)))
|
||||
([point] (round point 0))
|
||||
([{:keys [x y] :as p} decimanls]
|
||||
(assert (point? p))
|
||||
(assert (number? decimanls))
|
||||
(Point. (mth/precision x decimanls)
|
||||
(mth/precision y decimanls))))
|
||||
|
||||
(defn transform
|
||||
"Transform a point applying a matrix transfomation."
|
||||
|
|
Loading…
Add table
Reference in a new issue