mirror of
https://github.com/penpot/penpot.git
synced 2025-02-25 00:06:09 -05:00
✨ Multispan cells auto sizing
This commit is contained in:
parent
0eff2e8887
commit
cdebf245e3
6 changed files with 316 additions and 76 deletions
|
@ -51,6 +51,7 @@
|
||||||
|
|
||||||
(ns app.common.geom.shapes.grid-layout.layout-data
|
(ns app.common.geom.shapes.grid-layout.layout-data
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes.points :as gpo]
|
[app.common.geom.shapes.points :as gpo]
|
||||||
[app.common.types.shape.layout :as ctl]))
|
[app.common.types.shape.layout :as ctl]))
|
||||||
|
@ -134,6 +135,137 @@
|
||||||
(= :auto type)
|
(= :auto type)
|
||||||
(assoc :size (min (+ size add-size) max-size)))))))
|
(assoc :size (min (+ size add-size) max-size)))))))
|
||||||
|
|
||||||
|
(defn size-to-allocate
|
||||||
|
[type parent [child-bounds _] cell]
|
||||||
|
(let [[row-gap column-gap] (ctl/gaps parent)
|
||||||
|
[sfn gap prop-span]
|
||||||
|
(if (= type :column)
|
||||||
|
[gpo/width-points column-gap :column-span ]
|
||||||
|
[gpo/height-points row-gap :row-span ])
|
||||||
|
span (get cell prop-span)]
|
||||||
|
(- (sfn child-bounds) (* gap (dec span)))))
|
||||||
|
|
||||||
|
(defn allocate-size
|
||||||
|
[allocations indexed-tracks to-allocate]
|
||||||
|
(if (empty? indexed-tracks)
|
||||||
|
allocations
|
||||||
|
(let [[idx track] (first indexed-tracks)
|
||||||
|
old-allocated (get allocations idx 0.01)
|
||||||
|
auto-track? (= :auto (:type track))
|
||||||
|
|
||||||
|
allocated (if auto-track?
|
||||||
|
(max old-allocated
|
||||||
|
(/ to-allocate (count indexed-tracks))
|
||||||
|
(:size track))
|
||||||
|
(:size track))]
|
||||||
|
(recur (cond-> allocations auto-track?
|
||||||
|
(assoc idx allocated))
|
||||||
|
(rest indexed-tracks) (- to-allocate allocated)))))
|
||||||
|
|
||||||
|
(defn allocate-flex
|
||||||
|
[allocations indexed-tracks to-allocate fr-value]
|
||||||
|
(if (empty? indexed-tracks)
|
||||||
|
allocations
|
||||||
|
(let [[idx track] (first indexed-tracks)
|
||||||
|
old-allocated (get allocations idx 0.01)
|
||||||
|
|
||||||
|
auto-track? (= :auto (:type track))
|
||||||
|
flex-track? (= :flex (:type track))
|
||||||
|
|
||||||
|
fr (if flex-track? (:value track) 0)
|
||||||
|
|
||||||
|
target-allocation (* fr-value fr)
|
||||||
|
|
||||||
|
allocated (if (or auto-track? flex-track?)
|
||||||
|
(max target-allocation
|
||||||
|
old-allocated
|
||||||
|
(:size track))
|
||||||
|
(:size track))]
|
||||||
|
(recur (cond-> allocations (or flex-track? auto-track?)
|
||||||
|
(assoc idx allocated))
|
||||||
|
(rest indexed-tracks)
|
||||||
|
(- to-allocate allocated)
|
||||||
|
fr-value))))
|
||||||
|
|
||||||
|
(defn set-auto-multi-span
|
||||||
|
[parent track-list children-map shape-cells type]
|
||||||
|
|
||||||
|
(let [[prop prop-span]
|
||||||
|
(if (= type :column)
|
||||||
|
[:column :column-span]
|
||||||
|
[:row :row-span])
|
||||||
|
|
||||||
|
;; First calculate allocation without applying so we can modify them on the following tracks
|
||||||
|
allocate-auto-tracks
|
||||||
|
(->> shape-cells
|
||||||
|
(vals)
|
||||||
|
(filter #(> (get % prop-span) 1))
|
||||||
|
(sort-by prop-span -)
|
||||||
|
(reduce
|
||||||
|
(fn [alloc cell]
|
||||||
|
(let [shape-id (first (:shapes cell))
|
||||||
|
from-idx (dec (get cell prop))
|
||||||
|
to-idx (+ (dec (get cell prop)) (get cell prop-span))
|
||||||
|
indexed-tracks (subvec (d/enumerate track-list) from-idx to-idx)
|
||||||
|
has-flex? (->> indexed-tracks (d/seek #(= :flex (:type (second %)))) some?)
|
||||||
|
to-allocate (size-to-allocate type parent (get children-map shape-id) cell)]
|
||||||
|
(cond-> alloc
|
||||||
|
;; skip cells with flex tracks
|
||||||
|
(and (not has-flex?) (some? to-allocate))
|
||||||
|
(allocate-size indexed-tracks to-allocate))))
|
||||||
|
{}))
|
||||||
|
|
||||||
|
;; Apply the allocations to the tracks
|
||||||
|
track-list
|
||||||
|
(into []
|
||||||
|
(map-indexed #(update %2 :size max (get allocate-auto-tracks %1)))
|
||||||
|
track-list)]
|
||||||
|
track-list))
|
||||||
|
|
||||||
|
(defn set-flex-multi-span
|
||||||
|
[parent track-list children-map shape-cells type]
|
||||||
|
|
||||||
|
(let [[prop prop-span]
|
||||||
|
(if (= type :column)
|
||||||
|
[:column :column-span]
|
||||||
|
[:row :row-span])
|
||||||
|
|
||||||
|
;; First calculate allocation without applying so we can modify them on the following tracks
|
||||||
|
allocate-fr-tracks
|
||||||
|
(->> shape-cells
|
||||||
|
(vals)
|
||||||
|
(filter #(> (get % prop-span) 1))
|
||||||
|
(sort-by prop-span -)
|
||||||
|
(reduce
|
||||||
|
(fn [alloc cell]
|
||||||
|
(let [shape-id (first (:shapes cell))
|
||||||
|
from-idx (dec (get cell prop))
|
||||||
|
to-idx (+ (dec (get cell prop)) (get cell prop-span))
|
||||||
|
indexed-tracks (subvec (d/enumerate track-list) from-idx to-idx)
|
||||||
|
has-flex? (->> indexed-tracks (d/seek #(= :auto (:type (second %)))) some?)
|
||||||
|
total-frs (->> indexed-tracks (reduce (fn [tot [_ {:keys [type value]}]]
|
||||||
|
(cond-> tot
|
||||||
|
(= type :flex)
|
||||||
|
(+ value)))
|
||||||
|
0))
|
||||||
|
|
||||||
|
|
||||||
|
to-allocate (size-to-allocate type parent (get children-map shape-id) cell)
|
||||||
|
fr-value (when (some? to-allocate) (/ to-allocate total-frs))]
|
||||||
|
(cond-> alloc
|
||||||
|
;; skip cells with no flex tracks
|
||||||
|
(and has-flex? (some? to-allocate))
|
||||||
|
(allocate-flex indexed-tracks to-allocate fr-value))))
|
||||||
|
{}))
|
||||||
|
|
||||||
|
;; Apply the allocations to the tracks
|
||||||
|
track-list
|
||||||
|
(into []
|
||||||
|
(map-indexed #(update %2 :size max (get allocate-fr-tracks %1)))
|
||||||
|
track-list)]
|
||||||
|
track-list))
|
||||||
|
|
||||||
|
|
||||||
(defn calc-layout-data
|
(defn calc-layout-data
|
||||||
[parent children transformed-parent-bounds]
|
[parent children transformed-parent-bounds]
|
||||||
|
|
||||||
|
@ -155,6 +287,10 @@
|
||||||
(->> (:shapes cell) (map #(vector % cell)))))
|
(->> (:shapes cell) (map #(vector % cell)))))
|
||||||
(:layout-grid-cells parent))
|
(:layout-grid-cells parent))
|
||||||
|
|
||||||
|
children-map
|
||||||
|
(into {}
|
||||||
|
(map #(vector (:id (second %)) %))
|
||||||
|
children)
|
||||||
|
|
||||||
;; Initialize tracks
|
;; Initialize tracks
|
||||||
column-tracks
|
column-tracks
|
||||||
|
@ -171,8 +307,8 @@
|
||||||
|
|
||||||
|
|
||||||
;; Adjust multi-spaned cells with no flex columns
|
;; Adjust multi-spaned cells with no flex columns
|
||||||
;; TODO
|
column-tracks (set-auto-multi-span parent column-tracks children-map shape-cells :column)
|
||||||
|
row-tracks (set-auto-multi-span parent row-tracks children-map shape-cells :row)
|
||||||
|
|
||||||
;; Calculate the `fr` unit and adjust the size
|
;; Calculate the `fr` unit and adjust the size
|
||||||
column-total-size (tracks-total-size column-tracks)
|
column-total-size (tracks-total-size column-tracks)
|
||||||
|
@ -184,6 +320,12 @@
|
||||||
column-frs (tracks-total-frs column-tracks)
|
column-frs (tracks-total-frs column-tracks)
|
||||||
row-frs (tracks-total-frs row-tracks)
|
row-frs (tracks-total-frs row-tracks)
|
||||||
|
|
||||||
|
;; Assign minimum size to the multi-span flex tracks. We do this after calculating
|
||||||
|
;; the fr size because will affect only the minimum. The maximum will be set by the
|
||||||
|
;; fracion
|
||||||
|
column-tracks (set-flex-multi-span parent column-tracks children-map shape-cells :column)
|
||||||
|
row-tracks (set-flex-multi-span parent row-tracks children-map shape-cells :row)
|
||||||
|
|
||||||
;; Once auto sizes have been calculated we get calculate the `fr` unit with the remainining size and adjust the size
|
;; Once auto sizes have been calculated we get calculate the `fr` unit with the remainining size and adjust the size
|
||||||
free-column-space (- bound-width (+ column-total-size column-total-gap))
|
free-column-space (- bound-width (+ column-total-size column-total-gap))
|
||||||
free-row-space (- bound-height (+ row-total-size row-total-gap))
|
free-row-space (- bound-height (+ row-total-size row-total-gap))
|
||||||
|
@ -235,8 +377,7 @@
|
||||||
[(conj tracks (assoc track :start-p start-p))
|
[(conj tracks (assoc track :start-p start-p))
|
||||||
(gpt/add start-p (vv (+ size row-gap)))])
|
(gpt/add start-p (vv (+ size row-gap)))])
|
||||||
[[] start-p])
|
[[] start-p])
|
||||||
(first))
|
(first))]
|
||||||
]
|
|
||||||
|
|
||||||
{:origin start-p
|
{:origin start-p
|
||||||
:layout-bounds layout-bounds
|
:layout-bounds layout-bounds
|
||||||
|
@ -270,4 +411,3 @@
|
||||||
(gpt/to-vec origin row-start-p)))]
|
(gpt/to-vec origin row-start-p)))]
|
||||||
|
|
||||||
(assoc grid-cell :start-p start-p)))))
|
(assoc grid-cell :start-p start-p)))))
|
||||||
|
|
||||||
|
|
|
@ -55,11 +55,13 @@
|
||||||
|
|
||||||
(defn width-points
|
(defn width-points
|
||||||
[[p0 p1 _ _]]
|
[[p0 p1 _ _]]
|
||||||
(max 0.01 (gpt/length (gpt/to-vec p0 p1))))
|
(when (and (some? p0) (some? p1))
|
||||||
|
(max 0.01 (gpt/length (gpt/to-vec p0 p1)))))
|
||||||
|
|
||||||
(defn height-points
|
(defn height-points
|
||||||
[[p0 _ _ p3]]
|
[[p0 _ _ p3]]
|
||||||
(max 0.01 (gpt/length (gpt/to-vec p0 p3))))
|
(when (and (some? p0) (some? p3))
|
||||||
|
(max 0.01 (gpt/length (gpt/to-vec p0 p3)))))
|
||||||
|
|
||||||
(defn pad-points
|
(defn pad-points
|
||||||
[[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left]
|
[[p0 p1 p2 p3 :as points] pad-top pad-right pad-bottom pad-left]
|
||||||
|
|
|
@ -262,7 +262,7 @@
|
||||||
(hooks/setup-shortcuts node-editing? drawing-path? text-editing?)
|
(hooks/setup-shortcuts node-editing? drawing-path? text-editing?)
|
||||||
(hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox)
|
(hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox)
|
||||||
|
|
||||||
[:div.viewport
|
[:div.viewport {:style #js {"--zoom" zoom}}
|
||||||
[:div.viewport-overlays
|
[:div.viewport-overlays
|
||||||
;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap
|
;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap
|
||||||
;; inside a foreign object "dummy" so this awkward behaviour is take into account
|
;; inside a foreign object "dummy" so this awkward behaviour is take into account
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
;; Copyright (c) KALEIDOS INC
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
(ns app.main.ui.workspace.viewport.grid-layout-editor
|
(ns app.main.ui.workspace.viewport.grid-layout-editor
|
||||||
|
(:require-macros [app.main.style :refer [css]])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
@ -20,6 +21,8 @@
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.workspace.viewport.viewport-ref :as uwvv]
|
[app.main.ui.workspace.viewport.viewport-ref :as uwvv]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
[app.util.keyboard :as kbd]
|
||||||
|
[app.util.object :as obj]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
@ -41,36 +44,38 @@
|
||||||
value (unchecked-get props "value")
|
value (unchecked-get props "value")
|
||||||
zoom (unchecked-get props "zoom")
|
zoom (unchecked-get props "zoom")
|
||||||
|
|
||||||
|
marker-width (/ 24 zoom)
|
||||||
|
marker-h1 (/ 22 zoom)
|
||||||
|
marker-h2 (/ 8 zoom)
|
||||||
|
|
||||||
|
marker-half-width (/ marker-width 2)
|
||||||
|
marker-half-height (/ (+ marker-h1 marker-h2) 2)
|
||||||
|
|
||||||
marker-points
|
marker-points
|
||||||
(reduce
|
(reduce
|
||||||
apply-to-point
|
apply-to-point
|
||||||
[(gpt/subtract center
|
[(gpt/subtract center
|
||||||
(gpt/point (/ 13 zoom) (/ 16 zoom)))]
|
(gpt/point marker-half-width marker-half-height))]
|
||||||
[#(gpt/add % (gpt/point (/ 26 zoom) 0))
|
[#(gpt/add % (gpt/point marker-width 0))
|
||||||
#(gpt/add % (gpt/point 0 (/ 24 zoom)))
|
#(gpt/add % (gpt/point 0 marker-h1))
|
||||||
#(gpt/add % (gpt/point (- (/ 13 zoom)) (/ 8 zoom)))
|
#(gpt/add % (gpt/point (- marker-half-width) marker-h2))
|
||||||
#(gpt/subtract % (gpt/point (/ 13 zoom) (/ 8 zoom)))])
|
#(gpt/subtract % (gpt/point marker-half-width marker-h2))])
|
||||||
|
|
||||||
text-x (:x center)
|
text-x (:x center)
|
||||||
text-y (:y center)]
|
text-y (:y center)]
|
||||||
|
|
||||||
[:g.grid-track-marker
|
[:g {:class (css :grid-track-marker)}
|
||||||
[:polygon {:points (->> marker-points
|
[:polygon {:class (css :marker-shape)
|
||||||
|
:points (->> marker-points
|
||||||
(map #(dm/fmt "%,%" (:x %) (:y %)))
|
(map #(dm/fmt "%,%" (:x %) (:y %)))
|
||||||
(str/join " "))
|
(str/join " "))}]
|
||||||
|
[:text {:class (css :marker-text)
|
||||||
:style {:fill "var(--color-distance)"
|
:x text-x
|
||||||
:fill-opacity 0.3}}]
|
|
||||||
[:text {:x text-x
|
|
||||||
:y text-y
|
:y text-y
|
||||||
:width (/ 26.26 zoom)
|
:width (/ 26.26 zoom)
|
||||||
:height (/ 32 zoom)
|
:height (/ 32 zoom)
|
||||||
:font-size (/ 16 zoom)
|
|
||||||
:font-family "worksans"
|
|
||||||
:font-weight 600
|
|
||||||
:text-anchor "middle"
|
:text-anchor "middle"
|
||||||
:dominant-baseline "middle"
|
:dominant-baseline "middle"}
|
||||||
:style {:fill "var(--color-distance)"}}
|
|
||||||
(dm/str value)]]))
|
(dm/str value)]]))
|
||||||
|
|
||||||
(mf/defc grid-editor-frame
|
(mf/defc grid-editor-frame
|
||||||
|
@ -95,11 +100,11 @@
|
||||||
#(gpt/add % (vv (+ height (/ 40 zoom))))
|
#(gpt/add % (vv (+ height (/ 40 zoom))))
|
||||||
#(gpt/add % (hv (/ 40 zoom)))])]
|
#(gpt/add % (hv (/ 40 zoom)))])]
|
||||||
|
|
||||||
[:polygon {:points (->> frame-points
|
[:polygon
|
||||||
|
{:class (css :grid-frame)
|
||||||
|
:points (->> frame-points
|
||||||
(map #(dm/fmt "%,%" (:x %) (:y %)))
|
(map #(dm/fmt "%,%" (:x %) (:y %)))
|
||||||
(str/join " "))
|
(str/join " "))}]))
|
||||||
:style {:stroke "var(--color-distance)"
|
|
||||||
:stroke-width (/ 1 zoom)}}]))
|
|
||||||
|
|
||||||
(mf/defc plus-btn
|
(mf/defc plus-btn
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
|
@ -127,22 +132,21 @@
|
||||||
(mf/deps on-click)
|
(mf/deps on-click)
|
||||||
#(when on-click (on-click)))]
|
#(when on-click (on-click)))]
|
||||||
|
|
||||||
[:g.plus-button {:cursor "pointer"
|
[:g {:class (css :grid-plus-button)
|
||||||
:on-click handle-click}
|
:on-click handle-click}
|
||||||
[:rect {:x rect-x
|
|
||||||
|
[:rect {:class (css :grid-plus-shape)
|
||||||
|
:x rect-x
|
||||||
:y rect-y
|
:y rect-y
|
||||||
:width (/ 40 zoom)
|
:width (/ 40 zoom)
|
||||||
:height (/ 40 zoom)
|
:height (/ 40 zoom)}]
|
||||||
:style {:fill "var(--color-distance)"
|
|
||||||
:stroke "var(--color-distance)"
|
|
||||||
:stroke-width (/ 1 zoom)}}]
|
|
||||||
|
|
||||||
[:use {:x icon-x
|
[:use {:class (css :grid-plus-icon)
|
||||||
|
:x icon-x
|
||||||
:y icon-y
|
:y icon-y
|
||||||
:width (/ 16 zoom)
|
:width (/ 16 zoom)
|
||||||
:height (/ 16 zoom)
|
:height (/ 16 zoom)
|
||||||
:href (dm/str "#icon-plus")
|
:href (dm/str "#icon-plus")}]]))
|
||||||
:fill "white"}]]))
|
|
||||||
|
|
||||||
(defn use-drag
|
(defn use-drag
|
||||||
[{:keys [on-drag-start on-drag-end on-drag-delta on-drag-position]}]
|
[{:keys [on-drag-start on-drag-end on-drag-delta on-drag-position]}]
|
||||||
|
@ -259,7 +263,6 @@
|
||||||
:height height
|
:height height
|
||||||
:width width
|
:width width
|
||||||
:style {:fill "transparent" :stroke-width 0 :cursor cursor}
|
:style {:fill "transparent" :stroke-width 0 :cursor cursor}
|
||||||
|
|
||||||
:on-pointer-down handle-pointer-down
|
:on-pointer-down handle-pointer-down
|
||||||
:on-lost-pointer-capture handle-lost-pointer-capture
|
:on-lost-pointer-capture handle-lost-pointer-capture
|
||||||
:on-pointer-move handle-pointer-move}]))
|
:on-pointer-move handle-pointer-move}]))
|
||||||
|
@ -301,21 +304,17 @@
|
||||||
|
|
||||||
[:g.cell-editor
|
[:g.cell-editor
|
||||||
[:rect
|
[:rect
|
||||||
{:x (:x start-p)
|
{:class (dom/classnames (css :grid-cell-outline) true
|
||||||
|
(css :hover) hover?
|
||||||
|
(css :selected) selected?)
|
||||||
|
:x (:x start-p)
|
||||||
:y (:y start-p)
|
:y (:y start-p)
|
||||||
:width cell-width
|
:width cell-width
|
||||||
:height cell-height
|
:height cell-height
|
||||||
|
|
||||||
:on-pointer-enter #(st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) true))
|
:on-pointer-enter #(st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) true))
|
||||||
:on-pointer-leave #(st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) false))
|
:on-pointer-leave #(st/emit! (dwge/hover-grid-cell (:id shape) (:id cell) false))
|
||||||
:on-click #(st/emit! (dwge/select-grid-cell (:id shape) (:id cell)))
|
:on-click #(st/emit! (dwge/select-grid-cell (:id shape) (:id cell)))}]
|
||||||
|
|
||||||
:style {:fill "transparent"
|
|
||||||
:stroke "var(--color-distance)"
|
|
||||||
:stroke-dasharray (when-not (or hover? selected?)
|
|
||||||
(str/join " " (map #(/ % zoom) [0 8]) ))
|
|
||||||
:stroke-linecap "round"
|
|
||||||
:stroke-width (/ 2 zoom)}}]
|
|
||||||
|
|
||||||
(when selected?
|
(when selected?
|
||||||
(let [handlers
|
(let [handlers
|
||||||
|
@ -451,7 +450,44 @@
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
(mf/deps (:id shape))
|
(mf/deps (:id shape))
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! (st/emit! (dwsl/add-layout-track [(:id shape)] :row ctl/default-track-value)))))]
|
(st/emit! (st/emit! (dwsl/add-layout-track [(:id shape)] :row ctl/default-track-value)))))
|
||||||
|
|
||||||
|
handle-blur-track-input
|
||||||
|
(mf/use-callback
|
||||||
|
(mf/deps (:id shape))
|
||||||
|
(fn [track-type index event]
|
||||||
|
(let [target (-> event dom/get-target)
|
||||||
|
value (-> target dom/get-input-value str/upper)
|
||||||
|
value-int (d/parse-integer value)
|
||||||
|
|
||||||
|
[type value]
|
||||||
|
(cond
|
||||||
|
(str/ends-with? value "%")
|
||||||
|
[:percent value-int]
|
||||||
|
|
||||||
|
(str/ends-with? value "FR")
|
||||||
|
[:flex value-int]
|
||||||
|
|
||||||
|
(some? value-int)
|
||||||
|
[:fixed value-int]
|
||||||
|
|
||||||
|
(or (= value "AUTO") (= "" value))
|
||||||
|
[:auto nil])]
|
||||||
|
(if (some? type)
|
||||||
|
(do (obj/set! target "value" (format-size {:type type :value value}))
|
||||||
|
(dom/set-attribute! target "data-default-value" (format-size {:type type :value value}))
|
||||||
|
(st/emit! (dwsl/change-layout-track [(:id shape)] track-type index {:type type :value value})))
|
||||||
|
(obj/set! target "value" (dom/get-attribute target "data-default-value"))))))
|
||||||
|
|
||||||
|
handle-keydown-track-input
|
||||||
|
(mf/use-callback
|
||||||
|
(fn [event]
|
||||||
|
(let [enter? (kbd/enter? event)
|
||||||
|
esc? (kbd/esc? event)]
|
||||||
|
(when enter?
|
||||||
|
(dom/blur! (dom/get-target event)))
|
||||||
|
(when esc?
|
||||||
|
(dom/blur! (dom/get-target event))))))]
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
(fn []
|
(fn []
|
||||||
|
@ -482,23 +518,19 @@
|
||||||
(gpt/subtract (hv (/ layout-gap-col 2)))))
|
(gpt/subtract (hv (/ layout-gap-col 2)))))
|
||||||
|
|
||||||
text-p (-> start-p
|
text-p (-> start-p
|
||||||
(gpt/subtract (vv (/ 20 zoom)))
|
(gpt/subtract (vv (/ 36 zoom))))]
|
||||||
(gpt/add (hv (/ (:size column-data) 2))))]
|
|
||||||
[:* {:key (dm/str "column-" idx)}
|
[:* {:key (dm/str "column-" idx)}
|
||||||
[:& track-marker {:center marker-p
|
[:& track-marker {:center marker-p
|
||||||
:value (dm/str (inc idx))
|
:value (dm/str (inc idx))
|
||||||
:zoom zoom}]
|
:zoom zoom}]
|
||||||
|
[:foreignObject {:x (:x text-p) :y (:y text-p) :width (max 0 (- (:size column-data) 4)) :height (/ 32 zoom)}
|
||||||
[:text {:x (:x text-p)
|
[:input
|
||||||
:y (:y text-p)
|
{:class (css :grid-editor-label)
|
||||||
:font-size (/ 14 zoom)
|
:type "text"
|
||||||
:font-weight 600
|
:default-value (format-size column-data)
|
||||||
:font-family "worksans"
|
:data-default-value (format-size column-data)
|
||||||
:dominant-baseline "central"
|
:on-key-down handle-keydown-track-input
|
||||||
:text-anchor "middle"
|
:on-blur #(handle-blur-track-input :column idx %)}]]
|
||||||
:style {:fill "var(--color-distance)"}}
|
|
||||||
(format-size column-data)]
|
|
||||||
|
|
||||||
(when (not= idx 0)
|
(when (not= idx 0)
|
||||||
[:& resize-handler {:shape shape
|
[:& resize-handler {:shape shape
|
||||||
:layout-data layout-data
|
:layout-data layout-data
|
||||||
|
@ -514,24 +546,25 @@
|
||||||
(gpt/subtract (vv (/ layout-gap-row 2)))))
|
(gpt/subtract (vv (/ layout-gap-row 2)))))
|
||||||
|
|
||||||
text-p (-> start-p
|
text-p (-> start-p
|
||||||
(gpt/subtract (hv (/ 20 zoom)))
|
(gpt/subtract (hv (/ (:size row-data) 2)))
|
||||||
(gpt/add (vv (/ (:size row-data) 2))))]
|
(gpt/subtract (hv (/ 16 zoom)))
|
||||||
|
(gpt/add (vv (/ (:size row-data) 2)))
|
||||||
|
(gpt/subtract (vv (/ 18 zoom))))]
|
||||||
[:* {:key (dm/str "row-" idx)}
|
[:* {:key (dm/str "row-" idx)}
|
||||||
[:g {:transform (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p))}
|
[:g {:transform (dm/fmt "rotate(-90 % %)" (:x marker-p) (:y marker-p))}
|
||||||
[:& track-marker {:center marker-p
|
[:& track-marker {:center marker-p
|
||||||
:value (dm/str (inc idx))
|
:value (dm/str (inc idx))
|
||||||
:zoom zoom}]]
|
:zoom zoom}]]
|
||||||
|
|
||||||
[:g {:transform (dm/fmt "rotate(-90 % %)" (:x text-p) (:y text-p))}
|
[:g {:transform (dm/fmt "rotate(-90 % %)" (+ (:x text-p) (/ (:size row-data) 2)) (+ (:y text-p) (/ 36 zoom 2)))}
|
||||||
[:text {:x (:x text-p)
|
[:foreignObject {:x (:x text-p) :y (:y text-p) :width (:size row-data) :height (/ 36 zoom)}
|
||||||
:y (:y text-p)
|
[:input
|
||||||
:font-size (/ 14 zoom)
|
{:class (css :grid-editor-label)
|
||||||
:font-weight 600
|
:type "text"
|
||||||
:font-family "worksans"
|
:default-value (format-size row-data)
|
||||||
:dominant-baseline "central"
|
:data-default-value (format-size row-data)
|
||||||
:text-anchor "middle"
|
:on-key-down handle-keydown-track-input
|
||||||
:style {:fill "var(--color-distance)"}}
|
:on-blur #(handle-blur-track-input :row idx %)}]]]
|
||||||
(format-size row-data)]]
|
|
||||||
|
|
||||||
(when (not= idx 0)
|
(when (not= idx 0)
|
||||||
[:& resize-handler {:shape shape
|
[:& resize-handler {:shape shape
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{"grid-track-marker":"viewport_grid_layout_editor_grid-track-marker_HABEp","marker-shape":"viewport_grid_layout_editor_marker-shape_FZTUQ","marker-text":"viewport_grid_layout_editor_marker-text_5xM8J","grid-editor-label":"viewport_grid_layout_editor_grid-editor-label_2NbYe","grid-frame":"viewport_grid_layout_editor_grid-frame_CzMnU","grid-plus-button":"viewport_grid_layout_editor_grid-plus-button_brOge","grid-plus-shape":"viewport_grid_layout_editor_grid-plus-shape_jtOU9","grid-plus-icon":"viewport_grid_layout_editor_grid-plus-icon_Zolso","grid-cell-outline":"viewport_grid_layout_editor_grid-cell-outline_1-cRq","hover":"viewport_grid_layout_editor_hover_Rn-tv","selected":"viewport_grid_layout_editor_selected_nhyhL"}
|
|
@ -0,0 +1,64 @@
|
||||||
|
.grid-track-marker {
|
||||||
|
.marker-shape {
|
||||||
|
fill: var(--color-distance);
|
||||||
|
fill-opacity: 0.3;
|
||||||
|
}
|
||||||
|
.marker-text {
|
||||||
|
fill: var(--color-distance);
|
||||||
|
font-size: calc(12px / var(--zoom));
|
||||||
|
font-family: worksans;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-editor-label {
|
||||||
|
background: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-family: worksans;
|
||||||
|
color: var(--color-distance);
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: calc(12px / var(--zoom));
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
border-bottom: calc(1px / var(--zoom)) solid var(--color-distance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-frame {
|
||||||
|
fill: transparent;
|
||||||
|
stroke: var(--color-distance);
|
||||||
|
stroke-width: calc(1 / var(--zoom));
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-plus-button {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.grid-plus-shape {
|
||||||
|
fill: var(--color-distance);
|
||||||
|
stroke: var(--color-distance);
|
||||||
|
stroke-width: calc(1 / var(--zoom));
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-plus-icon {
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-cell-outline {
|
||||||
|
fill: transparent;
|
||||||
|
stroke: var(--color-distance);
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-width: calc(2 / var(--zoom));
|
||||||
|
stroke-dasharray: 0 calc(8 / var(--zoom));
|
||||||
|
|
||||||
|
&.hover,
|
||||||
|
&.selected {
|
||||||
|
stroke-dasharray: initial;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue