mirror of
https://github.com/penpot/penpot.git
synced 2025-07-26 15:37:26 +02:00
✨ Add grid layout options to context
This commit is contained in:
parent
9243ba937d
commit
fde0bcfd3e
4 changed files with 245 additions and 40 deletions
162
frontend/src/app/plugins/grid.cljs
Normal file
162
frontend/src/app/plugins/grid.cljs
Normal file
|
@ -0,0 +1,162 @@
|
|||
;; 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.plugins.grid
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.record :as crc]
|
||||
[app.common.spec :as us]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.utils :as utils :refer [get-data get-state]]))
|
||||
|
||||
(defn- make-tracks
|
||||
[tracks]
|
||||
(.freeze
|
||||
js/Object
|
||||
(apply array (->> tracks (map utils/to-js)))))
|
||||
|
||||
(deftype GridLayout [_data]
|
||||
Object
|
||||
|
||||
(addRow
|
||||
[self type value]
|
||||
(let [id (get-data self :id)
|
||||
type (keyword type)]
|
||||
(st/emit! (dwsl/add-layout-track #{id} :row {:type type :value value}))))
|
||||
|
||||
(addRowAtIndex
|
||||
[self type value index]
|
||||
(let [id (get-data self :id)
|
||||
type (keyword type)]
|
||||
(st/emit! (dwsl/add-layout-track #{id} :row {:type type :value value} index))))
|
||||
|
||||
(addColumn
|
||||
[self type value]
|
||||
(let [id (get-data self :id)
|
||||
type (keyword type)]
|
||||
(st/emit! (dwsl/add-layout-track #{id} :column {:type type :value value}))))
|
||||
|
||||
(addColumnAtIndex
|
||||
[self type value index]
|
||||
(let [id (get-data self :id)
|
||||
type (keyword type)]
|
||||
(st/emit! (dwsl/add-layout-track #{id} :column {:type type :value value} index))))
|
||||
|
||||
(removeRow
|
||||
[self index]
|
||||
(let [id (get-data self :id)]
|
||||
(st/emit! (dwsl/remove-layout-track #{id} :row index))))
|
||||
|
||||
(removeColumn
|
||||
[self index]
|
||||
(let [id (get-data self :id)]
|
||||
(st/emit! (dwsl/remove-layout-track #{id} :column index))))
|
||||
|
||||
(setColumn
|
||||
[self index type value]
|
||||
(let [id (get-data self :id)
|
||||
type (keyword type)]
|
||||
(st/emit! (dwsl/change-layout-track #{id} :column index (d/without-nils {:type type :value value})))))
|
||||
|
||||
(setRow
|
||||
[self index type value]
|
||||
(let [id (get-data self :id)
|
||||
type (keyword type)]
|
||||
(st/emit! (dwsl/change-layout-track #{id} :row index (d/without-nils {:type type :value value})))))
|
||||
|
||||
(remove
|
||||
[self]
|
||||
(let [id (get-data self :id)]
|
||||
(st/emit! (dwsl/remove-layout #{id})))))
|
||||
|
||||
(defn grid-layout-proxy
|
||||
[data]
|
||||
(-> (GridLayout. data)
|
||||
(crc/add-properties!
|
||||
{:name "dir"
|
||||
:get #(get-state % :layout-grid-dir d/name)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (get-data self :id)
|
||||
value (keyword value)]
|
||||
(when (contains? ctl/grid-direction-types value)
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-grid-dir value})))))}
|
||||
|
||||
{:name "rows"
|
||||
:get #(get-state % :layout-grid-rows make-tracks)}
|
||||
|
||||
{:name "columns"
|
||||
:get #(get-state % :layout-grid-columns make-tracks)}
|
||||
|
||||
{:name "alignItems"
|
||||
:get #(get-state % :layout-align-items d/name)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (get-data self :id)
|
||||
value (keyword value)]
|
||||
(when (contains? ctl/align-items-types value)
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-align-items value})))))}
|
||||
|
||||
{:name "alignContent"
|
||||
:get #(get-state % :layout-align-content d/name)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (get-data self :id)
|
||||
value (keyword value)]
|
||||
(when (contains? ctl/align-content-types value)
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-align-content value})))))}
|
||||
|
||||
{:name "justifyItems"
|
||||
:get #(get-state % :layout-justify-items d/name)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (get-data self :id)
|
||||
value (keyword value)]
|
||||
(when (contains? ctl/justify-items-types value)
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-justify-items value})))))}
|
||||
|
||||
{:name "justifyContent"
|
||||
:get #(get-state % :layout-justify-content d/name)
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (get-data self :id)
|
||||
value (keyword value)]
|
||||
(when (contains? ctl/justify-content-types value)
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-justify-content value})))))}
|
||||
|
||||
{:name "rowGap"
|
||||
:get #(:row-gap (get-state % :layout-gap))
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (get-data self :id)]
|
||||
(when (us/safe-int? value)
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:row-gap value}})))))}
|
||||
|
||||
{:name "columnGap"
|
||||
:get #(:column-gap (get-state % :layout-gap))
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (get-data self :id)]
|
||||
(when (us/safe-int? value)
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-gap {:column-gap value}})))))}
|
||||
|
||||
{:name "verticalPadding"
|
||||
:get #(:p1 (get-state % :layout-padding))
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (get-data self :id)]
|
||||
(when (us/safe-int? value)
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p1 value :p3 value}})))))}
|
||||
|
||||
{:name "horizontalPadding"
|
||||
:get #(:p2 (get-state % :layout-padding))
|
||||
:set
|
||||
(fn [self value]
|
||||
(let [id (get-data self :id)]
|
||||
(when (us/safe-int? value)
|
||||
(st/emit! (dwsl/update-layout #{id} {:layout-padding {:p2 value :p4 value}})))))})))
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.plugins.shape
|
||||
"RPC for plugins runtime."
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.record :as crc]
|
||||
|
@ -16,9 +15,11 @@
|
|||
[app.main.data.workspace :as udw]
|
||||
[app.main.data.workspace.changes :as dwc]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.data.workspace.shape-layout :as dwsl]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.store :as st]
|
||||
[app.plugins.utils :as utils :refer [get-data get-data-fn]]
|
||||
[app.plugins.grid :as grid]
|
||||
[app.plugins.utils :as utils :refer [get-data get-data-fn get-state]]
|
||||
[app.util.object :as obj]))
|
||||
|
||||
(declare data->shape-proxy)
|
||||
|
@ -40,23 +41,8 @@
|
|||
(let [page-id (:current-page-id @st/state)]
|
||||
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects shape-id])))
|
||||
|
||||
(defn- get-state
|
||||
([self attr]
|
||||
(let [id (get-data self :id)
|
||||
page-id (d/nilv (get-data self :page-id) (:current-page-id @st/state))]
|
||||
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects id attr])))
|
||||
([self attr mapfn]
|
||||
(-> (get-state self attr)
|
||||
(mapfn))))
|
||||
|
||||
(deftype ShapeProxy [^:mutable #_:clj-kondo/ignore _data]
|
||||
(deftype ShapeProxy [#_:clj-kondo/ignore _data]
|
||||
Object
|
||||
(getChildren
|
||||
[self]
|
||||
(apply array (->> (get-state self :shapes)
|
||||
(map locate-shape)
|
||||
(map data->shape-proxy))))
|
||||
|
||||
(resize
|
||||
[self width height]
|
||||
(let [id (get-data self :id)]
|
||||
|
@ -76,6 +62,13 @@
|
|||
(let [id (get-data self :id)]
|
||||
(st/emit! (dwsh/delete-shapes #{id}))))
|
||||
|
||||
;; Only for frames + groups + booleans
|
||||
(getChildren
|
||||
[self]
|
||||
(apply array (->> (get-state self :shapes)
|
||||
(map locate-shape)
|
||||
(map data->shape-proxy))))
|
||||
|
||||
(appendChild [self child]
|
||||
(let [parent-id (get-data self :id)
|
||||
child-id (uuid/uuid (obj/get child "id"))]
|
||||
|
@ -84,7 +77,16 @@
|
|||
(insertChild [self index child]
|
||||
(let [parent-id (get-data self :id)
|
||||
child-id (uuid/uuid (obj/get child "id"))]
|
||||
(st/emit! (udw/relocate-shapes #{child-id} parent-id index)))))
|
||||
(st/emit! (udw/relocate-shapes #{child-id} parent-id index))))
|
||||
|
||||
;; Only for frames
|
||||
(addFlexLayout [self]
|
||||
(let [id (get-data self :id)]
|
||||
(st/emit! (dwsl/create-layout-from-id id :flex :from-frame? true :calculate-params? false))))
|
||||
|
||||
(addGridLayout [self]
|
||||
(let [id (get-data self :id)]
|
||||
(st/emit! (dwsl/create-layout-from-id id :grid :from-frame? true :calculate-params? false)))))
|
||||
|
||||
(crc/define-properties!
|
||||
ShapeProxy
|
||||
|
@ -206,6 +208,32 @@
|
|||
{:name "children"
|
||||
:get #(.getChildren ^js %)}))
|
||||
|
||||
(cond-> (not (or (cfh/frame-shape? data) (cfh/group-shape? data) (cfh/svg-raw-shape? data) (cfh/bool-shape? data)))
|
||||
(-> (obj/unset! "appendChild")
|
||||
(obj/unset! "insertChild")
|
||||
(obj/unset! "getChildren")))
|
||||
|
||||
(cond-> (cfh/frame-shape? data)
|
||||
(-> (crc/add-properties!
|
||||
{:name "grid"
|
||||
:get
|
||||
(fn [self]
|
||||
(let [layout (get-state self :layout)]
|
||||
(when (= :grid layout)
|
||||
(grid/grid-layout-proxy data))))})
|
||||
|
||||
#_(crc/add-properties!
|
||||
{:name "flex"
|
||||
:get
|
||||
(fn [self]
|
||||
(let [layout (get-state self :layout)]
|
||||
(when (= :flex layout)
|
||||
(flex-layout-proxy data))))})))
|
||||
|
||||
(cond-> (not (cfh/frame-shape? data))
|
||||
(-> (obj/unset! "addGridLayout")
|
||||
(obj/unset! "addFlexLayout")))
|
||||
|
||||
(cond-> (cfh/text-shape? data)
|
||||
(crc/add-properties!
|
||||
{:name "characters"
|
||||
|
@ -213,4 +241,3 @@
|
|||
:set (fn [self value]
|
||||
(let [id (get-data self :id)]
|
||||
(st/emit! (dwc/update-shapes [id] #(txt/change-text % value)))))}))))
|
||||
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
(ns app.plugins.utils
|
||||
"RPC for plugins runtime."
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.store :as st]
|
||||
[app.util.object :as obj]
|
||||
[cuerdas.core :as str]
|
||||
[promesa.core :as p]))
|
||||
|
@ -32,22 +34,34 @@
|
|||
(fn [self]
|
||||
(get-data self attr transform-fn))))
|
||||
|
||||
(defn get-state
|
||||
([self attr]
|
||||
(let [id (get-data self :id)
|
||||
page-id (d/nilv (get-data self :page-id) (:current-page-id @st/state))]
|
||||
(dm/get-in @st/state [:workspace-data :pages-index page-id :objects id attr])))
|
||||
([self attr mapfn]
|
||||
(-> (get-state self attr)
|
||||
(mapfn))))
|
||||
|
||||
(defn from-js
|
||||
"Converts the object back to js"
|
||||
[obj]
|
||||
(let [ret (js->clj obj {:keyword-fn (fn [k] (str/camel (name k)))})]
|
||||
(reduce-kv
|
||||
(fn [m k v]
|
||||
(let [v (cond (map? v)
|
||||
(from-js v)
|
||||
([obj]
|
||||
(from-js obj identity))
|
||||
([obj vfn]
|
||||
(let [ret (js->clj obj {:keyword-fn (fn [k] (str/camel (name k)))})]
|
||||
(reduce-kv
|
||||
(fn [m k v]
|
||||
(let [k (keyword (str/kebab k))
|
||||
v (cond (map? v)
|
||||
(from-js v)
|
||||
|
||||
(and (string? v) (re-matches us/uuid-rx v))
|
||||
(uuid/uuid v)
|
||||
(and (string? v) (re-matches us/uuid-rx v))
|
||||
(uuid/uuid v)
|
||||
|
||||
:else v)]
|
||||
(assoc m (keyword (str/kebab k)) v)))
|
||||
{}
|
||||
ret)))
|
||||
:else (vfn k v))]
|
||||
(assoc m k v)))
|
||||
{}
|
||||
ret))))
|
||||
|
||||
(defn to-js
|
||||
"Converts to javascript an camelize the keys"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue