Reorder tracks from grid editor

This commit is contained in:
alonso.torres 2023-12-27 17:22:57 +01:00 committed by Andrey Antukh
parent 7508627dc5
commit da358d635b
5 changed files with 266 additions and 94 deletions

View file

@ -0,0 +1,18 @@
;; 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.geom.line)
(defn line-value
[[{px :x py :y} {vx :x vy :y}] {:keys [x y]}]
(let [a vy
b (- vx)
c (+ (* (- vy) px) (* vx py))]
(+ (* a x) (* b y) c)))
(defn is-inside-lines?
[line-1 line-2 pos]
(< (* (line-value line-1 pos) (line-value line-2 pos)) 0))

View file

@ -9,6 +9,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.files.helpers :as cfh] [app.common.files.helpers :as cfh]
[app.common.geom.line :as gl]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes.common :as gco] [app.common.geom.shapes.common :as gco]
[app.common.geom.shapes.grid-layout.layout-data :as ld] [app.common.geom.shapes.grid-layout.layout-data :as ld]
@ -182,18 +183,6 @@
(-> (ctm/add-modifiers fill-modifiers) (-> (ctm/add-modifiers fill-modifiers)
(ctm/move position-delta))))) (ctm/move position-delta)))))
(defn line-value
[[{px :x py :y} {vx :x vy :y}] {:keys [x y]}]
(let [a vy
b (- vx)
c (+ (* (- vy) px) (* vx py))]
(+ (* a x) (* b y) c)))
(defn is-inside-lines?
[line-1 line-2 pos]
(< (* (line-value line-1 pos) (line-value line-2 pos)) 0))
(defn get-position-grid-coord (defn get-position-grid-coord
[{:keys [layout-bounds row-tracks column-tracks]} position] [{:keys [layout-bounds row-tracks column-tracks]} position]
@ -206,7 +195,7 @@
(fn is-inside-track? [{:keys [start-p size] :as track}] (fn is-inside-track? [{:keys [start-p size] :as track}]
(let [unit-v (vfn 1) (let [unit-v (vfn 1)
end-p (gpt/add start-p (ofn size))] end-p (gpt/add start-p (ofn size))]
(is-inside-lines? [start-p unit-v] [end-p unit-v] position))))) (gl/is-inside-lines? [start-p unit-v] [end-p unit-v] position)))))
make-min-distance-track make-min-distance-track
(fn [type] (fn [type]
@ -214,8 +203,8 @@
(fn [[selected selected-dist] [cur-idx {:keys [start-p size] :as track}]] (fn [[selected selected-dist] [cur-idx {:keys [start-p size] :as track}]]
(let [unit-v (vfn 1) (let [unit-v (vfn 1)
end-p (gpt/add start-p (ofn size)) end-p (gpt/add start-p (ofn size))
dist-1 (mth/abs (line-value [start-p unit-v] position)) dist-1 (mth/abs (gl/line-value [start-p unit-v] position))
dist-2 (mth/abs (line-value [end-p unit-v] position))] dist-2 (mth/abs (gl/line-value [end-p unit-v] position))]
(if (or (< dist-1 selected-dist) (< dist-2 selected-dist)) (if (or (< dist-1 selected-dist) (< dist-2 selected-dist))
[[cur-idx track] (min dist-1 dist-2)] [[cur-idx track] (min dist-1 dist-2)]

View file

@ -327,6 +327,20 @@
[pad-top pad-right pad-top pad-right] [pad-top pad-right pad-top pad-right]
[pad-top pad-right pad-bottom pad-left]))) [pad-top pad-right pad-bottom pad-left])))
(defn h-padding
[{:keys [layout-padding-type layout-padding]}]
(let [{pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding]
(if (= :simple layout-padding-type)
(+ pad-right pad-right)
(+ pad-right pad-left))))
(defn v-padding
[{:keys [layout-padding-type layout-padding]}]
(let [{pad-top :p1 pad-right :p2 pad-bottom :p3 pad-left :p4} layout-padding]
(if (= :simple layout-padding-type)
(+ pad-top pad-top)
(+ pad-top pad-bottom))))
(defn child-min-width (defn child-min-width
[child] [child]
(if (and (fill-width? child) (if (and (fill-width? child)

View file

@ -10,6 +10,7 @@
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.files.helpers :as cfh] [app.common.files.helpers :as cfh]
[app.common.geom.line :as gl]
[app.common.geom.matrix :as gmt] [app.common.geom.matrix :as gmt]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
@ -163,7 +164,7 @@
(mf/set-ref-val! dragging-ref true) (mf/set-ref-val! dragging-ref true)
(mf/set-ref-val! start-pos-ref raw-pt) (mf/set-ref-val! start-pos-ref raw-pt)
(mf/set-ref-val! current-pos-ref raw-pt) (mf/set-ref-val! current-pos-ref raw-pt)
(when on-drag-start (on-drag-start position))))) (when on-drag-start (on-drag-start event position)))))
handle-lost-pointer-capture handle-lost-pointer-capture
(mf/use-callback (mf/use-callback
@ -174,7 +175,7 @@
(dom/release-pointer event) (dom/release-pointer event)
(mf/set-ref-val! dragging-ref false) (mf/set-ref-val! dragging-ref false)
(mf/set-ref-val! start-pos-ref nil) (mf/set-ref-val! start-pos-ref nil)
(when on-drag-end (on-drag-end position))))) (when on-drag-end (on-drag-end event position)))))
handle-pointer-move handle-pointer-move
(mf/use-callback (mf/use-callback
@ -185,8 +186,8 @@
pos (dom/get-client-position event) pos (dom/get-client-position event)
pt (uwvv/point->viewport pos)] pt (uwvv/point->viewport pos)]
(mf/set-ref-val! current-pos-ref pos) (mf/set-ref-val! current-pos-ref pos)
(when on-drag-delta (on-drag-delta (gpt/to-vec start pos))) (when on-drag-delta (on-drag-delta event (gpt/to-vec start pos)))
(when on-drag-position (on-drag-position pt))))))] (when on-drag-position (on-drag-position event pt))))))]
{:handle-pointer-down handle-pointer-down {:handle-pointer-down handle-pointer-down
:handle-lost-pointer-capture handle-lost-pointer-capture :handle-lost-pointer-capture handle-lost-pointer-capture
@ -212,7 +213,7 @@
handle-drag-position handle-drag-position
(mf/use-callback (mf/use-callback
(mf/deps shape row column row-span column-span) (mf/deps shape row column row-span column-span)
(fn [position] (fn [_ position]
(let [[drag-row drag-column] (gsg/get-position-grid-coord layout-data position) (let [[drag-row drag-column] (gsg/get-position-grid-coord layout-data position)
[new-row new-column new-row-span new-column-span] [new-row new-column new-row-span new-column-span]
@ -410,7 +411,7 @@
handle-drag-position handle-drag-position
(mf/use-callback (mf/use-callback
(mf/deps shape track-before track-after) (mf/deps shape track-before track-after)
(fn [position] (fn [_ position]
(let [[tracks-prop axis] (let [[tracks-prop axis]
(if (= :column type) [:layout-grid-columns :x] [:layout-grid-rows :y]) (if (= :column type) [:layout-grid-columns :x] [:layout-grid-rows :y])
@ -451,11 +452,14 @@
(let [shape (unchecked-get props "shape") (let [shape (unchecked-get props "shape")
index (unchecked-get props "index") index (unchecked-get props "index")
last? (unchecked-get props "last?") last? (unchecked-get props "last?")
drop? (unchecked-get props "drop?")
track-before (unchecked-get props "track-before") track-before (unchecked-get props "track-before")
track-after (unchecked-get props "track-after") track-after (unchecked-get props "track-after")
snap-pixel? (unchecked-get props "snap-pixel?") snap-pixel? (unchecked-get props "snap-pixel?")
{:keys [column-total-size column-total-gap row-total-size row-total-gap]} (unchecked-get props "layout-data") {:keys [column-total-size column-total-gap row-total-size row-total-gap] :as layout-data}
(unchecked-get props "layout-data")
start-p (unchecked-get props "start-p") start-p (unchecked-get props "start-p")
type (unchecked-get props "type") type (unchecked-get props "type")
zoom (unchecked-get props "zoom") zoom (unchecked-get props "zoom")
@ -477,7 +481,7 @@
[(+ column-total-size column-total-gap) [(+ column-total-size column-total-gap)
(max 0 (- layout-gap-row (/ 10 zoom)) (/ 8 zoom))]) (max 0 (- layout-gap-row (/ 10 zoom)) (/ 8 zoom))])
start-p start-p-resize
(cond-> start-p (cond-> start-p
(and (= type :column) (= index 0)) (and (= type :column) (= index 0))
(gpt/subtract (hv (/ width 2))) (gpt/subtract (hv (/ width 2)))
@ -491,22 +495,52 @@
(and (= type :row) (not= index 0) (not last?)) (and (= type :row) (not= index 0) (not last?))
(-> (gpt/subtract (vv (/ layout-gap-row 2))) (-> (gpt/subtract (vv (/ layout-gap-row 2)))
(gpt/subtract (vv (/ height 2)))))] (gpt/subtract (vv (/ height 2)))))
[:rect.resize-track-handler start-p-drop
{:x (:x start-p) (cond-> start-p
:y (:y start-p) (and (= type :column) (= index 0))
:height height (gpt/subtract (hv (/ width 2)))
:width width
:on-pointer-down handle-pointer-down (and (= type :row) (= index 0))
:on-lost-pointer-capture handle-lost-pointer-capture (gpt/subtract (vv (/ height 2)))
:on-pointer-move handle-pointer-move
:transform (dm/str (gmt/transform-in start-p (:transform shape))) (and (= type :column) last?)
:class (if (= type :column) (gpt/add (hv (/ width 2)))
(cur/get-dynamic "resize-ew" (:rotation shape))
(cur/get-dynamic "resize-ns" (:rotation shape))) (and (= type :row) last?)
:style {:fill "transparent" (gpt/add (vv (/ height 2)))
:stroke-width 0}}]))
(and (= type :column) (not= index 0) (not last?))
(-> (gpt/subtract (hv (/ layout-gap-col 2)))
(gpt/subtract (hv (/ 5 zoom))))
(and (= type :row) (not= index 0) (not last?))
(-> (gpt/subtract (vv (/ layout-gap-row 2)))
(gpt/subtract (vv (/ 5 zoom)))))]
[:*
(when drop?
[:rect.drop
{:x (:x start-p-drop)
:y (:y start-p-drop)
:width (if (= type :column)(/ 10 zoom) width)
:height (if (= type :row) (/ 10 zoom) height)
:fill "var(--grid-editor-area-background)"}])
[:rect.resize-track-handler
{:x (:x start-p-resize)
:y (:y start-p-resize)
:height height
:width width
:on-pointer-down handle-pointer-down
:on-lost-pointer-capture handle-lost-pointer-capture
:on-pointer-move handle-pointer-move
:transform (dm/str (gmt/transform-in start-p (:transform shape)))
:class (if (= type :column)
(cur/get-dynamic "resize-ew" (:rotation shape))
(cur/get-dynamic "resize-ns" (:rotation shape)))
:style {:fill "transparent"
:stroke-width 0}}]]))
(def marker-width 24) (def marker-width 24)
(def marker-h1 20) (def marker-h1 20)
@ -620,7 +654,7 @@
(dm/str value)]])) (dm/str value)]]))
(mf/defc track (mf/defc track
{::mf/wrap [#(mf/memo' % (mf/check-props ["shape" "zoom" "index" "type" "track-data" "layout-data" "hovering?"]))] {::mf/wrap [mf/memo]
::mf/wrap-props false} ::mf/wrap-props false}
[props] [props]
(let [shape (unchecked-get props "shape") (let [shape (unchecked-get props "shape")
@ -631,6 +665,11 @@
track-data (unchecked-get props "track-data") track-data (unchecked-get props "track-data")
layout-data (unchecked-get props "layout-data") layout-data (unchecked-get props "layout-data")
hovering? (unchecked-get props "hovering?") hovering? (unchecked-get props "hovering?")
drop? (unchecked-get props "drop?")
on-start-reorder-track (unchecked-get props "on-start-reorder-track")
on-move-reorder-track (unchecked-get props "on-move-reorder-track")
on-end-reorder-track (unchecked-get props "on-end-reorder-track")
track-input-ref (mf/use-ref) track-input-ref (mf/use-ref)
[layout-gap-row layout-gap-col] (ctl/gaps shape) [layout-gap-row layout-gap-col] (ctl/gaps shape)
@ -719,17 +758,41 @@
[(:x text-p) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)] [(:x text-p) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)]
[(- (:x text-p) (max 0 (:size track-data))) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)]) [(- (:x text-p) (max 0 (:size track-data))) (- (:y text-p) (/ 36 zoom)) (max 0 (:size track-data)) (/ 36 zoom)])
handle-drag-start
(mf/use-callback
(mf/deps on-start-reorder-track type index)
(fn []
(on-start-reorder-track type index)))
handle-drag-end
(mf/use-callback
(mf/deps on-end-reorder-track type index)
(fn [event position]
(on-end-reorder-track type index position (not (kbd/mod? event)))))
handle-drag-position
(mf/use-callback
(mf/deps on-move-reorder-track type index)
(fn [_ position]
(on-move-reorder-track type index position)))
trackwidth (* text-width zoom) trackwidth (* text-width zoom)
medium? (and (>= trackwidth small-size-limit) (< trackwidth medium-size-limit)) medium? (and (>= trackwidth small-size-limit) (< trackwidth medium-size-limit))
small? (< trackwidth small-size-limit) small? (< trackwidth small-size-limit)
track-before (get-in layout-data [track-list-prop (dec index)])] track-before (get-in layout-data [track-list-prop (dec index)])
{:keys [handle-pointer-down handle-lost-pointer-capture handle-pointer-move]}
(use-drag {:on-drag-start handle-drag-start
:on-drag-end handle-drag-end
:on-drag-position handle-drag-position})]
(mf/use-effect (mf/use-effect
(mf/deps track-data) (mf/deps track-data)
(fn [] (fn []
(dom/set-value! (mf/ref-val track-input-ref) (format-size track-data)))) (dom/set-value! (mf/ref-val track-input-ref) (format-size track-data))))
[:g.track [:g.track
[:g {:on-pointer-enter handle-pointer-enter [:g {:on-pointer-enter handle-pointer-enter
:on-pointer-leave handle-pointer-leave :on-pointer-leave handle-pointer-leave
@ -737,17 +800,20 @@
(dm/str (gmt/transform-in text-p (:transform shape))) (dm/str (gmt/transform-in text-p (:transform shape)))
(dm/str (gmt/transform-in text-p (gmt/rotate (:transform shape) -90))))} (dm/str (gmt/transform-in text-p (gmt/rotate (:transform shape) -90))))}
(when (and hovering? (not small?)) [:rect {:class (stl/css :grid-editor-header-hover)
[:rect {:x (+ text-x (/ 18 zoom)) :x (+ text-x (/ 18 zoom))
:y text-y :y text-y
:width (- text-width (/ 36 zoom)) :width (- text-width (/ 36 zoom))
:height (- text-height (/ 5 zoom)) :height (- text-height (/ 5 zoom))
:rx (/ 3 zoom) :rx (/ 3 zoom)
:fill "var(--grid-editor-marker-color)" :style {:cursor "pointer"}
:opacity 0.2}]) :opacity (if (and hovering? (not small?)) 0.2 0)}]
(when (not small?) (when (not small?)
[:foreignObject {:x text-x :y text-y :width text-width :height text-height} [:foreignObject {:x text-x :y text-y :width text-width :height text-height}
[:div {:class (stl/css :grid-editor-wrapper)} [:div {:class (stl/css :grid-editor-wrapper)
:on-pointer-down handle-pointer-down
:on-lost-pointer-capture handle-lost-pointer-capture
:on-pointer-move handle-pointer-move}
[:input [:input
{:ref track-input-ref {:ref track-input-ref
:style {} :style {}
@ -778,6 +844,7 @@
:layout-data layout-data :layout-data layout-data
:shape shape :shape shape
:snap-pixel? snap-pixel? :snap-pixel? snap-pixel?
:drop? drop?
:start-p start-p :start-p start-p
:track-after track-data :track-after track-data
:track-before track-before :track-before track-before
@ -855,8 +922,8 @@
(mf/deps shape children) (mf/deps shape children)
#(gsg/calc-layout-data shape bounds children all-bounds objects)) #(gsg/calc-layout-data shape bounds children all-bounds objects))
width (max (gpo/width-points bounds) (+ column-total-size column-total-gap)) width (max (gpo/width-points bounds) (+ column-total-size column-total-gap (ctl/h-padding shape)))
height (max (gpo/height-points bounds) (+ row-total-size row-total-gap)) height (max (gpo/height-points bounds) (+ row-total-size row-total-gap (ctl/v-padding shape)))
handle-pointer-down handle-pointer-down
(mf/use-callback (mf/use-callback
@ -875,7 +942,68 @@
(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)))))
target-tracks* (mf/use-ref nil)
drop-track-type* (mf/use-state nil)
drop-track-target* (mf/use-state nil)
handle-start-reorder-track
(mf/use-callback
(mf/deps layout-data)
(fn [type from-idx]
;; Initialize target-tracks
(let [line-vec (if (= type :column) (vv 1) (hv 1))
first-point origin
last-point (if (= type :column) (nth bounds 1) (nth bounds 3))
mid-points
(if (= type :column)
(->> (:column-tracks layout-data)
(mapv #(gpt/add (:start-p %) (hv (/ (:size %) 2)))))
(->> (:row-tracks layout-data)
(mapv #(gpt/add (:start-p %) (vv (/ (:size %) 2))))))
tracks
(->> (d/with-prev (d/concat-vec [first-point] mid-points [last-point]))
(d/enumerate)
(keep
(fn [[index [current prev]]]
(when (some? prev)
[[prev current line-vec] (dec index)]))))]
(mf/set-ref-val! target-tracks* tracks)
(reset! drop-track-type* type))))
handle-move-reorder-track
(mf/use-callback
(fn [type from-idx position]
(let [index
(->> (mf/ref-val target-tracks*)
(d/seek (fn [[[p1 p2 v] _]]
(gl/is-inside-lines? [p1 v] [p2 v] position)))
(second))]
(when (some? index)
(reset! drop-track-target* index)))))
handle-end-reorder-track
(mf/use-callback
(mf/deps base-shape @drop-track-target*)
(fn [type from-index position move-content?]
(when-let [to-index @drop-track-target*]
(let [ids [(:id base-shape)]]
(cond
(< from-index to-index)
(st/emit! (dwsl/reorder-layout-track ids type from-index (dec to-index) move-content?))
(> from-index to-index)
(st/emit! (dwsl/reorder-layout-track ids type from-index (dec to-index) move-content?)))))
(mf/set-ref-val! target-tracks* nil)
(reset! drop-track-type* nil)
(reset! drop-track-target* nil)))]
(mf/use-effect (mf/use-effect
(fn [] (fn []
@ -914,15 +1042,21 @@
:on-click handle-add-row}]]) :on-click handle-add-row}]])
(for [[idx column-data] (d/enumerate column-tracks)] (for [[idx column-data] (d/enumerate column-tracks)]
[:& track {:key (dm/str "column-track-" idx) (let [drop? (and (= :column @drop-track-type*)
:shape shape (= idx @drop-track-target*))]
:zoom zoom [:& track {:key (dm/str "column-track-" idx)
:type :column :shape shape
:index idx :zoom zoom
:layout-data layout-data :type :column
:snap-pixel? snap-pixel? :index idx
:track-data column-data :layout-data layout-data
:hovering? (contains? hover-columns idx)}]) :snap-pixel? snap-pixel?
:drop? drop?
:track-data column-data
:hovering? (contains? hover-columns idx)
:on-start-reorder-track handle-start-reorder-track
:on-move-reorder-track handle-move-reorder-track
:on-end-reorder-track handle-end-reorder-track}]))
;; Last track resize handler ;; Last track resize handler
(when-not (empty? column-tracks) (when-not (empty? column-tracks)
@ -940,27 +1074,36 @@
:type :column :type :column
:value (dm/str (inc (count column-tracks))) :value (dm/str (inc (count column-tracks)))
:zoom zoom}] :zoom zoom}]
[:& resize-track-handler (let [drop? (and (= :column @drop-track-type*)
{:index (count column-tracks) (= (count column-tracks) @drop-track-target*))]
:last? true [:& resize-track-handler
:shape shape {:index (count column-tracks)
:layout-data layout-data :last? true
:snap-pixel? snap-pixel? :drop? drop?
:start-p end-p :shape shape
:type :column :layout-data layout-data
:track-before (last column-tracks) :snap-pixel? snap-pixel?
:zoom zoom}]])) :start-p end-p
:type :column
:track-before (last column-tracks)
:zoom zoom}])]))
(for [[idx row-data] (d/enumerate row-tracks)] (for [[idx row-data] (d/enumerate row-tracks)]
[:& track {:index idx (let [drop? (and (= :row @drop-track-type*)
:key (dm/str "row-track-" idx) (= idx @drop-track-target*))]
:layout-data layout-data [:& track {:index idx
:shape shape :key (dm/str "row-track-" idx)
:snap-pixel? snap-pixel? :layout-data layout-data
:track-data row-data :shape shape
:type :row :snap-pixel? snap-pixel?
:zoom zoom :drop? drop?
:hovering? (contains? hover-rows idx)}]) :track-data row-data
:type :row
:zoom zoom
:hovering? (contains? hover-rows idx)
:on-start-reorder-track handle-start-reorder-track
:on-move-reorder-track handle-move-reorder-track
:on-end-reorder-track handle-end-reorder-track}]))
(when-not (empty? row-tracks) (when-not (empty? row-tracks)
(let [last-track (last row-tracks) (let [last-track (last row-tracks)
start-p (:start-p last-track) start-p (:start-p last-track)
@ -977,13 +1120,16 @@
:type :row :type :row
:value (dm/str (inc (count row-tracks))) :value (dm/str (inc (count row-tracks)))
:zoom zoom}]] :zoom zoom}]]
[:& resize-track-handler (let [drop? (and (= :row @drop-track-type*)
{:index (count row-tracks) (= (count row-tracks) @drop-track-target*))]
:last? true [:& resize-track-handler
:shape shape {:index (count row-tracks)
:layout-data layout-data :last? true
:start-p end-p :drop? drop?
:type :row :shape shape
:track-before (last row-tracks) :layout-data layout-data
:snap-pixel? snap-pixel? :start-p end-p
:zoom zoom}]]))])]))) :type :row
:track-before (last row-tracks)
:snap-pixel? snap-pixel?
:zoom zoom}])]))])])))

View file

@ -18,30 +18,35 @@
} }
.grid-editor-wrapper { .grid-editor-wrapper {
cursor: grab;
width: 100%; width: 100%;
height: 80%; height: 80%;
display: flex; display: flex;
flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.grid-editor-header-hover {
fill: var(--grid-editor-marker-color);
}
.grid-editor-label { .grid-editor-label {
flex: 1;
background: none; background: none;
border-bottom: calc($s-1 / var(--zoom)) solid transparent;
border: 0; border: 0;
color: var(--grid-editor-marker-text); color: var(--grid-editor-marker-text);
font-family: worksans; font-family: worksans;
font-size: calc($fs-12 / var(--zoom)); font-size: calc($fs-12 / var(--zoom));
font-weight: 400; font-weight: 400;
margin: 0; margin: 0;
max-width: calc($s-80 / var(--zoom)); max-width: calc($s-60 / var(--zoom));
padding: 0; padding: 0;
padding: $s-4; padding: calc($s-4 / var(--zoom));
text-align: center; text-align: center;
&:focus { &:focus {
outline: none; outline: none;
border-bottom: calc($s-1 / var(--zoom)) solid var(--grid-editor-marker-text);
} }
} }